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