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
Vytvořte soubor pro uložení nových funkcí zařazování, například MyMarshal.h.
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.
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.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
Vytvoření souboru pro uložení nových funkcí zařazování, například MyMarshal.h
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.
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, afromObject
jedná se o parametr, který se má převést.Nahraďte komentář o inicializaci kódem, který inicializuje
toPtr
odpovídající prázdnou hodnotu. Pokud je to například ukazatel, nastavte ho naNULL
.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 vtoPtr
.Nahraďte komentář k nastavení kódem
toObject
, který se nastavítoObject
na převedený objekt.Nahraďte komentář o čištění nativních prostředků kódem, který uvolní veškerou paměť přidělenou
toPtr
. PokudtoPtr
je přidělena paměť pomocí ,new
použijtedelete
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