NTSTATUS
was defined for code native to the Windows NT operating system. It was a part of the very clean separations built between the core OS and the various subsystems where user code was expected to run (POSIX, WIN32, WIN16/DOS, OS/2). Over time it has begun to leak into code in the WIN32 subsystem. One example of leakage is the BCrypt Api's.
Just including ntstatus.h and windows.h together produces errors:
main.cpp #include <windows.h> #include <winternl.h> #include <ntstatus.h> int main() { return 0; } >cl main.cpp Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. main.cpp [redacted]ntstatus.h(147) : warning C4005: 'STATUS_WAIT_0' : macro redefinition [redacted]winnt.h(1983) : see previous definition of 'STATUS_WAIT_0' ...
I spent some hours recently tracking down an incantation that would allow ntstatus.h to be included without the errors, the following was the result:
#define WIN32_NO_STATUS #include <windows.h> #undef WIN32_NO_STATUS #include <winternl.h> #include <ntstatus.h>
NTSTATUS
defines 2bits to hold four severity levels, SUCCESS, INFORMATION, WARNING, ERROR.
There are 12bits set aside for Facilities, which are used to create feature-specific error codes. Within each facility is 16bits to define codes specific to that facility.
FACILITY_NULL
contains generic codes like STATUS_SUCCESS
.
FACILITY_NTWIN32
contains all the WINERROR codes.
Checking NTSTATUS
values must be done via the NT_SUCCESS(ntstatus), NT_INFORMATION(ntstatus), NT_WARNING(ntstatus) or NT_ERROR(ntstatus) macros.
NTSTATUS
Usage
NTSTATUS ApiReturningNtStatus(HANDLE handle) { if (handle == INVALID_HANDLE_VALUE) { return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS; } NTSTATUS ntstatus = STATUS_SUCCESS; HANDLE handle = INVALID_HANDLE_VALUE; ntstatus = ApiReturningNtStatus(handle); if (!NT_SUCCESS(ntstatus)) { printf("ApiReturningNtStatus returned %x", ntstatus); exit(); }
Conversions to NTSTATUS
HRESULT = S_OK; NTSTATUS ntstatus = STATUS_SUCCESS; if (hr & FACILITY_NT_BIT) { ntstatus = hr & ~FACTILITY_NT_BIT; } else if (HRESULT_FACILITY(hr) == FACILITY_WIN32) { ntstatus = NTSTATUS_FROM_WIN32(HRESULT_CODE(hr)); } else if (SUCCEEDED(hr)) { ntstatus = STATUS_SUCCESS; } else { ntstatus = STATUS_UNSUCCESSFUL; } DWORD winerror = ERROR_SUCCESS; NTSTATUS ntstatus = STATUS_SUCCESS; ntstatus = NTSTATUS_FROM_WIN32(winerror);
Conversions from NTSTATUS
NTSTATUS ntstatus = STATUS_SUCCESS; HRESULT hr = HRESULT_FROM_NT(ntstatus); NTSTATUS ntstatus = STATUS_SUCCESS; DWORD winerror = RtlNtStatusToDosError(ntstatus); if (winerror == ERROR_MR_MID_NOT_FOUND) { // there is no conversion return ERROR_UNIDENTIFIED_ERROR; #if 0 // The following is common, but doesn't work out well // especially when combined with HRESULT_FROM_WIN32 // and NTSTATUS_FROM_WIN32 return ntstatus; #endif }
I know this is an old post, but I am working on a WIN32 project that uses Bcrypt and I've stumbled upon this problem.
ReplyDeleteThanks for the useful information!