I'm having problems with post-installation of WSUS on Windows 2012 R2. When I run it from the GUI I get this: Log file is located at C: Users administrator.xxxxxxx AppData Local Temp 2 tmp35BC.tmp Post install is starting Fatal Error: The object identifier does not represent a valid object. HResults are used often. As I understand, HResults are nothing more than a 32 bit entity where the different bits supply info on the result of certain operations. In some code I found online I often see things like int hres =. Being a total noob I went to check what this means.
There are three common error code formats used throughout Windows. In the kernel and native part, NTSTATUS is used exclusively. The Win32 API uses its own error codes (they do not really have a name, so I will refer to them as Win32 error codes) and COM uses HRESULTs — though the separation is not always so sharp, e.g. the safe string functions (StringCch* and friends) also return HRESULTs although they do not belong to COM.
HRESULT (From winerror.h)
NTSTATUS and Win32 error codes (From Winerror.h or ntstatus.h)
NTSTATUS* and Win32 error codes share the same definition:
In user mode, these codes are primarily encountered as SEH exception codes (e.g. EXCEPTION_ACCESS_VIOLATION, 0xC0000005) or return values. However, due to compatibility reasons, all common error codes defined in winerror.h (such as ERROR_FILE_NOT_FOUND, 0x2) do not quite adhere to their definition. Neither have they set Severity to 0y11 nor have they set their facility code to FACILITY_WIN32). Unsurprisingly, they are the same as in OS/2 (see DosExecPgm as an example).
Another unfortunate property of these Win32 error codes is, that no typedef for them exists. In fact, some APIs such as RegOpenKeyEx treat them as signed (LONG), others such as GetLastError treat them as unsigned (DWORD). Again, this is probably due to compatibility reasons.
So how compatible are those codes? Comparing the structure of HRESULTs and NTSTATUS/Win32 error codes, it is worth noting that HRESULTs explicitly allow for holding NTSTATUS values (Informational NTSTATUS become success HRESULTS, Warning NTSTATUS become failure HRESULTs). Even the other way round, assigning HRESULT values to NTSTATUS variables seems to be ok, given that the R, C, N and r bits of HRESULTS are usually 0.
So on a syntactic level, assigning NTSTATUS values to HRESULTs and vice versa seems to be correct. But let us have a look at the facility codes:
NTSTATUS (ntstatus.h):
Win32 error codes and HRESULT(winerror.h):
Having the same format, NTSTATUS and Win32 error codes could be expected to use the same facility codes. However, this is not the case — instead, Win32 error codes (according to winerror.h) use the facility values of HRESULTs! As a consequence, interchanging NTSTATUS and Win32 error codes is syntacticly ok but changes their semantics due to non matching facility codes.
With this background in mind, it is now possible to define a conversion matrix:
From | |||
NTSTATUS | Win32 | HRESULT | |
To | NTSTATUS | Yes 1, 2 | Yes 1 |
Win32 | LsaNtStatusToWinError() or HRESULT_FROM_NT() 1, 4 | Yes 3 | |
HRESULT | HRESULT_FROM_WIN32( LsaNtStatusToWinError()) or HRESULT_FROM_NT() 1, 4 | Yes 2 |
Hresult Code
Winrt::hresult_error Struct
1 Facility may need to be adapted
2 Holds for ‘real’ Win32 error codes. For compatibility error codes, use HRESULT_FROM_WIN32
3 As long as you have a ‘real’ HRESULT (i.e. not one from HRESULT_FROM_WIN32) and want to get a ‘real’ Win32 error code (i.e. not a compaitibility one) — otherwise it can get tricky
4 Note that HRESULT_FROM_NT does not take the NT Status to Win32 Error Code conversion table into account, thus the result may not be what one would expect. Using LsaNtStatusToWinError takes this table into account, but yields ‘compatibility’ Win32 error code.
* It turns out that the NTSTATUS documentation in the DDK contradicts the definition in ntstatus.h (3790): According to winerror.h, bit 28 is reserved whereas the DDK counts it as part of the facility field (Which, I guess, is wrong).