Auf Englisch lesen

Teilen über


Implizite Methodensignaturübersetzungen in .NET-Interoperabilität

Um die Programmiersprache agnostisch zu halten, geben das Windows COM-System und viele Windows-APIs einen ganzzahligen 4-Byte-Typ namens HRESULT an, um anzugeben, ob eine API erfolgreich war oder fehlgeschlagen ist, zusammen mit einigen Informationen zum Fehler. Andere Werte, die an den Aufrufer übergeben werden müssen, werden über Zeigerparameter „zurückgegeben“, die als „out“-Parameter fungieren und in der Regel der letzte Parameter in der Signatur sind. Sprachen wie C# und Visual Basic übersetzen einen Fehlercode traditionell in eine Ausnahme, um zu ermitteln, wie Fehler in der Sprache weitergegeben werden, und erwarten, dass Interoperabilitätsmethoden das HRESULT nicht enthalten. Um die Methodensignatur in eine systemeigene Signatur zu übersetzen, verschiebt die Runtime den Rückgabewert der Methode auf einen zusätzlichen „out“-Parameter mit einer weiteren Dereferenzierungsebene (d. h. sie macht sie zu einem Zeiger auf den Rückgabetyp der verwalteten Signatur), und es wird ein HRESULT-Rückgabewert angenommen. Wenn die verwaltete Methode void zurückgibt, wird kein zusätzlicher Parameter hinzugefügt, und der Rückgabewert wird zu einem HRESULT. Sehen Sie sich beispielsweise die folgenden beiden C#-COM-Methoden an, die in dieselbe systemeigene Signatur übersetzt werden:

C#
int Add(int a, int b);

void Add(int a, int b, out int sum);
C
HRESULT Add(int a, int b, /* out */ int* sum);

PreserveSig in COM

Es wird erwartet, dass alle COM-Methoden in C# standardmäßig die übersetzte Signatur verwenden. Um Methoden ohne Signaturübersetzung und -verarbeitung von HRESULT-Werten zu verwenden und zu exportieren, fügen Sie die PreserveSigAttribute-Methode einer COM-Schnittstelle hinzu. Wenn das Attribut auf eine Methode angewendet wird, wird keine Übersetzung für die Signatur durchgeführt, und es werden keine Ausnahmen für fehlerhafte HRESULT-Werte ausgelöst. Dies gilt sowohl für integrierte COM als auch für von der Quelle generierte COM. Sehen Sie sich beispielsweise die folgende C#-Methodensignatur mit einem PreserveSig-Attribut und der entsprechenden nativen Signatur an.

C#
[PreserveSig]
int Add(int a, int b, out int sum);
C
HRESULT Add(int a, int b, int* sum);

Dies kann hilfreich sein, wenn die Methode möglicherweise unterschiedliche HRESULT-Werte zurückgibt, die keine Fehler sind, aber unterschiedlich behandelt werden müssen. Beispielsweise können einige Methoden den Wert S_FALSE zurückgeben, wenn eine Methode nicht fehlschlägt, sondern nur Teilergebnisse zurückgibt, und S_OK wenn alle Ergebnisse zurückgegeben werden.

PreserveSig mit P/Invokes

Das DllImportAttribute-Attribut verfügt auch über das Feld bool PreserveSig das ähnlich wie das Feld PreserveSigAttribute funktioniert, aber standardmäßig auf true festgelegt ist. Um anzugeben, dass die Laufzeit die verwaltete Signatur übersetzen und das zurückgegebene HRESULT behandeln soll, legen Sie das Feld PreserveSig auf false im DllImportAttribute fest. Sehen Sie sich z. B. die folgenden Signaturen von zwei P/Invokes an die gleiche systemeigene Methode an, eine, bei der PreserveSig auf false festgelegt ist, und eine, bei der der Standardwert true bebehalten wird.

C#
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true, PreserveSig = false)]
public static extern void SHAutoComplete(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);

[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true)]
public static extern int SHAutoCompleteHRESULT(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);

Hinweis

Von der Quelle generierte P/Invokes, die das Feld LibraryImportAttribute verwenden, weisen kein Feld PreserveSig auf. Der generierte Code geht immer davon aus, dass die systemeigene und die verwaltete Signatur identisch sind. Weitere Informationen finden Sie unter Von der Quelle generierte P/Invokes.

Manuelles Behandeln von HRESULT-Werten

Beim Aufrufen einer PreserveSig-Methode, die ein HRESULT zurückgibt, können Sie mit der ThrowExceptionForHR-Methode die entsprechende Ausnahme auslösen, wenn das HRESULT einen Fehler anzeigt. Ebenso können Sie bei der Implementierung einer PreserveSig-Methode die GetHRForException-Methode verwenden, um das HRESULT zurückzugeben, das einen entsprechenden Wert für die Ausnahme anzeigt.

Marshal HRESULTs als Strukturen

Bei Verwendung einer PreserveSig-Methode wird erwartet, dass int der verwaltete Typ für HRESULT ist. Wenn Sie jedoch eine benutzerdefinierte 4-Byte-Struktur als Rückgabetyp verwenden, können Sie Hilfsmethoden und Eigenschaften definieren, die das Arbeiten mit dem HRESULT vereinfachen können. Im integrierten Marshalling funktioniert dies automatisch. Um eine Struktur anstelle von int als verwaltete Darstellung von HRESULT in von der Quelle generiertem Marshalling zu verwenden, fügen Sie das MarshalAsAttribute-Attribut mit Error als Argument hinzu. Das Vorhandensein dieses Attributs interpretiert die Bits des HRESULT als Struktur neu.

Siehe auch