Функции 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
функции, поэтому он должен доверять всему, что вы ей скажете. Если вы поместите PreserveSig=false
в функцию, которая возвращает что-то отличное от HRESULT
, вы получите странные результаты (например, случайные исключения). Если вы поставите SetLastError=true
на функцию, которая не устанавливает последний код ошибки Win32, вы получите мусор вместо полезного кода ошибки.