Previously, I introduce a Stream Interface Driver that was just a shell of a driver or a driver that didn’t do anything useful. I thought that it would be good to flesh it out a little and add some code to demonstrate some driver features that are fairly common. To get started, let’s flesh out the first function that gets called when the driver loads; DllEntry().   DllEntry() is typically fairly basic, but does some important things.
First, I will fill in the function, and then I will discuss what it does.
BOOL WINAPI DllEntry(HINSTANCE DllInstance, ULONG Reason, LPVOID Reserved)
                switch( Reason )
                                case DLL_PROCESS_ATTACH:
                                                DEBUGMSG(ZONE_INIT, (TEXT("XXX Driver Process Attach\r\n")));
                                                DisableThreadLibraryCalls((HMODULE) DllInstance);
                                case DLL_PROCESS_DETACH:
                                                DEBUGMSG( ZONE_INIT, (TEXT("XXX Driver Process Detach\r\n")));
Now to look at what DllEnty() does. We can see that it handles two events; Process Attach and Detach.
On process attach, it first outputs a DEBUGMSG announcing the process attach. Then it registers the dll with the kernel subsystem or at least that is the guidance that Platform Builder Help provides. What it really does is register the dll so that the debug zones can be modified externally, for example by using the Target Control Window. The debug zones control which DEBUGMSG calls actually output to the debug port using the global variable dpCurSettings.
The following defines dpCurSettings for driver shell. Note that the name of this structure is not optional; the debug macros use this variable name. In fact if you use DEBUGMSG and don’t declare dpCurSettings you will get an error when you build.
// Debug Zones.
#ifdef DEBUG
    #define DBG_INIT    0x0001
    #define DBG_OPEN    0x0002
    #define DBG_READ    0x0004
    #define DBG_WRITE   0x0008
    #define DBG_CLOSE   0x0010
    #define DBG_IOCTL   0x0020
    #define DBG_THREAD 0x0040
    #define DBG_EVENTS 0x0080
    #define DBG_CRITSEC 0x0100
    #define DBG_ALLOC   0x0200
    #define DBG_FUNCTION 0x0400
    #define DBG_WARNING 0x0800
    #define DBG_ERROR   0x1000
DBGPARAM dpCurSettings = {
                TEXT("XXX Driver"),
So now the debug zones are registered, the next call is to DisableThreadLibraryCalls() which tells the system not to call DllEntry() for thread attach and detach. Drivers don’t typically need those calls and this can reduce paging and call overhead.
Then DllEntry doesn’t do anything but output a DEBUGMSG on process detach. You might find a need to do more here if for instance you allocate something in the attach handler.
UPDATE:  Valter asked a good question about the call to DEBUGREGISTER().  He noted that I call it after calling DEBUGMSG() the first time.  That may have been a bad choice by me, but it really doesn't effect anything, so I thought it would be good to discuss this further.

The question was: if the call to DEBUGREGISTER is after the DEBUGMSG, will the DEBUGMSG output anything?

In fact, the DEBUGMSG will output, if ZONE_INIT is TRUE.  The call to DEBUGREGISTER does not effect the use of DEBUGMSG, but instead provides access to dbCurSettings from outside of the module.  This allows CEShell to change the mask at runtime.  It is not a requirement to call DEBUGREGISTER, but it is a good practice.

So, when I set the mask in dpCurSettings to 1, turning on ZONE_INIT output, the following was sent to the debug port when the driver was loaded:

   XXX Driver Process Attach

 Tags: ,  

Copyright © 2008 – Bruce Eitman
All Rights Reserved