Como: Estender a biblioteca de Marshaling
Este tópico explica como estender a biblioteca de marshaling para fornecer mais conversões entre tipos de dados. Os usuários podem ampliar a biblioteca de marshaling para quaisquer conversões de dados não suportadas atualmente pela biblioteca.
Você pode estender a biblioteca de marshaling de uma das duas maneiras - com ou sem um marshal_context Class. Revisão do Overview of Marshaling in C++ tópico para determinar se uma nova conversão requer um contexto.
Em ambos os casos, você primeiro criar um arquivo para conversões de empacotamento de novos. Depois de fazê-lo para preservar a integridade dos arquivos de biblioteca de marshaling padrão. Se você quiser um projeto para outro computador ou para outro programador de porta, você deverá copiar o arquivo de empacotamento novo juntamente com o restante do projeto. Dessa forma, o usuário que recebe o projeto será ser garantido para receber as conversões de novas e não precisará modificar quaisquer arquivos de biblioteca.
Para estender a biblioteca de Marshaling de mensagens com uma conversão que não requer um contexto
Crie um arquivo para armazenar as novas funções de empacotamento, por exemplo, MyMarshal.h.
Include one or more of the marshal library files:
Marshal.h para tipos base.
marshal_windows.h para tipos de dados do windows.
marshal_cppstd.h para tipos de dados STL.
marshal_atl.h para tipos de dados do ATL.
Use o código no final destas etapas para escrever a função de conversão. Nesse código, é o tipo para converter, FROM é o tipo para converter, e from é o parâmetro a ser convertido.
Substitua o comentário sobre a lógica de conversão de código para converter o from parâmetro em um objeto do para digitar e retornar o objeto convertido.
namespace msclr {
namespace interop {
template<>
inline TO marshal_as<TO, FROM> (const FROM& from) {
// Insert conversion logic here, and return a TO parameter.
}
}
}
Para estender a biblioteca de Marshaling uma conversão que requer um contexto.
Criar um arquivo para armazenar as novas funções de empacotamento, por exemplo, MyMarshal.h
Include one or more of the marshal library files:
Marshal.h para tipos base.
marshal_windows.h para tipos de dados do windows.
marshal_cppstd.h para tipos de dados STL.
marshal_atl.h para tipos de dados do ATL.
Use o código no final destas etapas para escrever a função de conversão. Nesse código, é o tipo para converter, FROM é o tipo para converter, toObject é um ponteiro para armazenar o resultado e fromObject é o parâmetro a ser convertido.
Substitua o comentário sobre como inicializar com o código para inicializar o toPtr para o valor apropriado vazio. Por exemplo, se for um ponteiro, defini-la NULL.
Substitua o comentário sobre a lógica de conversão de código para converter o from parâmetro em um objeto de para tipo. Este objeto convertido será armazenado em toPtr.
Substitua o comentário sobre a configuração toObject com código para definir toObject para o objeto convertido.
Substitua o comentário sobre a limpeza de recursos nativos com código para liberar qualquer memória alocada pelo toPtr. Se toPtr alocada a memória usando new, use delete para liberar memória.
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.
}
};
}
}
Exemplo
O exemplo a seguir amplia a biblioteca de marshaling uma conversão que não requer um contexto. Neste exemplo, o código converte as informações do funcionário de um tipo de dados nativos a um tipo de dados gerenciados.
// 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;
}
No exemplo anterior, o marshal_as função retorna um identificador de dados convertido. Isso foi feito para evitar a criação de uma cópia adicional dos dados. Retornando a variável diretamente seria ter um custo de desempenho desnecessária associado a ele.
O exemplo a seguir converte as informações do funcionário de um tipo de dados gerenciados para um tipo de dados nativos. Esta conversão requer um contexto de empacotamento.
// 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;
}