Udostępnij za pośrednictwem


Porady: rozszerzanie biblioteki kierowania

W tym temacie wyjaśniono, jak rozszerzyć bibliotekę marshalingu w celu zapewnienia większej liczby konwersji między typami danych. Użytkownicy mogą rozszerzyć bibliotekę marshalingu na wszelkie konwersje danych, które nie są obecnie obsługiwane przez bibliotekę.

Bibliotekę marshalingową można rozszerzyć na jeden z dwóch sposobów — z klasą marshal_context lub bez nich. Zapoznaj się z tematem Omówienie marshalingu w języku C++ , aby ustalić, czy nowa konwersja wymaga kontekstu.

W obu przypadkach należy najpierw utworzyć plik na potrzeby nowych konwersji marshalingowych. W tym celu należy zachować integralność standardowych plików bibliotek marshalingowych. Jeśli chcesz przełączyć projekt na inny komputer lub innego programistę, musisz skopiować nowy plik marshalingowy wraz z resztą projektu. W ten sposób użytkownik odbierający projekt będzie mieć gwarancję otrzymania nowych konwersji i nie będzie musiał modyfikować żadnych plików biblioteki.

Aby rozszerzyć bibliotekę marshalingową za pomocą konwersji, która nie wymaga kontekstu

  1. Utwórz plik do przechowywania nowych funkcji marshalingu, na przykład MyMarshal.h.

  2. Uwzględnij co najmniej jeden plik biblioteki marshalingowej:

    • marshal.h dla typów bazowych.

    • marshal_windows.h dla typów danych systemu Windows.

    • marshal_cppstd.h dla typów danych standardowej biblioteki C++.

    • marshal_atl.h dla typów danych ATL.

  3. Użyj kodu na końcu tych kroków, aby napisać funkcję konwersji. W tym kodzie parametr TO jest typem, na który ma zostać przekonwertowana, funkcja FROM jest typem, z który ma zostać przekonwertowany, i from jest parametrem, z który ma zostać przekonwertowany.

  4. Zastąp komentarz dotyczący logiki konwersji kodem, aby przekonwertować from parametr na obiekt typu TO i zwrócić przekonwertowany obiekt.

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

Aby rozszerzyć bibliotekę marshalingową za pomocą konwersji wymagającej kontekstu

  1. Utwórz plik do przechowywania nowych funkcji marshalingu, na przykład MyMarshal.h

  2. Uwzględnij co najmniej jeden plik biblioteki marshalingowej:

    • marshal.h dla typów bazowych.

    • marshal_windows.h dla typów danych systemu Windows.

    • marshal_cppstd.h dla typów danych standardowej biblioteki C++.

    • marshal_atl.h dla typów danych ATL.

  3. Użyj kodu na końcu tych kroków, aby napisać funkcję konwersji. W tym kodzie parametr TO jest typem, na który ma zostać przekonwertowana wartość FROM, toObject jest typem, z którego ma zostać przekonwertowany wskaźnik, w którym ma być przechowywany wynik, i fromObject jest parametrem, z którego ma zostać przekonwertowany.

  4. Zastąp komentarz dotyczący inicjowania kodem, aby zainicjować toPtr element do odpowiedniej pustej wartości. Jeśli na przykład jest to wskaźnik, ustaw go na NULLwartość .

  5. Zastąp komentarz dotyczący logiki konwersji kodem, aby przekonwertować from parametr na obiekt typu TO . Ten przekonwertowany obiekt będzie przechowywany w pliku toPtr.

  6. Zastąp komentarz o ustawieniu toObject kodem, aby ustawić toObject na przekonwertowany obiekt.

  7. Zastąp komentarz dotyczący czyszczenia zasobów natywnych kodem, aby zwolnić dowolną pamięć przydzieloną przez toPtrprogram . Jeśli toPtr przydzielona pamięć przy użyciu polecenia , newużyj polecenia delete , aby zwolnić pamięć.

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

Przykład: Rozszerzanie biblioteki marshalingowej

Poniższy przykład rozszerza bibliotekę marshalingową za pomocą konwersji, która nie wymaga kontekstu. W tym przykładzie kod konwertuje informacje o pracownikach z natywnego typu danych na zarządzany typ danych.

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

W poprzednim przykładzie marshal_as funkcja zwraca uchwyt do przekonwertowanych danych. Zostało to zrobione, aby zapobiec tworzeniu dodatkowej kopii danych. Zwracanie zmiennej bezpośrednio wiązałoby się z nią niepotrzebnym kosztem wydajności.

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

Przykład: konwertowanie informacji o pracownikach

Poniższy przykład konwertuje informacje o pracownikach z zarządzanego typu danych na natywny typ danych. Ta konwersja wymaga kontekstu marshalingu.

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

Zobacz też

Omówienie marshalingu w języku C++