10

在 MSDN 上,我找到了两个属性的以下描述:

PreserveSig将 PreserveSig 字段设置为 true 以直接转换具有 HRESULT 或 retval 值的非托管签名;将其设置为 false 以自动将 HRESULT 或 retval 值转换为异常。默认情况下,PreserveSig 字段为 true。

SetLastError使调用者能够使用 Marshal.GetLastWin32Error API 函数来确定执行方法时是否发生错误。在 Visual Basic 中,默认值为 true(这会增加一些开销);在 C# 和 C++ 中,默认值为 false。

我的问题是:这两者如何相互关联?假设我将 PreserveSig 设置为“false”——这意味着我应该将 HRESULT 转换为异常——如果非托管函数返回表示错误或未发生错误的整数,如何将其转换为异常?

另外,如果我设法使用 PreserveSig 提取异常,为什么还需要调用 GetLastWin32Error 方法?

亲切的问候PK

4

1 回答 1

18

Win32 函数几乎从不返回HRESULT. 相反,它们返回 aBOOL或使用特殊值来指示错误(例如,CreateFilereturns INVALID_HANDLE_VALUE)。它们将错误代码存储在每个线程变量中,您可以使用GetLastError(). SetLastError=true指示封送拆收器在本机函数返回后读取此变量,并将错误代码存储在您以后可以使用Marshal.GetLastWin32Error(). 这个想法是 .NET 运行时可能会在幕后调用其他 Win32 函数,这会在您有机会检查之前弄乱 p/invoke 调用中的错误代码。

返回 a HRESULT(或等价物,例如NTSTATUS)的函数与 Win32 函数属于不同的抽象级别。通常这些函数与 COM 相关(高于 Win32)或来自ntdll(低于 Win32),因此它们不使用 Win32 上一个错误代码(尽管它们可能在内部调用 Win32 函数)。

PreserveSig=false指示封送拆收器检查返回HRESULT,如果它不是成功代码,则创建并抛出包含HRESULT. DllImport然后,您的ed 函数的托管声明将void作为其返回类型。

请记住,C# 或 VB 编译器无法检查DllImported 函数的非托管签名,因此它必须信任您告诉它的任何内容。如果你PreserveSig=false使用一个返回非 a 的函数HRESULT,你会得到奇怪的结果(例如随机异常)。如果你SetLastError=true使用一个没有设置最后一个 Win32 错误代码的函数,你将得到垃圾而不是有用的错误代码。

于 2009-04-18T17:26:42.340 回答