Freigeben über


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

COM-Datentypen

Anpassen von durch COM aufrufbaren Wrappern

Referenz

Type Library Importer-Tool (Tlbimp.exe)