Thursday, September 29, 2011

unique_error

I work in places that abjure exceptions in most of the code. I have spent years writing both error-code and exception based error handling and building libraries for both environments. With some simple building blocks error-codes and exceptions can be joined such that each library can be written agnostic to exceptions and allow each caller of the library to choose whether to throw or pass error codes. These also implement certain exception features; such as requiring explicit checking of error codes.

One building block is unique_error.

unique_error serves much the same function as the std::system_error but with additional features and eschewing some things that blocked my adoption of std::system_error. unique_error does not require that all the error values of a type be redefined. It uses traits discovered by ADL to specify the behavior. It terminates the program if an error is set and then not checked. unique_error is also similar to unique_ptr in that it treats an error like a resource.

Here is the complete definition of unique_winerror:

namespace unique_winerror_def
{
struct tag {};

// found by ADL via the tag&& parameter
inline bool unique_error_ok(DWORD winerror, tag &&)
{
  return winerror == ERROR_SUCCESS;
}

// found by ADL via the tag&& parameter
inline DWORD unique_error_default(tag &&)
{
  return ERROR_SUCCESS;
}
}

//
// implementations of these must be included
// in the final module
//
void unique_error_report_initiated(
  DWORD value,
  unique_winerror_def::tag &&);
void unique_error_report_reset(
  DWORD value,
  unique_winerror_def::tag &&);

typedef unique_error<unique_winerror_def::tag>
unique_winerror;

inline unique_winerror make_winerror_if(BOOL is_last_error)
{
  unique_winerror result;
  if (is_last_error) {
    return std::move(result.reset(GetLastError()));
  }
  return std::move(result);
}

inline
unique_winerror::static_error winerror_cast(DWORD raw)
{
  return unique_winerror::cast(raw);
}

Using unique_winerror

CreateEvent example

Starting from a previous post we can now improve the code further:

namespace Win32
{
template<typename Resource, Resource InvalidValue>
std::pair<unique_winerror, Resource>
WinerrorAndResource(Resource resource)
{
  return std::make_pair(
      make_winerror_if(Resource == InvalidValue),
      Resource);
}

namespace Event
{
inline auto EventAndWinerror(
  HANDLE apiResult) -> decltype(
      WinerrorAndResource<HANDLE, nullptr>(
          apiResult))
{
  return WinerrorAndResource<HANDLE, nullptr>(
      apiResult);
}
}
}

// now you can write this
namespace we = Win32::Event;
unique_winerror winerror;
HANDLE event = nullptr;

std::tie(
  winerror,
  event) = we::EventAndWinerror(
      CreateEvent(
          nullptr
          make(we::Reset::Manual),
          make(we::Value::Reset),
          nullptr));
if (!winerror)
{
  return;
}

LoadString example

The complexities of LoadString for arbitrary sized strings is encapsulated here:

inline
unique_winerror
LoadStringRaw(
  HINSTANCE instance,
  UINT id,
  const range<WCHAR*>& space,
  range<WCHAR*>* spaceUsed,
  size_t* spaceRequested)
{
  if (spaceUsed) {
    *spaceUsed = space;
    spaceUsed->advance_end(-space.size());
  }

  if (spaceRequested) {
    *spaceRequested = space.size();
  }

  SetLastError(ERROR_SUCCESS);

  int loadResult = LoadStringW(
      instance,
      id,
      space.begin(),
      space.size());

  auto winerror = make_winerror_if(TRUE);

  if (loadResult >= 0) {
    if ((loadResult + 1) < space.size()) {
      if (winerror.ok()) {
        *spaceUsed = space;
        spaceUsed->advance_end(
          loadResult - space.size());
      }
    } else {
      *spaceRequested = std::max<size_t>(
          3,
          static_cast<size_t>(space.size() * 1.5));

      if (winerror.ok()) {
        winerror = winerror_cast(ERROR_MORE_DATA);
      }
    }
  } else {
    if (winerror.ok()) {
      winerror = winerror_cast(ERROR_UNIDENTIFIED_ERROR);
    }
  }

  return winerror;
}

inline
std::wstring
LoadStdString(
  HINSTANCE instance,
  UINT id,
  size_t sizeLimit = 2048,
  size_t initialSize = 80)
{
  unique_winerror winerror;
  std::wstring result;
  RANGE_NAMESPACE::range<WCHAR*> spaceUsed;
  size_t spaceRequested = initialSize;

  while (spaceRequested < sizeLimit) {
    result.resize(spaceRequested);
    winerror = LoadStringRaw(
        instance,
        id,
        make_range_raw(result),
        &spaceUsed,
        &spaceRequested);
    if (winerror != winerror_cast(ERROR_MORE_DATA)) {
      winerror.throw_if();
      break;
    }
    winerror.suppress();
    continue;
  }

  return std::move(result);
}

std::wstring title;

title = LoadStdString(
    hInstance,
    IDS_APP_TITLE);

Implementation

Maintained here.

template<typename ErrorTag>
class unique_error
{
public:
  typedef unique_error
  this_type;

  typedef ErrorTag
  tag;

  typedef decltype(unique_error_default(tag()))
  type;

  class static_error
  {
  private:
    type value;
  };

  static static_error cast(type raw);
  static this_type make(type raw);
  static this_type make(const static_error& other);

  ~unique_error();

  unique_error();
  unique_error(static_error other);
  unique_error(unique_error && other);
  unique_error(const unique_error& other);

  void swap(unique_error& other);
  unique_error& operator=(unique_error other);

  operator
  typename unspecified_bool<this_type>::type() const;

  this_type& reset();
  this_type& reset(type raw);
  type release();

  type get() const;
  bool try_ok() const;
  bool ok() const;

  const this_type& suppress() const;
  this_type& suppress();

  void throw_if(const std::string& message) const;
  void throw_if(const char* message = NULL) const;

private:
  type value;
  mutable Disposition::type disposition;
};

Tuesday, September 27, 2011

an unwinder should be in the standard library

The Unwinder is an implementation of the ScopeGuard pattern. The Unwinder is a class with a constructor that accepts a function and then runs that function in its destructor. The class has a method to dismiss the Unwinder. A dismissed unwinder will not run the function in its destructor. The Unwinder can be used as a generic implementation of the RRID (Resource Release Is Destruction) pattern.

With the addition of lambdas, auto and declspec to the C++ language the Unwinder becomes so trivial to use that in many cases no RAII class should be written. The implementation I use is called Unwinder.

Unwinder usage

int main()
{
  CRITICAL_SECTION lock = {};
  if (
    !InitializeCriticalSectionAndSpinCount(
        &lock,
        0x00000400)) {
    terminate();
  }

  ON_UNWIND_AUTO([&] {DeleteCriticalSection(&lock);});

  EnterCriticalSection(&lock);
  ON_UNWIND_AUTO([&] {LeaveCriticalSection(&lock);});

  // protected region

  {
    LeaveCriticalSection(&lock);
    ON_UNWIND_AUTO([&] {EnterCriticalSection(&lock);});

    // unprotected region
  }

  // protected region

  return 0;
}

Comparisons


This actually intersects with discussions of code style. There are many ways to structure function implementations. Of those there are a few common patterns that produce predictable results. Here are two structures; goto-cleanup and nested-scope:

int main()
{
  //
  // The goto-cleanup structure
  //

  CRITICAL_SECTION lock = {};
  BOOL inLock = FALSE;

  if (
    !InitializeCriticalSectionAndSpinCount(
        &lock,
        0x00000400)) {
    terminate();
  }

  EnterCriticalSection(&lock);
  inLock = TRUE;

  // protected region

  LeaveCriticalSection(&lock);
  inLock = FALSE;

  // unprotected region

  EnterCriticalSection(&lock);
  inLock = TRUE;

  // protected region

Cleanup:
  if (inLock) {
    LeaveCriticalSection(&lock);
    inLock = FALSE;
  }
  DeleteCriticalSection(&lock);
  return 0;
}
int main()
{
  //
  // The nested-scope structure
  //

  CRITICAL_SECTION lock = {};

  if (
    !!InitializeCriticalSectionAndSpinCount(
        &lock,
        0x00000400)) {
    {
      EnterCriticalSection(&lock);

      // protected region

      {
        LeaveCriticalSection(&lock);

        // unprotected region

        EnterCriticalSection(&lock);
      }

      // protected region

      LeaveCriticalSection(&lock);
    }

    DeleteCriticalSection(&lock);
  }

  return 0;
}

In both of these structures the code to undo or release an action is located a great distance from the action. Thus to read or verify the code one must scroll back and forth, even in short functions one must bounce visually all over the code to understand it.
Also, both of these are exception phobic. They require that exceptions are not used in the code.
Using the Unwinder, one is able to read left->right, top->bottom with no need to bounce. Each action is immediately followed by the undo. Even better, the code becomes exception agnostic, it will behave correctly with or without exceptions.

Implementation


The Unwinder is so subtle to build that it really should be in the standard. I have been through at least 4 implementations to reach my current one. One of the previous implementations was contributed by a coworker. His was based on std::function and did not require a macro to use correctly. After using it in my code for a while I pointed out that std::function could throw on construction and that this required changes to the implementation and made usage very tricky. After a year of periodic reviews of and changes to that implementation we finally decided to deprecate it, it was just too subtle and risky. The implementation included here does require macros, but is exception agnostic. This implementation is maintained here.

//
// common tools
//

#define MAKE_IDENTIFIER_EXPLICIT_PASTER(Prefix, Suffix) \
  Prefix ## Suffix

#define MAKE_IDENTIFIER_EXPLICIT(Prefix, Suffix) \
  MAKE_IDENTIFIER_EXPLICIT_PASTER(Prefix, Suffix)

#define MAKE_IDENTIFIER(Prefix) \
  MAKE_IDENTIFIER_EXPLICIT(Prefix, __LINE__)

#define FAIL_FAST_FILTER() \
  __except(FailFastFilter(GetExceptionInformation())) \
  { \
  } do {} while(0,0)

inline
LONG WINAPI FailFastFilter(
  __in  struct _EXCEPTION_POINTERS* exceptionInfo)
{
  RaiseFailFastException(
    exceptionInfo->ExceptionRecord,
    exceptionInfo->ContextRecord,
    0);
  return EXCEPTION_CONTINUE_SEARCH;
}

template<typename Function>
auto FailFastOnThrow(
  Function && function) -> decltype(
      std::forward<Function>(function)())
{
  //
  // __ try must be isolated in its own
  // function in order for the compiler
  // to reason about C++ unwind in the
  // calling and called functions.
  //
  __try {
    return std::forward<Function>(function)();
  }
  FAIL_FAST_FILTER();
}

#define FAIL_FAST_ON_THROW(Function) \
  FailFastOnThrow((Function))

//
// unwinder
//

template<typename Function>
class unwinder
{
public:
  ~unwinder() {
    if (!!function) {
      FAIL_FAST_ON_THROW([&] {(*function)();});
    }
  }

  explicit unwinder(Function* functionArg)
    : function(functionArg) {
  }

  void dismiss() {
    function = nullptr;
  }

private:
  unwinder();
  unwinder(const unwinder&);
  unwinder& operator=(const unwinder&);

  Function* function;
};

#define ON_UNWIND(Name, Function) \
  ON_UNWIND_EXPLICIT( \
      uwfunc_ ## Name, \
      Name, \
      Function)

#define ON_UNWIND_AUTO(Function) \
  ON_UNWIND_EXPLICIT( \
      MAKE_IDENTIFIER(uwfunc_), \
      MAKE_IDENTIFIER(unwind_), \
      Function)

#define ON_UNWIND_EXPLICIT(FunctionName, UnwinderName, Function) \
  auto FunctionName = (Function); \
  unwinder<decltype(FunctionName)> \
  UnwinderName(std::addressof(FunctionName))

Thursday, September 22, 2011

I loathe bool function parameters

What does HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); do?
In this case bManualReset = TRUE and bInitialState = FALSE.

By combining patterns that I observed in the code of various co-workers and adding some of my own, I built the following pattern for making enums that can be used for parameters with any number of states, including bool.

namespace Win32
{
namespace Event
{
namespace Reset
{
enum type {
  // ensures that zero
  // initialized is invalid
  Invalid = 0,

  Manual,
  Auto,

  End,
  Begin = Manual
};

inline BOOL make(type from)
{
  switch (from) {
  case Manual:
    return TRUE;
  case Auto:
    return FALSE;
  default:
    terminate();
  };
}
}

namespace Value
{
enum type {
  // ensures that zero
  // initialized is invalid
  Invalid = 0,

  Set,
  Reset,

  End,
  Begin = Set
};

inline BOOL make(type from)
{
  switch (from) {
  case Set:
    return TRUE;
  case Reset:
    return FALSE;
  default:
    terminate();
  };
}
}
}
}

// now you can write this
// (the make functions are found via ADL)
namespace we = Win32::Event;
HANDLE event = nullptr;
event = CreateEvent(
    nullptr,
    make(we::Reset::Manual),
    make(we::Value::Reset),
    nullptr
    );

A remaining issue is that the compiler cannot enforce the type safety on the result of the make functions, so reversing the bManualReset and bInitialState parameters will compile without error and lie to readers of the code.

This issue does not plague functions that are defined to use the enum types. So, with a little more work:

namespace Win32
{
namespace Event
{
inline HANDLE Create(
  Reset::type reset,
  Value::type value,
  LPCWSTR name = nullptr
)
{
  return CreateEventW(
      nullptr,
      make(reset),
      make(value),
      name);
}

inline HANDLE Create(
  LPSECURITY_ATTRIBUTES security,
  Reset::type reset,
  Value::type value,
  LPCWSTR name = nullptr
)
{
  return CreateEventW(
      security,
      make(reset),
      make(value),
      name);
}
}
}

// now you can write this
namespace we = Win32::Event;
HANDLE event = nullptr;
event = we::Create(
    we::Reset::Manual,
    we::Value::Reset
    );

I general I try to avoid recreating named values and wrapping Api functions. Both the set of values and the valid inputs to the Api can change over time which requires me to chase the current definitions. Also, these change the surface of the Api, which creates an additional learning curve for callers. In this case where the api takes two BOOL parameters, I think the enums are valuable, but I am still somewhat ambivalent about the inline functions.

Tuesday, September 20, 2011

NTSTATUS

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
}

Thursday, September 15, 2011

HRESULT

HRESULT is the highest fidelity error code of the three big ones (WINERROR, NTSTATUS and HRESULT). Both of the other error types can be converted, without any information loss, into an HRESULT via HRESULT_FROM_WIN32 and HRESULT_FROM_NT.

HRESULT was defined as the error type for COM functions to return.

HRESULT and NTSTATUS have a similar structure but very different sets of values.
1bit holds 2 severity levels, SUCCESS, ERROR.
1bit is used to allow HRESULT_FROM_NT to store a full NTSTATUS in an HRESULT. The define for this bit is FACILITY_NT_BIT.
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 S_OK, E_FAIL and S_FALSE.
FACILITY_WIN32 contains all the WINERROR codes.

Checking HRESULT values must be done via the SUCCEEDED(hr) or FAILED(hr) macros.

HRESULT Usage

HRESULT ApiReturningHresult(HANDLE handle)
{
  if (handle == INVALID_HANDLE_VALUE) {
    return E_HANDLE;
  }
  return S_OK;
}

HRESULT hr = S_OK;
HANDLE handle = INVALID_HANDLE_VALUE;
hr = ApiReturningHresult(handle);
if (FAILED(hr))
{
  printf("ApiReturningHresult returned %x", hr);
  exit();
}

Conversions to HRESULT

NTSTATUS ntstatus = STATUS_SUCCESS;
HRESULT hr = HRESULT_FROM_NT(ntstatus);

DWORD winerror = ERROR_SUCCESS;
HRESULT hr = HRESULT_FROM_WIN32(winerror);

Conversions from HRESULT

HRESULT = S_OK;
NTSTATUS ntstatus = STATUS_SUCCESS;
if (hr & FACILITY_NT_BIT)
{
  ntstatus = hr & ~FACILITY_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;
}

HRESULT hr = S_OK;
DWORD winerror = ERROR_SUCCESS;
if (SUCCEEDED(hr))
{
  winerror = S_OK;
} else if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
{
  winerror = HRESULT_CODE(hr);
} else
{
  winerror = ERROR_UNIDENTIFIED_ERROR;
}

Tuesday, September 13, 2011

WINERROR

WINERROR has it's roots in DOS which is why it is also referred to as DosError. RtlNtStatusToDosError() is an example which will be discussed more later. DOS errors were in turn derived from the C standard library errno.

Values of WINERROR are defined in winerror.h and look like ERROR_SUCCESS. They are an enumeration that are expected to fit in the lower 16bits of the 32bit WINERROR type, more on that later. WINERROR values are sometimes returned through the API result, but often an API will return a BOOL or HANDLE and pass any errors to SetLastError() and then return FALSE or an invalid-handle, the caller will retrieve the WINERROR by calling GetLastError(). ERROR_SUCCESS is the only success value for WINERROR.

Api Examples:

DWORD ApiReturningWinerror(HANDLE handle)
{
  if (handle == INVALID_HANDLE_VALUE) {
    return ERROR_INVALID_PARAMETER;
  }
  return ERROR_SUCCESS;
}

DWORD winerror = ERROR_SUCCESS;
HANDLE handle = INVALID_HANDLE_VALUE;
winerror = ApiReturningWinerror(handle);
if (winerror != ERROR_SUCCESS)
{
  printf("ApiReturningWinerror returned %d", winerror);
  exit();
}

BOOL ApiReturningBool(HANDLE handle)
{
  if (handle == INVALID_HANDLE_VALUE) {
    SetLastError(ERROR_INVALID_PARAMETER);
    // The caller should call GetLastError()
    return FALSE;
  }
  // the common pattern is that SetLastError
  // is only called on failure.
  // Thus the caller should NOT call GetLastError()
  return TRUE;
}

DWORD winerror = ERROR_SUCCESS;
HANDLE handle = INVALID_HANDLE_VALUE;
if (!ApiReturningBool(handle))
{
  winerror = GetLastError();
  printf("ApiReturningBool returned %d", winerror);
  exit();
}

Conversions to WINERROR

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
}

HRESULT hr = S_OK;
DWORD winerror = ERROR_SUCCESS;
if (SUCCEEDED(hr))
{
  winerror = S_OK;
} else if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
{
  winerror = HRESULT_SCODE(hr);
} else
{
  winerror = ERROR_UNIDENTIFIED_ERROR;
}

Conversions from WINERROR

DWORD winerror = ERROR_SUCCESS;
HRESULT hr = HRESULT_FROM_WIN32(winerror);

DWORD winerror = ERROR_SUCCESS;
NTSTATUS ntstatus = NTSTATUS_FROM_WIN32(winerror);

Both of the FROM_WIN32 macros work by masking only the lower 16bits of the WINERROR value into the resulting NTSTATUS or HRESULT

Thursday, September 8, 2011

error codes in Windows

Differences between and best practices for WINERROR, HRESULT, RPC_STATUS, SECURITY_STATUS and NTSTATUS?

Why would a developer care?

These error types and their values are an often ignored part of the API contract. Using the return value incorrectly has the same type of consequences as using a cast to pass the wrong data type to a parameter of an API, code just doesn't work, and often fails first in the wild.

I recently began running into code like this:

// ERROR_SUCCESS is a WINERROR value
NTSTATUS status = ERROR_SUCCESS;
WCHAR* buffy;

buffy = (WCHAR*)malloc(1);
if (buffy == NULL)
{
  // this is an HRESULT value
  status = E_OUTOFMEMORY;
}

// not only is this a WINERROR value, but HRESULT and
// NTSTATUS have many success values, not just one
if (status != ERROR_SUCCESS)
{
  return status;
}

I went searching for information about what each type is and the relationships between them and how to use them correctly. Here is what I learned.

They are all 32bit values, some signed some unsigned. Some are defined in terms of bit fields and require macros or inline-functions to check their current state. Others are straight enumerations.

One of the complexities is best demonstrated with the HRESULT type. Lets look at the out of memory condition. Here are some of the possible encodings:

ExpressionHRESULT value
E_OUTOFMEMORY0x8007000E
HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY)0x8007000E
HRESULT_FROM_NT(STATUS_NO_MEMORY)0xD0000017
HRESULT_FROM_NT(
NTSTATUS_FROM_WIN32(ERROR_OUTOFMEMORY))
0xD007000E
STG_E_INSUFFICIENTMEMORY0x80030008
NTE_NO_MEMORY0x8009000E

There was some effort to make the values agree across the different expressions.

Many Api's will pick a set of return codes and then build internal maps from all the errors they receive from other Api's to the set they have decided to return. Thus most code calling Api's can expect that only one encoding will be returned.

Primary Windows Error Types

There will be subsequent posts that expand on each of these types. Here is a summary:

WINERROR

Includewinerror.h
TypeDWORD
Structurevalues in the range 0-16384
Successvalue == ERROR_SUCCESS
Failurevalue != ERROR_SUCCESS
ConversionsHRESULT_FROM_WIN32(value)
NTSTATUS_FROM_WIN32(value)

HRESULT

Includewinerror.h
TypeHRESULT
Structure[1bit Severity]
[1bit Reserved]
[1bit Customer]
[1bit FACILITY_NT_BIT]
[12bit Facility]
[16bit Code]
SuccessSUCCEEDED(value)
FailureFAILED(value)
ConversionsHRESULT is a superset
of all the other error types.
They all have lossless conversions
to HRESULT but it doesn't have
lossless conversions to anything else

NTSTATUS

Include
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS

#include <winternl.h>
#include <ntstatus.h>
TypeNTSTATUS
Structure[2bit Severity]
[1bit Customer]
[1bit Reserved]
[12bit Facility]
[16bit Code]
SuccessNT_SUCCESS(value)
Failure!NT_SUCCESS(value)
Other
Tests
NT_INFORMATIONAL(value)
NT_WARNING(value)
NT_ERROR(value)
ConversionsHRESULT_FROM_NT(value)

Derived/Subset Windows Error Types

RPC_STATUS

Includerpcnterr.h
TypeRPC_STATUS
StructureA subset of the WINERROR values, redefined as RPC_S_...
Successvalue == RPC_S_OK
Failurevalue != RPC_S_OK
ConversionsHRESULT_FROM_WIN32(value)
NTSTATUS_FROM_WIN32(value)

SECURITY_STATUS

Includewinerror.h
TypeSECURITY_STATUS or HRESULT
StructureA subset of the HRESULT values (from FACILITY_NULL and FACILITY_SECURITY)
SuccessSUCCEEDED(value)
FailureFAILED(value)
Conversions

Tuesday, September 6, 2011

hello

Welcome to my unconsciously fictional autobiography

I expect that most of what I write here will be about things I have already experienced and therefore from my unique memory of them.

A radiolab podcast about Memory and Forgetting described how every time we recall a memory it is rewritten and that each time it is rewritten it is slightly modified. So that each time we remember something the memory becomes less accurate.

Maybe some of my fiction will be incorporated into the fiction of the reader, which is ultimately the point of this.

Thank you