C++ snacks: HRESULT and Windows Error Codes are not the same thing

created at 12-29-2021 views: 31

Introduction

When using C++ to develop Windows programs, we often see the following judgments:

HRESULT hr = ::RegCreateKeyEx(hk, szKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hk, NULL);

if (SUCCEEDED(hr)) 
{

In the code, use the SUCCEEDED macro to determine the return value of the function RegCreateKeyEx().

Some programmers think that when RegCreateKeyEx returns 0, it means success, and S_OK is 0, so they habitually use the SUCCEEDED macro to make judgments.

Some people use the following method to judge, which looks more rigorous:

HRESULT hr = ::RegCreateKeyEx(hk, szKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hk, NULL);

if (S_OK == hr) 
{

Indeed, the second type is more rigorous, at least it will not cause a big problem, while the first one is completely a big bug, this bug is not a problem under normal circumstances. But once there is a problem, you can't find it.

What's wrong? Let me introduce it below.

SUCCEEDED

First look at the definition of this macro (WinError.h):

// Generic test for success on any status value (non-negative numbers
// indicate success).

#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)

It can be seen from this that it is to convert hr to HRESULT type, and then make a judgment whether it is greater than 0. It is also stated in the comment: But when the value is a non-negative number, it means success.

In other words, as long as HRESULT is a value greater than or equal to 0, it is considered successful.

HRESULT

Let's look at the definition of HRESULT (winnt.h):

// Component Object Model defines, and macros

#ifndef _HRESULT_DEFINED
#define _HRESULT_DEFINED
typedef LONG HRESULT;

#endif // !_HRESULT_DEFINED

Oh, it turns out that HRESULT is an integer of Long type.

In MSDN, you can find more detailed information:

mdn document

As shown in the figure above, HRESULT is a 4-byte Long type with a total of 32 bits. in:

The 31st bit is the s bit, which is the sign bit, because the HRESUlT format stipulates that all successes are positive integers, and the failure values are negative numbers.

The 30th bit is the r bit, which is a reserved bit, but when the n bit (28 bit) is not set, it must be 0; if the n bit is used, it is used with the s bit to identify the NTSTATUS value.

The 29th bit is the c bit, which means Custom, that is, the custom bit. If it is a Microsoft-defined return value, this bit is 0; if it is custom, the bit is 1.

The 28th bit is the n bit, which means NTSTATUS. If the value is 0, the value of NTSTATUS can be mapped to a value of HRESULT.

The 27th bit is the x bit, which is reserved and must be 0.

The 26th to 16th bits are Facility, and 11 bits are used to indicate the source of the error, such as

FACILITY_WINDOWS means from the Windows subsystem

The 15th to the 1st are the Code bits, which are used to store the error value.

It can be seen from this that only the last 2 bytes are used to indicate the return value and the others are auxiliary information, which is mainly used for the return value of the COM function.

Common HRESULT values

Name Description Value
S_OK operation successful 0x00000000
S_FALSE operation is successful but there is a problem 0x00000001L
E_ABORT operation aborted 0x80004004
E_ACCESSDENIED Access denied 0x80070005
E_FAIL unknown error 0x80004005

Note: In addition to S_OK, there is also a S_FALSE, which also belongs to success.

Therefore, for the convenience of everyone, Microsoft has specially provided the SUCCEEDED macro and the FAILED macro to facilitate your judgment.

At this point, everyone understands: The SUCCEEDED macro is used to determine whether the function in COM is executed successfully. Failure is a negative number, and success is 0 and a positive number.

Windows Error Code

In the previous code, we called a Windows API:

:RegCreateKeyEx(hk, szKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hk, NULL);

The declaration of this API is:

LONG WINAPI RegCreateKeyEx(
  __in        HKEY hKey,
  __in        LPCTSTR lpSubKey,
  __reserved  DWORD Reserved,
  __in_opt    LPTSTR lpClass,
  __in        DWORD dwOptions,
  __in        REGSAM samDesired,
  __in_opt    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __out       PHKEY phkResult,
  __out_opt   LPDWORD lpdwDisposition
);

From MSDN, it returns ERROR_SUCCESS when it succeeds, other values are failures, and other values are error codes similar to GetLastError. These error codes are Windows Error Code.

Windows Error Codes

Microsoft defines a large number of Windows Error Codes in WinError.h. The range of this error code is 0x0000~0xFFFF, which is 2 bytes, but it is not limited to 2 bytes, and 4 bytes can also be used. save. In the Windows API, this error code is widely used. For example, the above registry API, its return value is this kind of error code.

Another feature of this error code is that Microsoft defines more detailed and readable description information for these error codes, which can be obtained through the FormatMessage function. In the Chinese environment, the translated Chinese is displayed.

Windows Error Codes are all positive numbers except ERROR_SUCCESS, that is, you cannot use the SUCCEEDED macro to judge, because this macro only judges whether it is a non-negative number. For it, all Windows Error Codes are successful.

Common Windows Error Codes

Win32 error codes Description
0x00000000 ERROR_SUCCESS The operation completed successfully.
0x00000000 ERROR_SUCCESS The operation completed successfully.
0x00000001 ERROR_INVALID_FUNCTION Incorrect function.
0x00000002 ERROR_FILE_NOT_FOUND The system cannot find the file specified.
0x00000003 ERROR_PATH_NOT_FOUND The system cannot find the path specified.
0x00000004 ERROR_TOO_MANY_OPEN_FILES The system cannot open the file.
0x00000005 ERROR_ACCESS_DENIED Access is denied.

So in the previous code, HRESULT and Windows Error Code are confused, especially the first type of code. It will also be judged as successful when the registry fails. The second type is because both are 0, which happens to not be. There is a problem, but it is recommended not to mix it up.

SUMMARY

summary of HRESULT and Windows error code

created at:12-29-2021
edited at: 12-29-2021: