如何:扩展封送处理库
本主题介绍如何扩展封送库,以在数据类型之间提供更多转换。 用户可以为封送库当前不支持的任何数据转换扩展库。
可以通过这两种方式之一扩展封送库:使用或不使用 marshal_context 类。 查看 C++ 中的封送处理概述主题,确定新转换是否需要上下文。
在这两种情况下,首先为新的封送转换创建一个文件。 执行此操作可保持标准封送库文件的完整性。 如果要将项目移植到另一台计算机或另一个程序员,必须将新的封送文件与项目的其余部分一起复制。 这样可以保证接收项目的用户能够接收新转换,而无需修改任何库文件。
使用不需要上下文的转换扩展封送库
创建文件以存储新的封送函数,例如 MyMarshal.h。
包括一个或多个封送库文件:
marshal.h,用于基类型。
marshal_windows.h,用于 windows 数据类型。
marshal_cppstd.h,用于 C++ 标准库数据类型。
marshal_atl.h,用于 ATL 数据类型。
在这些步骤末尾使用代码编写转换函数。 在此代码中,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,用于基类型。
marshal_windows.h,用于 windows 数据类型。
marshal_cppstd.h,用于 C++ 标准库数据类型。
marshal_atl.h,用于 ATL 数据类型。
在这些步骤末尾使用代码编写转换函数。 在此代码中,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.
}
};
}
}
示例:扩展封送库
以下示例使用不需要上下文的转换扩展封送库。 在此示例中,代码将员工信息从本机数据类型转换为托管数据类型。
// 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
示例:转换员工信息
以下示例将员工信息从托管数据类型转换为本机数据类型。 此转换需要封送上下文。
// 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
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈