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:
int Add(int a, int b);
void Add(int a, int b, out int sum);
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.
[PreserveSig]
int Add(int a, int b, out int sum);
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.
[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.