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
}