Gewusst wie: Erweitern der Marshallingbibliothek
In diesem Thema wird erläutert, wie Sie die Marshallingbibliothek erweitern, um mehr Konvertierungen zwischen Datentypen bereitzustellen. Benutzer können die Marshaling-Bibliothek auf alle Datenkonvertierungen erweitern, die derzeit von der Bibliothek nicht unterstützt werden.
Sie können die Marshaling-Bibliothek auf eine von zwei Arten erweitern – mit oder ohne eine marshal_context Klasse. Lesen Sie die Übersicht über Marshaling in C++ , um zu ermitteln, ob eine neue Konvertierung einen Kontext erfordert.
In beiden Fällen erstellen Sie zuerst eine Datei für neue Marshaling-Konvertierungen. Dies geschieht, um die Integrität der Standardmäßigen Marshaling-Bibliotheksdateien beizubehalten. Wenn Sie ein Projekt auf einen anderen Computer oder einen anderen Programmierer portieren möchten, müssen Sie die neue Marshallingdatei zusammen mit dem Rest des Projekts kopieren. Auf diese Weise erhält der Benutzer, der das Projekt erhält, garantiert die neuen Konvertierungen und muss keine Bibliotheksdateien ändern.
So erweitern Sie die Marshaling-Bibliothek mit einer Konvertierung, die keinen Kontext erfordert
Erstellen Sie eine Datei zum Speichern der neuen Marshaling-Funktionen, z. B. "MyMarshal.h".
Fügen Sie eine oder mehrere der Marshallbibliotheksdateien ein:
marshal.h für Basistypen.
marshal_windows.h für Windows-Datentypen.
marshal_cppstd.h für C++-Standardbibliothek-Datentypen.
marshal_atl.h für ATL-Datentypen.
Verwenden Sie den Code am Ende dieser Schritte, um die Konvertierungsfunktion zu schreiben. In diesem Code ist TO der Typ, in den konvertiert werden soll, FROM ist der Typ, aus dem konvertiert werden soll, und
from
ist der Parameter, der konvertiert werden soll.Ersetzen Sie den Kommentar zur Konvertierungslogik durch Code, um den
from
Parameter in ein Objekt des TO-Typs zu konvertieren und das konvertierte Objekt zurückzugeben.
namespace msclr {
namespace interop {
template<>
inline TO marshal_as<TO, FROM> (const FROM& from) {
// Insert conversion logic here, and return a TO parameter.
}
}
}
So erweitern Sie die Marshaling-Bibliothek mit einer Konvertierung, die einen Kontext erfordert
Erstellen einer Datei zum Speichern der neuen Marshaling-Funktionen, z. B. "MyMarshal.h"
Fügen Sie eine oder mehrere der Marshallbibliotheksdateien ein:
marshal.h für Basistypen.
marshal_windows.h für Windows-Datentypen.
marshal_cppstd.h für C++-Standardbibliothek-Datentypen.
marshal_atl.h für ATL-Datentypen.
Verwenden Sie den Code am Ende dieser Schritte, um die Konvertierungsfunktion zu schreiben. In diesem Code ist TO der Typ, in den konvertiert werden soll, FROM ist der Typ, aus dem konvertiert werden soll, ein Zeiger,
toObject
in dem das Ergebnis gespeichert werden soll, undfromObject
der Parameter, der konvertiert werden soll.Ersetzen Sie den Kommentar zum Initialisieren durch Code, um den
toPtr
entsprechenden leeren Wert zu initialisieren. Wenn es sich z. B. um einen Zeiger handelt, legen Sie ihn aufNULL
.Ersetzen Sie den Kommentar zur Konvertierungslogik durch Code, um den
from
Parameter in ein Objekt des TO-Typs zu konvertieren. Dieses konvertierte Objekt wird intoPtr
gespeichert.Ersetzen Sie den Kommentar zur Einstellung
toObject
durch Code, der auf ihr konvertiertes Objekt festgelegttoObject
werden soll.Ersetzen Sie den Kommentar zum Bereinigen systemeigener Ressourcen durch Code, um alle speicherzuweisungen freizugeben.
toPtr
VerwendentoPtr
Siedelete
bei verwendung dernew
Verwendung des zugewiesenen Arbeitsspeichers den Speicher.
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.
}
};
}
}
Beispiel: Erweitern der Marshallingbibliothek
Im folgenden Beispiel wird die Marshallingbibliothek durch eine Konvertierung erweitert, die keinen Kontext erfordert. In diesem Beispiel konvertiert der Code die Mitarbeiterinformationen aus einem systemeigenen Datentyp in einen verwalteten Datentyp.
// 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;
}
Im vorherigen Beispiel gibt die marshal_as
Funktion ein Handle für die konvertierten Daten zurück. Dies wurde durchgeführt, um das Erstellen einer zusätzlichen Kopie der Daten zu verhindern. Wenn Sie die Variable direkt zurückgeben, wäre dies mit einem unnötigen Leistungsaufwand verbunden.
Managed name: Jeff Smith
Managed address: 123 Main Street
Managed zip code: 98111
Beispiel: Konvertieren von Mitarbeiterinformationen
Im folgenden Beispiel werden die Mitarbeiterinformationen aus einem verwalteten Datentyp in einen systemeigenen Datentyp konvertiert. Für diese Konvertierung ist ein Marshallingkontext erforderlich.
// 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