2009-04-18 56 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