如何:擴充封送處理程式庫
本主題說明如何擴充封送處理程式庫,以提供資料類型之間的更多轉換。 使用者可以針對程式庫目前不支援的任何資料轉換,擴充封送處理程式庫。
您可以使用下列兩種方式之一來擴充封送處理程式庫:使用或不使用 marshal_coNtext 類別 。 檢閱 C++ 中封送處理的概觀主題,以判斷新的轉換是否需要內容。
在這兩種情況下,您都會先建立檔案以進行新的封送處理轉換。 您可以這樣做,以保留標準封送處理程式庫檔案的完整性。 如果您想要將專案移植到另一部電腦或另一個程式設計人員,您必須將新的封送處理檔案與專案的其餘部分一起複製。 如此一來,接收專案的使用者將保證會收到新的轉換,而且不需要修改任何程式庫檔案。
若要使用不需要內容的轉換來擴充封送處理程式庫
建立檔案來儲存新的封送處理函式,例如 MyMarshal.h。
包含一或多個封送處理程式庫檔案:
基底類型的 marshal.h。
適用于 windows 資料類型的 marshal_windows.h。
適用于 C++ 標準程式庫資料類型的 marshal_cppstd.h。
適用于 ATL 資料類型的 marshal_atl.h。
使用這些步驟結尾的程式碼來撰寫轉換函式。 在此程式碼中,TO 是要轉換成的類型,FROM 是要轉換的類型,而
from
是要轉換的參數。將轉換邏輯的相關批註取代為程式碼,以將 參數轉換成
from
TO 類型的物件,並傳回轉換的物件。
namespace msclr {
namespace interop {
template<>
inline TO marshal_as<TO, FROM> (const FROM& from) {
// Insert conversion logic here, and return a TO parameter.
}
}
}
若要使用需要內容的轉換來擴充封送處理程式庫
建立檔案來儲存新的封送處理函式,例如 MyMarshal.h
包含一或多個封送處理程式庫檔案:
基底類型的 marshal.h。
適用于 windows 資料類型的 marshal_windows.h。
適用于 C++ 標準程式庫資料類型的 marshal_cppstd.h。
適用于 ATL 資料類型的 marshal_atl.h。
使用這些步驟結尾的程式碼來撰寫轉換函式。 在此程式碼中,TO 是要轉換成的類型,FROM 是要轉換的來源型別,
toObject
是用來儲存結果的指標,而fromObject
是要轉換的參數。將初始化的批註取代為程式碼,以初始化
toPtr
為適當的空白值。 例如,如果是指標,請將它設定為NULL
。將轉換邏輯的相關批註取代為程式碼,以將參數轉換成
from
TO 類型的物件 。 這個轉換的物件將會儲存在 中toPtr
。將有關設定
toObject
的批註取代為要設定toObject
為已轉換物件的程式碼。以程式碼取代清除原生資源的批註,以釋放 所
toPtr
配置的任何記憶體。 如果使用toPtr
配置記憶體new
,請使用delete
釋放記憶體。
namespace msclr {
namespace interop {
template<>
ref class context_node<TO, FROM> : public context_node_base
{
private:
TO toPtr;
public:
context_node(TO& toObject, FROM fromObject)
{
// (Step 4) Initialize toPtr to the appropriate empty value.
// (Step 5) Insert conversion logic here.
// (Step 6) Set toObject to the converted parameter.
}
~context_node()
{
this->!context_node();
}
protected:
!context_node()
{
// (Step 7) Clean up native resources.
}
};
}
}
範例:擴充封送處理程式庫
下列範例會使用不需要內容的轉換來擴充封送處理程式庫。 在此範例中,程式碼會將員工資訊從原生資料類型轉換成 Managed 資料類型。
// MyMarshalNoContext.cpp
// compile with: /clr
#include <msclr/marshal.h>
value struct ManagedEmp {
System::String^ name;
System::String^ address;
int zipCode;
};
struct NativeEmp {
char* name;
char* address;
int zipCode;
};
namespace msclr {
namespace interop {
template<>
inline ManagedEmp^ marshal_as<ManagedEmp^, NativeEmp> (const NativeEmp& from) {
ManagedEmp^ toValue = gcnew ManagedEmp;
toValue->name = marshal_as<System::String^>(from.name);
toValue->address = marshal_as<System::String^>(from.address);
toValue->zipCode = from.zipCode;
return toValue;
}
}
}
using namespace System;
using namespace msclr::interop;
int main() {
NativeEmp employee;
employee.name = "Jeff Smith";
employee.address = "123 Main Street";
employee.zipCode = 98111;
ManagedEmp^ result = marshal_as<ManagedEmp^>(employee);
Console::WriteLine("Managed name: {0}", result->name);
Console::WriteLine("Managed address: {0}", result->address);
Console::WriteLine("Managed zip code: {0}", result->zipCode);
return 0;
}
在上一個範例中,函 marshal_as
式會傳回已轉換資料的控制碼。 這樣做是為了防止建立額外的資料複本。 直接傳回變數會有與其相關聯的不必要的效能成本。
Managed name: Jeff Smith
Managed address: 123 Main Street
Managed zip code: 98111
範例:轉換員工資訊
下列範例會將員工資訊從 Managed 資料類型轉換成原生資料類型。 此轉換需要封送處理內容。
// MyMarshalContext.cpp
// compile with: /clr
#include <stdlib.h>
#include <string.h>
#include <msclr/marshal.h>
value struct ManagedEmp {
System::String^ name;
System::String^ address;
int zipCode;
};
struct NativeEmp {
const char* name;
const char* address;
int zipCode;
};
namespace msclr {
namespace interop {
template<>
ref class context_node<NativeEmp*, ManagedEmp^> : public context_node_base
{
private:
NativeEmp* toPtr;
marshal_context context;
public:
context_node(NativeEmp*& toObject, ManagedEmp^ fromObject)
{
// Conversion logic starts here
toPtr = NULL;
const char* nativeName;
const char* nativeAddress;
// Convert the name from String^ to const char*.
System::String^ tempValue = fromObject->name;
nativeName = context.marshal_as<const char*>(tempValue);
// Convert the address from String^ to const char*.
tempValue = fromObject->address;
nativeAddress = context.marshal_as<const char*>(tempValue);
toPtr = new NativeEmp();
toPtr->name = nativeName;
toPtr->address = nativeAddress;
toPtr->zipCode = fromObject->zipCode;
toObject = toPtr;
}
~context_node()
{
this->!context_node();
}
protected:
!context_node()
{
// When the context is deleted, it will free the memory
// allocated for toPtr->name and toPtr->address, so toPtr
// is the only memory that needs to be freed.
if (toPtr != NULL) {
delete toPtr;
toPtr = NULL;
}
}
};
}
}
using namespace System;
using namespace msclr::interop;
int main() {
ManagedEmp^ employee = gcnew ManagedEmp();
employee->name = gcnew String("Jeff Smith");
employee->address = gcnew String("123 Main Street");
employee->zipCode = 98111;
marshal_context context;
NativeEmp* result = context.marshal_as<NativeEmp*>(employee);
if (result != NULL) {
printf_s("Native name: %s\nNative address: %s\nNative zip code: %d\n",
result->name, result->address, result->zipCode);
}
return 0;
}
Native name: Jeff Smith
Native address: 123 Main Street
Native zip code: 98111