VisualDDKHelpers.h file

VisualDDK simplifies driver debugging by visualizing most of core NT structures, such as FILE_OBJECT, DEVICE_OBJECT, etc. However, another important aspect of visualization is displaying NTSTATUS values and showing detailed information about handles. See the screenshot below from WinCDEmu debugging session:

screenshot watch

However, Microsoft C/C++ compiler creates one serious obstacle on the way to this aim. It simply does not put information about typedefs in PDB files. That way, a NTSTATUS variable is seen by debugger as unsigned long, and a HANDLE is seen as void *. VisualDDK provides a workaround for that, consisting of two parts:

  • A special include file that #define-s NTSTATUS as an enum with a special long name.
  • Special code in VisualDDK debugger that renames all occurrences of this special enum back into NTSTATUS.

Similarily, HANDLE is defined as a pointer to a special structure.

Ah, yes, if you have noticed that MS C++ debugger shows HRESULT values correctly, be informed that it is a dirty hack implemented in compiler. If you create an empty project not including any headers and define 2 equal typedefs called HRESULT and, for instance, XRESULT, the HRESULT will be displayed as HRESULT, while XRESULT will turn into "unsigned long" in debugger.

While VisualDDK debugger always supports these special types, if you want your program to have this debug support, you need to include a special file called VisualDDKHelpers.h. This file is automatically generated when you create new projects using VisualDDK Project Wizard, however, you can include it in any project you want. The file is very short and simple and contains the following code:

#pragma once

/*! \file
\brief Contains definitions making handles and NTSTATUS variables recognizable by debugger
This file contains definitions for special helper structures and enums, so NTSTATUS and HANDLE
variables will not appear in debugger as "unsigned long" and "void *".

Once the variable type is recognized correctly, VisualDDK can display additional information
about this types, such as translated NTSTATUS code and object referenced by handle.
*/


#ifdef _DEBUG

#include <excpt.h>
#include <ntdef.h>

typedef enum NTSTATUS_VisualDDK_Helper {} NTSTATUS_VisualDDK_Helper_t;
C_ASSERT(sizeof(NTSTATUS_VisualDDK_Helper_t) == sizeof(NTSTATUS));

#define NTSTATUS NTSTATUS_VisualDDK_Helper_t

typedef struct HANDLE_VisualDDK_Helper *HANDLE_VisualDDK_Helper_t, **PHANDLE_VisualDDK_Helper_t;
C_ASSERT(sizeof(HANDLE_VisualDDK_Helper_t) == sizeof(HANDLE));
C_ASSERT(sizeof(PHANDLE_VisualDDK_Helper_t) == sizeof(PHANDLE));

#define HANDLE HANDLE_VisualDDK_Helper_t
#define PHANDLE PHANDLE_VisualDDK_Helper_t

#endif

Note that it should be included before including any DDK headers, and it needs to be included from all source files in your project. Otherwise, decorated C++ names for function with HANDLE as void * from file A and for the same function from with HANDLE as struct __HANDLE from file B would not match.

That VisualDDKHelpers.h works on both x86 and x64 platforms and does not change size of redefined types, making no problem with calling NT API. Please also note that the special type replacement is performed only in DEBUG builds. To modify this, change the VisualDDKHelpers.h file contents.