Marshallingänderungen
Aktualisiert: November 2007
Die folgenden Abschnitte enthalten eine Gruppe ausgewählter Änderungen, die Sie in einer Interop-Assembly vornehmen können, um einige die Ausgabe des Importprozesses betreffende spezifische Probleme zu behandeln:
Konforme Arrays im C-Format
In/Out-Arrays im C-Format
Mehrdimensionale Arrays im C-Format
SAFEARRAY mit Grenzwert ungleich 0
Beibehalten der Signatur
Übergeben von Null anstelle eines Verweises auf einen Werttyp
Diese Abschnitte enthalten nicht alle Fälle, in denen eine Interop-Assembly bearbeitet wird. Sie können eine Interop-Assembly beispielsweise auch bearbeiten, um deren Verwendung zu vereinfachen. Die einzige Möglichkeit festzustellen, welche Anpassungen erforderlich sind, besteht darin, Code unter Verwendung der Interop-Assembly zu schreiben. Anweisungen zum Bearbeiten von Interop-Assemblys finden Sie unter Gewusst wie: Bearbeiten von Interop-Assemblys.
Wenn sich der Client und der Server in nicht kompatiblen Apartments befinden, hat dies Einfluss auf das Marshallen. In den folgenden Beispielen sind die meisten gemarshallten Parameter nicht automatisierungskompatibel, und es ist eine der folgenden Aktionen erforderlich:
Bestätigen Sie, dass sich sowohl der Client als auch der Server in kompatiblen Apartments befinden (sodass kein COM-Marshalling erforderlich ist).
Registrieren Sie den von der IDL (Interface Definition Language) generierten Proxy und Stub. Das Registrieren der Typbibliothek ist in diesen Fällen keine Lösung, da viele der für das Marshalling benötigten Informationen nicht aus der IDL an die Typbibliothek übertragen werden.
Konforme Arrays im C-Format
Die folgende IDL-Deklaration enthält ein Array im C-Format.
HRESULT ConformantArray([in] int cElems, [in, size_is(cElems)] int
aConf[]);
Da dieser Typ nicht automatisierungskompatibel ist, können Informationen zur Größe des Arrays (z. B. die Verknüpfung zwischen dem ersten und dem zweiten Parameter) nicht in der Typbibliothek ausgedrückt werden. Der Type Library Importer (Tlbimp.exe ) importiert den zweiten Parameter als Verweis auf die Ganzzahl und nicht als verwaltetes Array. Sie können den Parameter anpassen, indem Sie die MSIL bearbeiten.
Durchsuchen der MSIL nach
method public hidebysig newslot virtual
instance void ConformantArray([in] int32 cElems,
[in] int32& aConf) runtime managed internalcall
Ersetzen durch
method public hidebysig newslot virtual
instance void ConformantArray([in] int32 cElems,
[in] int32[] marshal([]) aConf) runtime managed internalcall
Zum Abrufen aus verwaltetem Code
int[] param1 = { 11, 22, 33 };
tstArrays.ConformantArray( 3, param1 );
In/Out-Arrays im C-Format
Die folgende IDL-Deklaration enthält ein In/Out-Array im C-Format.
HRESULT InOutArray([in, out] int* pcElems, [in, out, size_is(,*pcElems)]
int** ppInOut);
In diesem Fall kann die Größe des Arrays geändert werden, und die neue Größe kann zurückübergeben werden. Da dieser Typ nicht automatisierungskompatibel ist, können Informationen zur Größe des Arrays (z. B. die Verknüpfung zwischen dem ersten und dem zweiten Parameter) nicht in der Typbibliothek ausgedrückt werden. Tlbimp.exe importiert den zweiten Parameter als IntPtr. Zwar können Sie diese Methode immer noch aus verwaltetem Code abrufen, zum Ändern der Größe des Arrays müssen Sie jedoch die MSIL bearbeiten und Methoden aus der Marshal-Klasse verwenden, um die Zuweisung und Freigabe des Speichers manuell durchzuführen.
Durchsuchen der MSIL nach
.method public hidebysig newslot virtual
instance void InOutArray([in][out] int32& pcElems,
[in][out] native int ppInOut) runtime managed internalcall
Ersetzen durch
.method public hidebysig newslot virtual
instance void InOutArray([in][out] int32& pcElems,
[in][out] native int& ppInOut) runtime managed internalcall
Zum Abrufen aus verwaltetem Code
int[] inArray = { 11, 22, 33 };
int arraySize = inArray.Length;
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( typeof( int )) * inArray.Length );
Marshal.Copy( inArray, 0, buffer, inArray.Length );
tstArrays.InOutArray( ref arraySize, ref buffer );
if( arraySize > 0 )
{
int[] arrayRes = new int[ arraySize ];
Marshal.Copy( buffer, arrayRes, 0, arraySize );
Marshal.FreeCoTaskMem( buffer );
}
Mehrdimensionale Arrays im C-Format
Die folgende IDL-Deklaration enthält ein zweidimensionales Array im C-Format.
HRESULT TwoDimArray([in] int cDim, [in, size_is(cDim)] int aMatrix[][3]);
Da dieser Typ nicht automatisierungskompatibel ist, können Informationen zur Größe und Anzahl der Dimensionen des Arrays (z. B. die Verknüpfung zwischen dem ersten und dem zweiten Parameter) nicht in der Typbibliothek ausgedrückt werden. Tlbimp.exe importiert den zweiten Parameter als IntPtr-Typ und nicht als verwaltetes mehrdimensionales Array. Sie können den Parameter anpassen, indem Sie die MSIL bearbeiten.
Durchsuchen der MSIL nach
.method public hidebysig newslot virtual
instance void TwoDimArray([in] int32 cDim,
[in] native int aMatrix) runtime managed internalcall
Ersetzen durch
.method public hidebysig newslot virtual
instance void TwoDimArray([in] int32 cDim,
[in] int32[,] marshal([]) aMatrix) runtime managed internalcall
Zum Abrufen aus verwaltetem Code
int[,] param = {{ 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 }};
tstArrays.TwoDimArray( 3, param );
SAFEARRAY mit Grenzwert ungleich 0
Die folgende IDL-Deklaration enthält einen SAFEARRAY-Parameter.
HRESULT InSArray([in] SAFEARRAY(int) *ppsa);
Dieser SAFEARRAY hat einen Grenzwert, der ungleich 0 ist. In verwaltetem Code werden solche Arrays durch den Typ System.Array dargestellt. Standardmäßig konvertiert der Importer jedoch alle SAFEARRAY-Parameter in Verweise auf verwaltete Arrays. Sie haben zwei Möglichkeiten, das Standardverhalten zu ändern:
Importieren Sie alle Arrays als System.Array -Typen in eine Typbibliothek, indem Sie Tlbimp.exe mit dem Schalter /sysarray verwenden.
Importieren Sie einige Parameter als System.Array-Typen, indem Sie die MSIL manuell bearbeiten (siehe folgendes Beispiel).
Durchsuchen der MSIL nach
.method public hidebysig newslot virtual instance void InSArray([in] int32[]& marshal( safearray int) ppsa) runtime managed internalcall
Ersetzen durch
.method public hidebysig newslot virtual instance void InSArray(class [mscorlib]System.Array& marshal( safearray) ppsa) runtime managed internalcall
Zum Abrufen aus verwaltetem Code
int[] lengthsArray = new int[1] { 3 }; int[] boundsArray = new int[1] { -1 }; Array param2 = Array.CreateInstance( typeof(int), lengthsArray, boundsArray ); for( int i = param2.GetLowerBound( 0 ); i <= param2.GetUpperBound( 0 ); i++ ) param2.SetValue( i * 10, i ); sum = tstArrays.InSArray( ref param2 );
Beibehalten der Signatur
Die folgende IDL-Deklaration enthält eine COM-Methodensignatur.
HRESULT TestPreserveSig2([in] int inParam, [out,retval] int* outParam);
Tlbimp.exe ändert die Signatur von COM-Methoden. Parameter, die in der IDL mit [out, retval] markiert sind, werden zu Rückgabewerten von verwalteten Methoden. Alle HRESULT-Werte, die auf einen Fehler hinweisen, werden in verwaltete Ausnahmen umgewandelt. In einigen Fällen muss die ursprüngliche COM-Methodensignatur beibehalten werden (z. B., wenn die Methode etwas anderes als Erfolgs-HRESULTs zurückgibt). Die folgende verwaltete Darstellung enthält ein Beispiel einer Signatur, die Sie ändern können.
Verwaltete Darstellung in MSIL
.method public hidebysig newslot virtual
instance int32 TestPreserveSig2([in] int32 inParam) runtime managed internalcall
{
Ersetzen durch
.method public hidebysig newslot virtual
instance int32 TestPreserveSig2([in] int32 inParam, [out] int32& outParam) runtime managed internalcall preservesig
Um zu sehen, welches HRESULT zurückgegeben wird
int hr = tst.TestPreserveSig2( -3, out retValue );
Console.WriteLine( "Return value is {0}", retValue );
if( hr == 0 )
Console.WriteLine( "HRESULT = S_OK" );
else if ( hr == 1 )
Console.WriteLine( "HRESULT = S_FALSE" );
else
Console.WriteLine( "HRESULT = {0}", hr );
Übergeben von Null anstelle eines Verweises auf einen Werttyp
Die folgende IDL-Deklaration enthält einen IDL-Zeiger auf eine Struktur.
HRESULT TestPassingNull([in, unique] Point* refParam);
Tlbimp.exe importiert den Parameter als Verweis auf den Werttyp Point . In C# und Visual Basic 2005 kann ein NULL-Verweis (in Visual Basic Nothing) nicht als Parameter übergeben werden, wenn ein Verweis auf einen Werttyp erwartet wird. Wenn für die COM-Funktion ein NULL-(Nothing-)Parameter erforderlich ist, können Sie die Signatur ändern, indem Sie die MSIL bearbeiten.
Durchsuchen der MSIL nach
.method public hidebysig newslot virtual
instance void TestPassingNull(
[in] valuetype MiscSrv.tagPoint& refParam)
runtime managed internalcall
Ersetzen durch
.method public hidebysig newslot virtual
instance void TestPassingNull([in] native int) runtime managed internalcall
Mit der geänderten Signatur können Sie einen Nullwert übergeben. Wenn jedoch reale Werte übergeben werden müssen, müssen Sie die Methode der Marshal-Klasse verwenden (siehe folgendes Beispiel).
tagPoint p = new tagPoint();
p.x = 3;
p.y = 9;
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( p ));
Marshal.StructureToPtr( p, buffer, false );
tst.TestPassingNull( buffer );
Marshal.FreeCoTaskMem( buffer );
tst.TestPassingNull( IntPtr.Zero );
Siehe auch
Aufgaben
Gewusst wie: Bearbeiten von Interop-Assemblys
Gewusst wie: Manuelles Erstellen von Wrappern
Konzepte
Anpassen von durch die Laufzeit aufrufbaren Wrappern
Anpassen von durch COM aufrufbaren Wrappern