Sdílet prostřednictvím


Postupy: Rozšíření knihovny zařazování

Toto téma vysvětluje, jak rozšířit knihovnu zařazování tak, aby poskytovala více převodů mezi datovými typy. Uživatelé mohou rozšířit knihovnu zařazování pro jakékoli převody dat, které knihovna v současné době nepodporuje.

Knihovnu zařazování můžete rozšířit jedním ze dvou způsobů – se třídou marshal_context nebo bez nich. Projděte si přehled zařazování v tématu jazyka C++ a zjistěte, jestli nový převod vyžaduje kontext.

V obou případech nejprve vytvoříte soubor pro nové převody zařazování. Uděláte to proto, abyste zachovali integritu standardních souborů zařazování knihoven. Pokud chcete projekt přenést do jiného počítače nebo jiného programátora, musíte zkopírovat nový zařazovací soubor společně se zbytkem projektu. Tímto způsobem bude zaručeno, že uživatel, který projekt obdrží, obdrží nové převody a nebude muset upravovat žádné soubory knihovny.

Rozšíření knihovny zařazování převodem, který nevyžaduje kontext

  1. Vytvořte soubor pro uložení nových funkcí zařazování, například MyMarshal.h.

  2. Zahrnout jeden nebo více souborů zařazování knihovny:

    • marshal.h pro základní typy.

    • marshal_windows.h pro datové typy Windows.

    • marshal_cppstd.h pro datové typy standardní knihovny C++.

    • marshal_atl.h pro datové typy ATL.

  3. K zápisu funkce převodu použijte kód na konci těchto kroků. V tomto kódu je TO typ, na který se má převést, from je typ, ze které se má převést, a from je parametr, který se má převést.

  4. Nahraďte komentář o logice převodu kódem, který převede from parametr na objekt typu TO a vrátí převedený objekt.

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

Rozšíření knihovny zařazování převodem, který vyžaduje kontext

  1. Vytvoření souboru pro uložení nových funkcí zařazování, například MyMarshal.h

  2. Zahrnout jeden nebo více souborů zařazování knihovny:

    • marshal.h pro základní typy.

    • marshal_windows.h pro datové typy Windows.

    • marshal_cppstd.h pro datové typy standardní knihovny C++.

    • marshal_atl.h pro datové typy ATL.

  3. K zápisu funkce převodu použijte kód na konci těchto kroků. V tomto kódu je TO typ, na který se má převést, from je typ, ze kterého se má převést, je ukazatel, toObject do kterého chcete uložit výsledek, a fromObject jedná se o parametr, který se má převést.

  4. Nahraďte komentář o inicializaci kódem, který inicializuje toPtr odpovídající prázdnou hodnotu. Pokud je to například ukazatel, nastavte ho na NULL.

  5. Nahraďte komentář o logice převodu kódem, který převede from parametr na objekt typu TO . Tento převedený objekt bude uložen v toPtr.

  6. Nahraďte komentář k nastavení kódem toObject , který se nastaví toObject na převedený objekt.

  7. Nahraďte komentář o čištění nativních prostředků kódem, který uvolní veškerou paměť přidělenou toPtr. Pokud toPtr je přidělena paměť pomocí , newpoužijte delete k uvolnění paměti.

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

Příklad: Rozšíření zařazování knihovny

Následující příklad rozšiřuje zařazování knihovny s převodem, který nevyžaduje kontext. V tomto příkladu kód převede informace o zaměstnancích z nativního datového typu na spravovaný datový typ.

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

V předchozím příkladu marshal_as vrátí funkce popisovač převedených dat. To se provedlo, aby se zabránilo vytvoření další kopie dat. Vrácení proměnné přímo by mělo spojené zbytečné náklady na výkon.

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

Příklad: Převod informací o zaměstnanech

Následující příklad převede informace o zaměstnancích ze spravovaného datového typu na nativní datový typ. Tento převod vyžaduje zařazování kontextu.

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

Viz také

Přehled zařazování v jazyce C++