Condividi tramite


Procedura: estendere la libreria del marshalling

In questo argomento viene illustrato come estendere la libreria di marshalling per fornire più conversioni tra tipi di dati. Gli utenti possono estendere la libreria di marshalling per eventuali conversioni di dati attualmente non supportate dalla libreria.

È possibile estendere la libreria di marshalling in uno dei due modi, con o senza una classe marshal_context. Esaminare l'argomento Panoramica del marshalling in C++ per determinare se una nuova conversione richiede un contesto.

In entrambi i casi, si crea prima di tutto un file per le nuove conversioni di marshalling. Questa operazione consente di mantenere l'integrità dei file di libreria di marshalling standard. Se si desidera convertire un progetto in un altro computer o in un altro programmatore, è necessario copiare il nuovo file di marshalling insieme al resto del progetto. In questo modo, l'utente che riceve il progetto sarà garantito di ricevere le nuove conversioni e non dovrà modificare alcun file di libreria.

Per estendere la libreria di marshalling con una conversione che non richiede un contesto

  1. Creare un file per archiviare le nuove funzioni di marshalling, ad esempio MyMarshal.h.

  2. Includere uno o più file di libreria di marshalling:

    • marshal.h per i tipi di base.

    • marshal_windows.h per i tipi di dati windows.

    • marshal_cppstd.h per i tipi di dati della libreria standard C++.

    • marshal_atl.h per i tipi di dati ATL.

  3. Usare il codice alla fine di questi passaggi per scrivere la funzione di conversione. In questo codice, TO è il tipo in cui eseguire la conversione, FROM è il tipo da cui eseguire la conversione ed from è il parametro da convertire.

  4. Sostituire il commento sulla logica di conversione con il codice per convertire il from parametro in un oggetto di tipo TO e restituire l'oggetto convertito.

namespace msclr {
   namespace interop {
      template<>
      inline TO marshal_as<TO, FROM> (const FROM& from) {
         // Insert conversion logic here, and return a TO parameter.
      }
   }
}

Per estendere la libreria di marshalling con una conversione che richiede un contesto

  1. Creare un file per archiviare le nuove funzioni di marshalling, ad esempio MyMarshal.h

  2. Includere uno o più file di libreria di marshalling:

    • marshal.h per i tipi di base.

    • marshal_windows.h per i tipi di dati windows.

    • marshal_cppstd.h per i tipi di dati della libreria standard C++.

    • marshal_atl.h per i tipi di dati ATL.

  3. Usare il codice alla fine di questi passaggi per scrivere la funzione di conversione. In questo codice, TO è il tipo in cui eseguire la conversione, FROM è il tipo da cui eseguire la conversione, toObject è un puntatore in cui archiviare il risultato ed fromObject è il parametro da convertire.

  4. Sostituire il commento relativo all'inizializzazione con il codice per inizializzare l'oggetto toPtr sul valore vuoto appropriato. Ad esempio, se si tratta di un puntatore, impostarlo su NULL.

  5. Sostituire il commento sulla logica di conversione con il codice per convertire il from parametro in un oggetto di tipo TO . Questo oggetto convertito verrà archiviato in toPtr.

  6. Sostituire il commento relativo all'impostazione toObject con il codice da impostare sull'oggetto toObject convertito.

  7. Sostituire il commento relativo alla pulizia delle risorse native con il codice per liberare qualsiasi memoria allocata da toPtr. Se toPtr la memoria allocata tramite , newusare delete per liberare la memoria.

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.
         }
      };
   }
}

Esempio: Estendere la libreria di marshalling

L'esempio seguente estende la libreria di marshalling con una conversione che non richiede un contesto. In questo esempio il codice converte le informazioni sui dipendenti da un tipo di dati nativo a un tipo di dati gestito.

// 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;
}

Nell'esempio precedente la marshal_as funzione restituisce un handle ai dati convertiti. Questa operazione è stata eseguita per impedire la creazione di una copia aggiuntiva dei dati. La restituzione diretta della variabile comporta un costo di prestazioni non necessario associato.

Managed name: Jeff Smith
Managed address: 123 Main Street
Managed zip code: 98111

Esempio: Convertire le informazioni sui dipendenti

L'esempio seguente converte le informazioni sui dipendenti da un tipo di dati gestito a un tipo di dati nativo. Questa conversione richiede un contesto di marshalling.

// 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

Vedi anche

Panoramica del marshalling in C++