Win32 functions almost never return a HRESULT
. Instead they return a BOOL
or use special values to indicate error (e.g. CreateFile
returns INVALID_HANDLE_VALUE
). They store the error code in a per-thread variable, which you can read with GetLastError()
. SetLastError=true
instructs the marshaler to read this variable after the native function returns, and stash the error code where you can later read it with Marshal.GetLastWin32Error()
. The idea is that the .NET runtime may call other Win32 functions behind the scenes which mess up the error code from your p/invoke call before you get a chance to inspect it.
Functions which return a HRESULT
(or equivalent, e.g. NTSTATUS
) belong to a different level of abstraction than Win32 functions. Generally these functions are COM-related (above Win32) or from ntdll
(below Win32), so they don't use the Win32 last-error code (they might call Win32 functions internally, though).
PreserveSig=false
instructs the marshaler to check the return HRESULT
and if it's not a success code, to create and throw an exception containing the HRESULT
. The managed declaration of your DllImport
ed function then has void
as its return type.
Remember, the C# or VB compiler cannot check the DllImport
ed function's unmanaged signature, so it has to trust whatever you tell it. If you put PreserveSig=false
on a function which returns something other than a HRESULT
, you will get strange results (e.g. random exceptions). If you put SetLastError=true
on a function which does not set the last Win32 error code, you will get garbage instead of a useful error code.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…