2009-04-18 10 views
9

Auf der MSDN habe ich die folgende Beschreibung für die beiden Attribute gefunden:DllImport - PreserverSig und SetLastError Attribute

PreserveSig das PreserveSig Feld auf true gesetzt, um direkt unmanaged Signaturen mit HRESULT oder Retval Werten zu übersetzen; Setzen Sie es auf "false", um HRESULT- oder retval-Werte automatisch in Ausnahmen zu konvertieren. Standardmäßig ist das PreserveSig-Feld wahr.

SetLastError Ermöglicht dem Aufrufer, mithilfe der Marshal.GetLastWin32Error-API-Funktion festzustellen, ob beim Ausführen der Methode ein Fehler aufgetreten ist. In Visual Basic ist der Standardwert wahr (was zusätzlichen Aufwand verursacht); In C# und C++ ist der Standardwert falsch.

Meine Frage ist: Wie diese beiden miteinander in Beziehung stehen? Angenommen, ich habe PreserveSig auf 'false' gesetzt - dies bedeutet, dass HRESULT in Ausnahme konvertiert werden soll - wenn die nicht verwaltete Funktion eine ganze Zahl zurückgibt, die anzeigt, dass ein Fehler oder kein Fehler aufgetreten ist, wie kann dies in eine Ausnahme umgesetzt werden?

Auch warum muss ich GetLastWin32Error Methode aufrufen, wenn ich irgendwie die Ausnahme mit PreserveSig extrahieren konnte?

Mit freundlichen Grüßen PK

Antwort

14

Win32-Funktionen so gut wie nie ein HRESULT zurück. Stattdessen geben sie BOOL zurück oder verwenden spezielle Werte, um Fehler anzuzeigen (z. B. CreateFile gibt INVALID_HANDLE_VALUE zurück). Sie speichern den Fehlercode in einer Variablen pro Thread, die Sie mit GetLastError() lesen können. SetLastError=true weist den Marshaller an, diese Variable zu lesen, nachdem die native Funktion zurückgegeben wurde, und speichert den Fehlercode, in dem Sie ihn später mit Marshal.GetLastWin32Error() lesen können. Die Idee ist, dass die .NET-Laufzeit möglicherweise andere Win32-Funktionen hinter den Kulissen aufruft, die den Fehlercode von Ihrem p/invoke-Aufruf durcheinander bringen, bevor Sie eine Chance bekommen, ihn zu untersuchen.

Funktionen, die eine HRESULT (oder gleichwertig, z. B. NTSTATUS) zurückgeben, gehören zu einer anderen Abstraktionsebene als Win32-Funktionen. Im Allgemeinen sind diese Funktionen COM-bezogen (über Win32) oder von ntdll (unter Win32), so dass sie nicht den Win32-letzten Fehlercode verwenden (sie können Win32-Funktionen jedoch intern aufrufen).

PreserveSig=false weist den Marshaller an, die Rückgabe HRESULT zu überprüfen, und wenn es kein Erfolgscode ist, eine Ausnahme zu erstellen und zu werfen, die die HRESULT enthält. Die verwaltete Deklaration Ihrer DllImport Ed-Funktion hat dann void als Rückgabetyp.

Denken Sie daran, dass der C# - oder VB-Compiler die nicht verwaltete Signatur der ED-Funktionnicht überprüfen kann, also muss sie dem vertrauen, was immer Sie ihm sagen. Wenn Sie PreserveSig=false auf eine Funktion setzen, die etwas anderes als HRESULT zurückgibt, erhalten Sie seltsame Ergebnisse (z. B. zufällige Ausnahmen). Wenn Sie SetLastError=true auf eine Funktion setzen, die den letzten Win32-Fehlercode nicht festlegt, erhalten Sie anstelle eines nützlichen Fehlercodes Müll.

+0

Ich habe keine Erfahrung mit COM-Objekten, also lassen Sie mich noch eine Frage bezüglich der Erstellung der Methodensignatur stellen. Die Frage ist: Wenn ich sehe, dass die COM-Funktion HRESULT zurückgibt, kann ich meine Methode als void zurückgeben und PreserveSig = false (wie Sie sagten) setzen oder PreserveSig = true setzen und meine Methode als IntPtr zurückgeben, um den zurückgegebenen Code manuell zu untersuchen. – pkolodziej

+0

Ja, das ist richtig, außer HRESULTs sind UInt32s, nicht IntPtrs. –

+0

Danke - Sie waren sehr hilfreich. – pkolodziej