Partilhar via


Como: estende 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 estender a biblioteca de marshaling para qualquer conversões de dados não suportadas atualmente da biblioteca.

Você pode estender a biblioteca de marshaling de duas maneiras - com ou sem um Classe marshal_context.Revisão do Visão geral do empacotamento em 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 novos.Faça isso para preservar a integridade do padrão de empacotamento de arquivos de biblioteca.Se você deseja um projeto para outro computador ou para outro programador de porta, você deverá copiar o arquivo empacotamento novo junto com o restante do projeto.Dessa forma, o usuário receber o projeto será garantido para receber as novas conversões e não será necessário modificar os arquivos de biblioteca.

Para estender a biblioteca de Marshaling com uma conversão não requer um contexto

  1. Crie um arquivo para armazenar as novas funções de empacotamento, por exemplo, MyMarshal.h.

  2. Inclua um ou mais dos arquivos de biblioteca de empacotamento:

    • Marshal.h de 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.

  3. 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.

  4. Substituir o comentário sobre a lógica de conversão com código para converter o from parâmetro em um objeto 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 com uma conversão requer um contexto

  1. Criar um arquivo para armazenar as novas funções de empacotamento, por exemplo, MyMarshal.h

  2. Inclua um ou mais dos arquivos de biblioteca de empacotamento:

    • Marshal.h de 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.

  3. 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.

  4. Substituir o comentário sobre Inicializando com código para inicializar o toPtr para o valor apropriado de vazio.Por exemplo, se for um ponteiro, defini-la NULL.

  5. Substituir o comentário sobre a lógica de conversão com código para converter o from parâmetro em um objeto de para tipo.Este objeto convertido será armazenado em toPtr.

  6. Substituir o comentário sobre a configuração de toObject com código para definir toObject para o objeto convertido.

  7. Substituir o comentário sobre limpeza de recursos nativos com o código para liberar qualquer memória alocada por toPtr.Se toPtr memória alocada usando new, use delete para liberar a 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 com uma conversão não requer um contexto.Neste exemplo, o código converte as informações do funcionário de um tipo de dados nativo para um tipo de dados gerenciado.

// 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 para os dados convertidos.Isso foi feito para evitar a criação de uma cópia adicional dos dados.Retornando a variável diretamente deve 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 gerenciado para um tipo de dados nativo.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;
}
  

Consulte também

Conceitos

Visão geral do empacotamento em C++