2009-04-18 47 views
9

在MSDN我發現下面的描述了兩個屬性:的DllImport - PreserverSig和SetLastError屬性

PreserveSig將PreserveSig字段設置爲true,直接翻譯與HRESULT或retval的值,非託管簽名;將其設置爲false以自動將HRESULT或retval值轉換爲例外。默認情況下,PreserveSig字段爲true。

SetLastError使調用者能夠使用Marshal.GetLastWin32Error API函數來確定執行該方法時是否發生錯誤。在Visual Basic中,默認值爲true(這會增加一些開銷);在C#和C++中,默認值爲false。

我的問題是:這兩者如何相互關聯?假設我將PreserveSig設置爲'false' - 這意味着我應該將HRESULT轉換爲異常 - 如果非託管函數返回表示發生錯誤或沒有錯誤的整數,那麼這怎麼會被轉換爲異常呢?

此外,爲什麼我需要調用GetLastWin32Error方法,如果我以某種方式設法使用PreserveSig提取異常?

親切的問候 PK

回答

14

Win32函數幾乎從未返回HRESULT。而是返回BOOL或使用特殊值指示錯誤(例如,CreateFile返回INVALID_HANDLE_VALUE)。它們將錯誤代碼存儲在每個線程變量中,您可以使用GetLastError()來讀取它。 SetLastError=true指示封送處理器在本地函數返回後讀取此變量,並存儲錯誤代碼,您可以稍後使用Marshal.GetLastWin32Error()讀取它。這個想法是,.NET運行庫可能會在你有機會檢查它之前調用其他Win32函數在幕後弄亂P/invoke調用中的錯誤代碼。

返回HRESULT(或同等值,例如NTSTATUS)的函數屬於與Win32函數不同的抽象級別。通常這些函數是與COM相關的(在Win32上面)或從ntdll(在Win32下面),所以它們不使用Win32最後一個錯誤代碼(它們可能會在內部調用Win32函數)。

PreserveSig=false指示封送程序檢查退貨HRESULT,如果它不是成功代碼,則創建並拋出包含HRESULT的異常。您的DllImport ed函數的管理聲明然後將void作爲其返回類型。請記住,C#或VB編譯器不能檢查DllImport ed函數的非託管簽名,所以它必須信任你所說的任何內容。如果您將PreserveSig=false放在一個返回除HRESULT之外的函數中,您將得到奇怪的結果(例如隨機異常)。如果您將SetLastError=true放在不設置最後一個Win32錯誤代碼的函數上,您將得到垃圾而不是有用的錯誤代碼。

+0

我沒有COM對象的經驗,所以讓我再問一個關於創建方法簽名的問題。問題是:當我看到COM函數返回HRESULT時,我可以將我的方法標記爲返回void並設置PreserveSig = false(如您所述),或者設置PreserveSig = true並將我的方法標記爲返回IntPtr以手動檢查返回的代碼? – pkolodziej 2009-04-18 17:42:53