How to Use Function typedefs in C++ Driver Code to Improve PREƒast Results

Updated: May 2, 2007

Static tools such as PREƒast for Drivers and Static Driver Verifier produce better results when function typedef declarations - also called "role types" - are used to declare callback functions. For drivers written in C, this is simple to do. For drivers written in C++, however, there are several variations that are best clarified through examples.

This tip shows several examples of how to implement function typedef declarations in C++ driver code. The function shown is a DriverEntry (typedef DRIVER_INITIALIZE) function, but the same usage patterns also apply to other system-defined callbacks that have function typedef declarations. Note that the first few examples illustrate specific points but do not include everything that would be needed in a working driver. The last example is more complete.

*
On This Page
DriverEntry Declared without DRIVER_INITIALIZEDriverEntry Declared without DRIVER_INITIALIZE
DriverEntry Declared with DRIVER_INITIALIZEDriverEntry Declared with DRIVER_INITIALIZE
DriverEntry Implemented as a Static Member FunctionDriverEntry Implemented as a Static Member Function
DriverEntry Implemented as a Regular Member FunctionDriverEntry Implemented as a Regular Member Function
A More Complete ExampleA More Complete Example

DriverEntry Declared without DRIVER_INITIALIZE

The first example resembles a DriverEntry function, but it is not declared by using the DRIVER_INITIALIZE typedef:

NTSTATUS
DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{   //... }

When analyzing this function, PREƒast reports warning 28101, "The Drivers module has inferred that the current function is a DriverEntry function." Note that DriverEntry is a special case: PREƒast recognizes it by inference from its name and signature because there's no other way for PREƒast to recognize it. PREƒast can identify other callback types from context, so DriverEntry is the only function for which PREƒast makes this kind of inference.

DriverEntry Declared with DRIVER_INITIALIZE

Because PREƒast usually makes a correct inference, declaring a callback in the following style is the correct action, both to eliminate warning 28101 and enhance checking. In driver code written in C++, the extern "C" is required to create C-style linkage and allow the linker to recognize this as the driver entry callback. The function is declared to be a DRIVER_INITIALIZE function, so warning 28101 is suppressed:

extern "C"
DRIVER_INITIALIZE DriverEntry;

extern "C"
NTSTATUS
DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{ //... }

DriverEntry Implemented as a Static Member Function

A static member function can be used to implement DriverEntry, but not directly. C++ qualifies the linker name of the function with the class name, so the function won't be linked correctly. ("Linker magic" could be used to work around this problem, but it isn't recommended.)

A simple indirection wrapper to call the class member function is the simplest solution, as shown in the following example, which declares the static member function sf_driverEntry as a DRIVER_INITIALIZE function type. Note that extern "C" doesn't appear-it isn't allowed. If the static member function is not declared by using DRIVER_INITIALIZE, PREƒast issues warning 28101:

class MyDriverClass
{
public:
    static DRIVER_INITIALIZE sf_DriverEntry;

};

NTSTATUS
MyDriverClass::sf_DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{ //... }

DriverEntry Implemented as a Regular Member Function

PREƒast does not recognize a member function that appears similar to a DriverEntry function as actually being a DriverEntry function, both because the language wouldn't allow it and the operating system doesn't provide a valid this pointer at the point of call.

For example, the mf_DriverEntry member function in the following class declaration is not recognized as a DriverEntry function because it is an ordinary member function:

class MyDriverClass
{
public:
	NTSTATUS
	mf_DriverEntry
	   __in PDRIVER_OBJECT DriverObject,
	   __in PUNICODE_STRING RegistryPath);

};

NTSTATUS
MyDriverClass::mf_DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{  //... }

However, when the member function is declared with an explicit typedef declaration, PREƒast does recognize the function as being a DriverEntry function because the typedef makes it clear that the developer intends the function to meet the contractual requirements of a DriverEntry function. The function could be used to actually implement the required DriverEntry functionality if called from an extern "C" wrapper function that had access to an appropriate member pointer. The following example shows a class declaration that declares a DriverEntry member function as a DRIVER_INITIALIZE function type:

class DriverObject
{
public:
    DRIVER_INITIALIZE DriverEntry;
};

NTSTATUS
DriverObject::DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{ //... }

A More Complete Example

The following example shows all of the relevant pieces for one possible solution that uses function typedef declarations in C++ driver code. In this case, DriverEntry does the little bit of work needed to create or initialize the C++ MyDriverClass class and then calls mf_DriverEntry as a C++ member function to finish the work. Note that this example omits error handling and code for the actual work that a DriverEntry routine is expected to perform. For details, see "Writing a DriverEntry Routine" in the Windows Driver Kit (WDK) documentation.

class MyDriverClass
{
    PDRIVER_OBJECT m_DriverObject;
public:

    DRIVER_INITIALIZE mf_DriverEntry;
    MyDriverClass();
};

MyDriverClass *g_DriverObject;

// The C linkage wrapper function
extern "C"
DRIVER_INITIALIZE DriverEntry;

extern "C"
NTSTATUS
DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{
   // Create/Initialize class MyDriverClass with a pointer
   // to it in g_DriverObject.
   g_DriverObject = new MyDriverClass();
   if (g_DriverObject == NULL)
   {
       //...
   }

   NTSTATUS st = g_DriverObject
        ->mf_DriverEntry(DriverObject,RegistryPath);

   //...
}

// Implement the DriverEntry member function
NTSTATUS
MyDriverClass::mf_DriverEntry(
   __in PDRIVER_OBJECT DriverObject,
   __in PUNICODE_STRING RegistryPath
   )
{
   m_DriverObject = DriverObject;
   //...
}

For more information

PREƒast for Drivers

C++ for Kernel-Mode Drivers: Pros and Cons

Writing a DriverEntry Routine

Developing Drivers with the Windows Driver Foundation



Was This Information Useful?