Comment : étendre la bibliothèque de marshaling

Cette rubrique explique comment étendre la bibliothèque de marshaling pour fournir davantage de conversions entre les types de données. Les utilisateurs peuvent étendre la bibliothèque de marshaling pour toutes les conversions de données non prises en charge actuellement par la bibliothèque.

Vous pouvez étendre la bibliothèque de marshaling de deux façons : avec ou sans classe marshal_context. Passez en revue la vue d’ensemble du marshaling dans la rubrique C++ pour déterminer si une nouvelle conversion nécessite un contexte.

Dans les deux cas, vous créez d’abord un fichier pour les nouvelles conversions de marshaling. Pour préserver l’intégrité des fichiers de bibliothèque de marshaling standard. Si vous souhaitez porter un projet vers un autre ordinateur ou vers un autre programmeur, vous devez copier le nouveau fichier de marshaling avec le reste du projet. De cette façon, l’utilisateur recevant le projet sera garanti pour recevoir les nouvelles conversions et n’aura pas à modifier les fichiers de bibliothèque.

Pour étendre la bibliothèque de marshaling avec une conversion qui ne nécessite pas de contexte

  1. Créez un fichier pour stocker les nouvelles fonctions de marshaling, par exemple MyMarshal.h.

  2. Incluez un ou plusieurs fichiers de bibliothèque marshal :

    • marshal.h pour les types de base.

    • marshal_windows.h pour les types de données Windows.

    • marshal_cppstd.h pour les types de données de la bibliothèque standard C++.

    • marshal_atl.h pour les types de données ATL.

  3. Utilisez le code à la fin de ces étapes pour écrire la fonction de conversion. Dans ce code, TO est le type à convertir en, FROM est le type à convertir, et from est le paramètre à convertir.

  4. Remplacez le commentaire relatif à la logique de conversion par du code pour convertir le from paramètre en objet de type TO et renvoyer l’objet converti.

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

Pour étendre la bibliothèque de marshaling avec une conversion nécessitant un contexte

  1. Créer un fichier pour stocker les nouvelles fonctions de marshaling, par exemple, MyMarshal.h

  2. Incluez un ou plusieurs fichiers de bibliothèque marshal :

    • marshal.h pour les types de base.

    • marshal_windows.h pour les types de données Windows.

    • marshal_cppstd.h pour les types de données de la bibliothèque standard C++.

    • marshal_atl.h pour les types de données ATL.

  3. Utilisez le code à la fin de ces étapes pour écrire la fonction de conversion. Dans ce code, TO est le type à convertir en, FROM est le type à convertir, toObject est un pointeur dans lequel stocker le résultat, et fromObject est le paramètre à convertir.

  4. Remplacez le commentaire sur l’initialisation par du code pour initialiser la toPtr valeur vide appropriée. Par exemple, s’il s’agit d’un pointeur, définissez-le sur NULL.

  5. Remplacez le commentaire relatif à la logique de conversion par du code pour convertir le from paramètre en objet de type TO . Cet objet converti est stocké dans toPtr.

  6. Remplacez le commentaire sur le paramètre toObject par le code à définir toObject sur votre objet converti.

  7. Remplacez le commentaire sur propre la mise en place de ressources natives par du code pour libérer toute mémoire allouée par toPtr. Si toPtr la mémoire allouée est utilisée new, utilisez-la delete pour libérer la mémoire.

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

Exemple : Étendre la bibliothèque de marshaling

L’exemple suivant étend la bibliothèque de marshaling avec une conversion qui ne nécessite pas de contexte. Dans cet exemple, le code convertit les informations des employés d’un type de données natif en type de données managé.

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

Dans l’exemple précédent, la marshal_as fonction retourne un handle aux données converties. Cette opération a été effectuée pour empêcher la création d’une copie supplémentaire des données. Le renvoi de la variable directement aurait un coût de performances inutile associé à celui-ci.

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

Exemple : Convertir des informations sur les employés

L’exemple suivant convertit les informations des employés d’un type de données managé en type de données natif. Cette conversion nécessite un contexte de marshaling.

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

Voir aussi

Vue d’ensemble du marshaling en C++