DllImport - PreserverSig和SetLastError属性

时间:2009-04-18 16:27:48

标签: interop dllimport

在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

1 个答案:

答案 0 :(得分: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错误代码的函数上,你将得到垃圾而不是有用的错误代码。