[Previous] [Contents] [Next]

Error Codes

Practically all COM+ interface methods return an HRESULT value. An HRESULT is defined simply as a long type, which means that it is a signed 32-bit value. The term HRESULT is a holdover from the days when 16-bit operating systems ruled the world and an HRESULT was a handle to a result. Today, an HRESULT is the result value itself. All HRESULT values are composed of three parts: the severity, the facility, and the status code. For many HRESULT names, these parts are separated by underscores. For example, the code for MK_E_MUSTBOTHERUSER is a combination of the moniker facility (MK), an error severity (E), and a status code indicating that user input is required for the operation to succeed (MUSTBOTHERUSER).

Figure 6-1 shows how an HRESULT is laid out in memory. The R, C, N, and r bits are reserved.

Click to view at full size.

Figure 6-1. The memory layout of an HRESULT.

The top bit (31) defines the severity code of the HRESULT value. The severity code contains 0 for success or 1 for an error. The facility codes are shown in the following table.

Facility Value Meaning
FACILITY_NULL 0 Used for general error codes such as S_OK
FACILITY_RPC 1 Errors from Remote Procedure Calls (RPCs)
FACILITY_DISPATCH 2 Errors from the IDispatch interface
FACILITY_STORAGE 3 Errors from the IStorage or IStream interface
FACILITY_ITF 4 Error codes defined by custom interfaces
FACILITY_WIN32 7 Errors from the Win32 API
FACILITY_WINDOWS 8 Errors from standard interfaces
FACILITY_SSPI 9 Errors from the Security Support Provider Interface (SSPI)
FACILITY_MSMQ 14 Errors from the Microsoft Message Queue Server (MSMQ)
FACILITY_COMPLUS 17 Errors from COM+ component services

FACILITY_ITF Error Codes

To ensure that facility codes don't conflict, developers outside Microsoft are not permitted to define new facility codes. In addition, you can define new status codes using only the FACILITY_ITF facility code, and then only in the range 0x0200 through 0xFFFF to avoid conflicting with Microsoft-defined status codes in the range 0x0000 through 0x01FF. It is legal for different interfaces to reuse identical status codes of the FACILITY_ITF facility for completely different errors. This reuse is possible because the HRESULT values returned by interface methods are considered part of the interface contract and therefore must be interpreted in the context of that interface.

Helper Macros

Microsoft provides several helpful macros that can help you work directly with HRESULT values. The HRESULT_SEVERITY, HRESULT_FACILITY, and HRESULT_CODE macros extract the severity, facility, and status codes from an HRESULT, respectively. The SUCCEEDED and FAILED macros test the severity portion of an HRESULT. If the top bit of the HRESULT is 0, the SUCCEEDED macro returns true. For an error severity code of 1, the SUCCEEDED macro returns false. The FAILED macro works in the exact opposite manner of the SUCCEEDED macro, returning true when the top bit of the HRESULT is 1. The MAKE_HRESULT macro composes an HRESULT value from severity, facility, and status codes.

All COM+ and Windows errors as well as the aforementioned macros are defined in the winerror.h system include file. To obtain a meaningful string that explains a system error code at run time, you can call the Win32 function FormatMessage. The ErrorMessage routine shown in the following code is a simple wrapper for FormatMessage that you can use; you call it with a user-provided string and the HRESULT. The companion CD contains a simple utility named Error that interactively decodes HRESULT values.

void ErrorMessage(char* szMessage, HRESULT hr)
{
    if(HRESULT_FACILITY(hr) == FACILITY_WINDOWS)
        hr = HRESULT_CODE(hr);

    char* szError;
    if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
        FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        (LPTSTR)&szError, 0, NULL) != 0)
    {
        printf("%s: (%0x) %s", szMessage, hr, szError);
        LocalFree(szError);
    }
    else
        printf("Error number not found\n");
}