This week I was asked how to access a stream interface driver from an application. The request came from someone who was trying to call the XXX_Open, XXX_Write… functions directly from his application. By directly, I mean using LoadLibrary() and GetProcAddress().
Let’s start with stating that calling the functions directly is not the way to call the functions in a driver. In fact, a Windows CE 6.0 kernel driver cannot be accessed at all by applications directly. Let us think about that for a moment and say that the application could use LoadLibrary() to load the driver (which is possible if the driver has not be fixed up to run in kernel space.) If the application could do that, then the driver would not be a driver, but instead it would simply be a user mode DLL loaded by an application.
The Win32 API includes functions to call functions in a stream interface driver. These functions include:
Ø ActivateDeviceEx() and ActivateDevice()call the drivers XXX_Init()
Ø DeactiveateDevice()calls the drivers XXX_Deinit()
Ø WriteFile()calls the drivers XXX_Write()
Ø ReadFile() calls the driver’s XXX_Read()
Ø SetFilePointer() calls the driver’s XXX_Seek()
Ø DeviceIoControl() calls the driver’s XXX_IOControl()
To demonstrate these, I wrote the following application:
#define IOCTL_DO_SOMETHING <Set to some value that is defined by your driver>
 
HANDLE hDriverShell = INVALID_HANDLE_VALUE;
 
void UseDriverShell()
{
                HANDLE hDS;
                DWORD Data;
                DWORD BytesRead;
                DWORD BytesWritten;
                DWORD BytesHandled;
 
                // Get a handle to the driver. Which causes the driver's XXX_Open function to be called
                hDS = CreateFile( TEXT("XXX1:"), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
 
                // Readfile causes the driver's XXX_Read to be called
                ReadFile( hDS, &Data, sizeof( Data ), &BytesRead, 0 );
 
                // WriteFile causes the driver's XXX_Write to be called
                WriteFile( hDS, &Data, sizeof( Data ), &BytesWritten, NULL );
 
                // SetFilePointer causes XXX_Seek to be called
                SetFilePointer( hDS, 0, NULL, FILE_BEGIN );
 
                // DeviceIoControl causes the driver's XXX_IOControl to be called
                DeviceIoControl( hDS, IOCTL_DO_SOMETHING, &Data, sizeof( Data ), NULL, 0, &BytesHandled, NULL );
 
                // CloseHandle will call XXX_Close
                CloseHandle( hDS );
}
 
 
int WINAPI WinMain(     HINSTANCE hInstance,
                                                HINSTANCE hPrevInstance,
                                                LPTSTR    lpCmdLine,
                                                int       nCmdShow)
{
                RETAILMSG( 1, (TEXT("FunWithDrivers starting\n")));
                AddDriverShellToRegistry();
                if( LoadDriverShell() )
                {
                                // So now the driver is loaded, we can interact with it
 
                                UseDriverShell();
                               
                                UnloadDriverShell();
                }
                else
                                RETAILMSG( 1, (TEXT("Failed to load driver, exiting\n")));
                RETAILMSG( 1, (TEXT("FunWithDrivers ending\n")));
}
I didn’t include the function AddDriverShellToRegistry(), LoadDriverShell() or UnloadDriverShell() because I included them in Windows CE: Loading a Driver with ActivateDeviceEx and because they really aren’t necessary if the driver is loaded when the system boots.
Note that these same methods can be used by a driver to access another driver, they are not limited to use by applications.
Copyright © 2009 – Bruce Eitman
All Rights Reserved