Windows CE 流驱动实例

先描述一下流式接口驱动的基本概念:

流式接口驱动:任何暴露流式接口函数的驱动程序都可以被称作流式接口驱动程序,也就是在驱动程序的DLL中把这些函数作为DLL的导出函数。在流式接口驱动程序中,驱动程序负责把外设抽象成一个文件,而应用程序则使用操作系统提供的文件API对外设进行访问。

 

流式接口函数:

XXX_Init()

XXX_Deinit()

XXX_Open()

XXX_Close()

XXX_IOControl()

XXX_PowerUp()

XXX_PowerDown()

XXX_Read()

XXX_Write()

XXX_Seek()

其中XXX是驱动程序的设备名称。例如串口驱动程序,其名称是COM。因此,XXX_Open在串口当中就被替换为COM_Open

 

流式驱动程序工作原理:

第一步:加载驱动程序。加载驱动程序有两种方式:第一种,当系统启动的时候,设备管理器会搜寻注册表的HKEY_LOCAL_MACHINE/Drivers/BuiltIn键下面的子键,并逐一加载子键下的每一个驱动,这一过程称之为BusEnum。第二种,应用程序可以调用ActivateDeviceEx()函数动态加载驱动程序。

第二步:设备管理器会从注册表的dll键值中获取驱动程序所在的DLL文件名。

第三步:设备管理器会调用LoadDriver函数把.dll加载到自己(也就是Device.exe)的虚拟地址空间内。

第四步:设备管理器会在注册表的HKEY_LOCAL_MACHINE/Drivers/Active下面记录所有已经加载的驱动程序记录,通常会包含设备的名称等等,ActivateDeviceEx()的第二个参数就是要在Active键下增加的内容。

第五步:设备管理器会调用驱动程序中的XXX_Init函数,并把上一步中添加的注册表

项的完整路径作为XXX_Init函数的第一个参数传入驱动程序内。

第六步:在XXX_Init中,通常需要对硬件进行一些最基本的初始化操作,例如打开硬件设备、影射硬件的I/O端口或缓存等。

通过前面六步,流式接口驱动程序已经被成功加载。下面是对驱动程序的操作。

第七步:应用程序需要使用该设备。首先,它会调用CreateFile(TEXT(XXX1), )来打开设备。CreateFile()函数是在FileSys.exe中实现的,但是FileSys.exe只作简单的判断,如果发现打开的是设备驱动程序而不是一个文件,就会重新把主动权交还给设备管理器。

第八步:设备管理器会调用驱动程序中的XXX_Open函数来打开设备。在XXX_Open中,驱动程序可能会对硬件进行一些额外的初始化工作,使硬件进入工作状态。

第九步:XXX_Open函数会把打开设备的结果返回给设备管理器。

第十步:设备管理器会把XXX_Open返回的结果再返回给应用程序中的CreateFile()函数调用。

通过第七到第十步,设备已经被成功的打开,接下来已经可以对设备进行读、写和控制操作了。我们以从设备中读取数据为例,进一步说明流式接口驱动的工作原理。

第十一步:应用程序使用第七步CreateFile调用返回的句柄作为ReadFile的第一个参数,来向设备发送读请求,同样ReadFile要经过FileSys.exe转发给设备管理器。

第十二步:设备管理器调用驱动程序中的XXX_Read函数,来读取设备的数据信息。

第十三步:在流式驱动程序中,XXX_Read函数可以与硬件交互,从硬件中读取必要的信息。然后返回给设备管理器,再返回给应用程序。

当应用程序不再使用该设备的时候,它可以调用CloseHandle()把设备关闭。

当系统不再使用该设备的时候,应用程序可以调用DeactivateDevice()函数把该驱动程序卸载。这时,设备管理器会负责把.dlldevice.exe的虚拟地址空间中移除,并且会从HKEY_LOCAL_MACHINE/Drivers/Active键下移除对该设备驱动的记录。这样,流式接口驱动程序的完整生命周期就结束了。

 

实现流式接口驱动程序通常只需四个步骤:

1. 为流式接口驱动程序选择一个前缀。

2. 实现流式接口驱动DLL所必需的接口函数。

3. 编写DLL的导出函数定义文件.DEF

4. 为驱动程序配置注册表。

 

 

 

好,下面开始进入正题,如何创建一个流式驱动程序及测试,该驱动程序并不操作实际的硬件,只是作为一个示例。

1.       先用PB创建一个基于模拟器平台的OS镜像,并生成OS镜像文件。

2.       PB创建一个新动态库工程MyDriver,选择A simple Windows CE DLL project

3.       MyDriver.def中加入如下内容:

LIBRARY MyDriver

 

EXPORTS

   DEM_Init

   DEM_Deinit

   DEM_Open

   DEM_Close

   DEM_IOControl

   DEM_PowerUp

   DEM_PowerDown

   DEM_Read

   DEM_Write

   DEM_Seek

 

4.        MyDriver.cpp中加入如下内容:

 

// MyDriver.cpp : Defines the entry point for the DLL application.

//

 

#include "stdafx.h"

 

DWORD DEM_Init(LPCTSTR pContext, LPCVOID lpvBusContext);

BOOL DEM_Deinit( DWORD hDeviceContext );

DWORD DEM_Open( DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode );

BOOL DEM_Close( DWORD hOpenContext );

BOOL DEM_IOControl( DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut );

void DEM_PowerUp( DWORD hDeviceContext );

void DEM_PowerDown( DWORD hDeviceContext );

DWORD DEM_Read( DWORD hOpenContext, LPVOID pBuffer, DWORD Count );

DWORD DEM_Write( DWORD hOpenContext, LPCVOID pBuffer, DWORD Count );

DWORD DEM_Seek( DWORD hOpenContext, long Amount, WORD Type );

 

#define IOCTL_DRIVER_DEMO   42

// Not exposed by the Device Driver

void DBGOut(DWORD dwValue);

 

HANDLE hMem=NULL;

DWORD dwCount;

BOOL APIENTRY DllMain( HANDLE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                                    )

{

       switch ( ul_reason_for_call )

       {

       case DLL_PROCESS_ATTACH:

              OutputDebugString(L"MyDriver - DLL_PROCESS_ATTACH/n");

              break;

       case DLL_PROCESS_DETACH:

              OutputDebugString(L"MyDriver - DLL_PROCESS_DETACH/n");

              break;

       case DLL_THREAD_ATTACH:

              OutputDebugString(L"MyDriver - DLL_THREAD_ATTACH/n");

              break;

       case DLL_THREAD_DETACH:

              OutputDebugString(L"MyDriver - DLL_THREAD_DETACH/n");

              break;  

       }

    return TRUE;

}

 

DWORD DEM_Init( LPCTSTR pContext, LPCVOID lpvBusContext)

{

       OutputDebugString(L"MyDriver - DEM_Init - Context: ");

       OutputDebugString(pContext);

       OutputDebugString(L"/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_Init/n");

       return 0x1234;

}

 

BOOL DEM_Deinit( DWORD hDeviceContext )

{

       OutputDebugString(L"MyDriver - DEM_Deinit/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_Deinit/n");

       return TRUE;

}

 

DWORD DEM_Open( DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode )

{

       OutputDebugString(L"MyDriver - DEM_Open/n");

       OutputDebugString(L"hDeviceContext - ");

       DBGOut(hDeviceContext);

       OutputDebugString(L"/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_Open/n");

       return 0x5678;

}

 

BOOL DEM_Close( DWORD hOpenContext )

{

       OutputDebugString(L"MyDriver - DEM_Close/n");

       OutputDebugString(L"hOpenContext - ");

       DBGOut(hOpenContext);

       OutputDebugString(L"/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_Close/n");

      

       return TRUE;

}

 

BOOL DEM_IOControl( DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut )

{

       OutputDebugString(L"MyDriver - DEM_IOControl/n");

       OutputDebugString(L"hOpenContext - ");

       DBGOut(hOpenContext);

       OutputDebugString(L"/n");

      

       switch (dwCode) {

       case IOCTL_DRIVER_DEMO:

              {

                     OutputDebugString(L"DRIVER DEMO IOCTL.../n");

                     // reverse the string...

                     HANDLE hTemp=LocalAlloc(LPTR,dwLenIn+1);

                     memset(hTemp,0x00,dwLenIn+1);

                     TCHAR *tcOut=(TCHAR*)hTemp;

                     TCHAR *tcIn=(TCHAR*)pBufIn;

                     DWORD dwChars=dwLenIn/2;

                     for (DWORD x=0;x < dwChars;x++) {

                            tcOut[x]=tcIn[dwChars-x-1];

                     }

                     memcpy(pBufOut,hTemp,dwLenIn);

                     LocalFree(hTemp);

                     *pdwActualOut=dwLenIn;

              }

              break;

       default:

              OutputDebugString(L"Unknown IOCTL/n");

              break;

       }

      

       OutputDebugString(L"MyDriver - ~ DEM_IOControl/n");

       return TRUE;

}

 

void DEM_PowerUp( DWORD hDeviceContext )

{

       OutputDebugString(L"MyDriver - DEM_PowerUp/n");

       OutputDebugString(L"hDeviceContext - ");

       DBGOut(hDeviceContext);

       OutputDebugString(L"/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_PowerUp/n");

}

 

void DEM_PowerDown( DWORD hDeviceContext )

{

       OutputDebugString(L"MyDriver - DEM_PowerDown/n");

       OutputDebugString(L"hDeviceContext - ");

       DBGOut(hDeviceContext);

       OutputDebugString(L"/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_PowerDown/n");

}

 

DWORD DEM_Read( DWORD hOpenContext, LPVOID pBuffer, DWORD Count )

{

       DWORD dwRetCount=0xffff;      // default to error

       OutputDebugString(L"MyDriver - DEM_Read/n");

       OutputDebugString(L"hOpenContext - ");

       DBGOut(hOpenContext);

       OutputDebugString(L"/n");

       if (NULL != hMem) {

              dwRetCount=dwCount;

              memcpy(pBuffer,hMem,dwCount);

       }

       OutputDebugString(L"MyDriver - ~ DEM_Read/n");

      

       return dwRetCount;

}

 

DWORD DEM_Write( DWORD hOpenContext, LPCVOID pBuffer, DWORD Count )

{

       OutputDebugString(L"MyDriver - DEM_Write/n");

       OutputDebugString(L"hOpenContext - ");

       DBGOut(hOpenContext);

       OutputDebugString(L"/n");

      

       if (NULL != hMem) {

              LocalFree(hMem);

       }

      

       hMem=LocalAlloc(LPTR,Count);

       memcpy(hMem,pBuffer,Count);

       dwCount=Count;

      

       OutputDebugString(L"MyDriver - ~ DEM_Write/n");

      

       return Count;

}

 

DWORD DEM_Seek( DWORD hOpenContext, long Amount, WORD Type )

{

       OutputDebugString(L"MyDriver - DEM_Seek/n");

       OutputDebugString(L"hOpenContext - ");

       DBGOut(hOpenContext);

       OutputDebugString(L"/n");

      

       OutputDebugString(L"MyDriver - ~ DEM_Seek/n");

      

       return 0;

}

 

 

void DBGOut(DWORD dwValue)

{

       TCHAR tcTemp[10];

       wsprintf(tcTemp,L"%ld",dwValue);

       OutputDebugString(tcTemp);

}

 

5.        project.reg文件中加入如下内容:

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/Sample]

    "Dll" = "mydriver.Dll"

    "Prefix" = "DEM"

    "Index" = dword:1

    "Order" = dword:0

    "FriendlyName" = "Demo Driver"

    "Ioctl" = dword:0

 

流式驱动程序算是完成了,编译该工程,生成系统镜像,启动模拟器平台从输出信息里就可以看到驱动程序被加载了。

780 PID:43f8f22a TID:43f9a002 MyDriver - DLL_PROCESS_ATTACH

    780 PID:43f8f22a TID:43f9a002 MyDriver - DEM_Init - Context:

    780 PID:43f8f22a TID:43f9a002 Drivers/Active/03

    780 PID:43f8f22a TID:43f9a002

    780 PID:43f8f22a TID:43f9a002 MyDriver - ~ DEM_Init

    790 PID:43f8f22a TID:43f9a002 MyDriver - DEM_Open

    790 PID:43f8f22a TID:43f9a002 hDeviceContext -

    790 PID:43f8f22a TID:43f9a002 4660

    790 PID:43f8f22a TID:43f9a002

    790 PID:43f8f22a TID:43f9a002 MyDriver - ~ DEM_Open

    790 PID:43f8f22a TID:43f9a002 MyDriver - DEM_IOControl

    790 PID:43f8f22a TID:43f9a002 hOpenContext -

    790 PID:43f8f22a TID:43f9a002 22136

    790 PID:43f8f22a TID:43f9a002

    790 PID:43f8f22a TID:43f9a002 Unknown IOCTL

    790 PID:43f8f22a TID:43f9a002 MyDriver - ~ DEM_IOControl

    790 PID:43f8f22a TID:43f9a002 MyDriver - DEM_Close

    790 PID:43f8f22a TID:43f9a002 hOpenContext -

    790 PID:43f8f22a TID:43f9a002 22136

    800 PID:43f8f22a TID:43f9a002

    800 PID:43f8f22a TID:43f9a002 MyDriver - ~ DEM_Close

    920 PID:43f8f22a TID:e3f24002 MyDriver - DLL_THREAD_ATTACH

    960 PID:43f8f22a TID:83f1f7aa MyDriver - DLL_THREAD_ATTACH

    960 PID:43f8f22a TID:63f1ffc6 MyDriver - DLL_THREAD_ATTACH

    960 PID:43f8f22a TID:63f1ffc6 MyDriver - DLL_THREAD_DETACH

    980 PID:43f8f22a TID:83f1f7aa MyDriver - DLL_THREAD_DETACH

 

下面再建一个测试工程。

1.       PB创建一个WCE Application工程MyApp,选择A typical Hello World! application

2.       为该应用程序添加菜单资源:

IDR_MENU MENU DISCARDABLE

BEGIN

    POPUP "File"

    BEGIN

        MENUITEM "Exit",                        ID_FILE_EXIT

        MENUITEM "Write",                       ID_DRIVER_WRITE

        MENUITEM "Read",                        ID_DRIVER_READ

        MENUITEM "Io Control",                  ID_DRIVER_IOCTL

    END

END

3.       MyApp.cpp的内容如下:

// MyApp.cpp : Defines the entry point for the application.

//

 

#include "stdafx.h"

#include "resource.h"

#include <commctrl.h>

 

#pragma comment(lib, "commctrl")

#define MAX_LOADSTRING 100

#define IDC_CMDBAR 0x101

HWND hWndCmdBar;

 

void WriteToDriver( );

void ReadFromDriver( );

void HandleIOCTL( );

 

#define IOCTL_DRIVER_DEMO   42

 

// Global Variables:

HINSTANCE hInst;                                                        // current instance

TCHAR szTitle[MAX_LOADSTRING];                                                        // The title bar text

TCHAR szWindowClass[MAX_LOADSTRING];                                                  // The title bar text

 

// Forward declarations of functions included in this code module:

ATOM                          MyRegisterClass(HINSTANCE hInstance);

BOOL                          InitInstance(HINSTANCE, int);

LRESULT CALLBACK  WndProc(HWND, UINT, WPARAM, LPARAM);

void WriteToDriver( )

{

       DWORD dwWritten;

       TCHAR *tcString=L"Demo String...";

       HANDLE hDrv=CreateFile(L"DEM1:",GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

       if (INVALID_HANDLE_VALUE == hDrv) {

              OutputDebugString(L"Failed to open Driver.../n");

       } else {

              WriteFile(hDrv,(LPVOID)tcString,lstrlen(tcString)*sizeof(TCHAR),&dwWritten,NULL);

       }

       CloseHandle(hDrv);

}

 

void ReadFromDriver( )

{

       DWORD dwRead;

       TCHAR tcTemp[30];

       HANDLE hDrv=CreateFile(L"DEM1:",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

       if (INVALID_HANDLE_VALUE == hDrv) {

              OutputDebugString(L"Failed to open Driver.../n");

       } else {

              memset(tcTemp,0x00,30*sizeof(TCHAR));

              ReadFile(hDrv,tcTemp,30,&dwRead,NULL);

              MessageBox(NULL,tcTemp,L"Demo Data",MB_OK);

       }

       CloseHandle(hDrv);

}

 

void HandleIOCTL( )

{

       HANDLE hDrv=CreateFile(L"DEM1:",GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

       TCHAR tcBuffer[10];

       DWORD dwBytesReturned;

      

       lstrcpy(tcBuffer,L"Hello");

      

       BOOL bRet=DeviceIoControl(

              hDrv,

              IOCTL_DRIVER_DEMO,

              tcBuffer,

              lstrlen(tcBuffer)*sizeof(TCHAR),

              tcBuffer,

              lstrlen(tcBuffer)*sizeof(TCHAR),

              &dwBytesReturned,

              NULL);

      

       MessageBox(NULL,tcBuffer,L"IOCTL Test",MB_OK);

       CloseHandle(hDrv);

      

}

 

int WINAPI WinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPTSTR     lpCmdLine,

                     int       nCmdShow)

{

      // TODO: Place code here.

       MSG msg;

       HACCEL hAccelTable;

 

       // Initialize global strings

       LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

       LoadString(hInstance, IDC_MyApp, szWindowClass, MAX_LOADSTRING);

       MyRegisterClass(hInstance);

 

       // Perform application initialization:

       if (!InitInstance (hInstance, nCmdShow))

       {

              return FALSE;

       }

 

       hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MyApp);

 

       // Main message loop:

       while (GetMessage(&msg, NULL, 0, 0))

       {

              if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))

              {

                     TranslateMessage(&msg);

                     DispatchMessage(&msg);

              }

       }

 

       return msg.wParam;

}

 

 

 

//

//  FUNCTION: MyRegisterClass()

//

//  PURPOSE: Registers the window class.

//

//  COMMENTS:

//

//    This function and its usage is only necessary if you want this code

//    to be compatible with Win32 systems prior to the 'RegisterClassEx'

//    function that was added to Windows 95. It is important to call this function

//    so that the application will get 'well formed' small icons associated

//    with it.

//

ATOM MyRegisterClass(HINSTANCE hInstance)

{

       WNDCLASS wc;

 

    wc.style = CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc = (WNDPROC) WndProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hInstance;

    wc.hIcon = 0;

    wc.hCursor = 0;

    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName = 0;

    wc.lpszClassName = szWindowClass;

 

       return RegisterClass(&wc);

}

 

//

//   FUNCTION: InitInstance(HANDLE, int)

//

//   PURPOSE: Saves instance handle and creates main window

//

//   COMMENTS:

//

//        In this function, we save the instance handle in a global variable and

//        create and display the main program window.

//

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

   HWND hWnd;

 

   hInst = hInstance; // Store instance handle in our global variable

 

   hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,

      0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

 

   if (!hWnd)

   {

      return FALSE;

   }

 

   ShowWindow(hWnd, nCmdShow);

   UpdateWindow(hWnd);

 

   return TRUE;

}

 

//

//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)

//

//  PURPOSE:  Processes messages for the main window.

//

//  WM_COMMAND    - process the application menu

//  WM_PAINT     - Paint the main window

//  WM_DESTROY      - post a quit message and return

//

//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

       PAINTSTRUCT ps;

       HDC hdc;

       TCHAR szHello[MAX_LOADSTRING];

       LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

 

       switch (message)

       {

       case WM_COMMAND:

              switch(LOWORD(wParam)) {

              case ID_FILE_EXIT:

                     PostQuitMessage(0);

            break;

              case ID_DRIVER_WRITE:

                     WriteToDriver( );

            break;

              case ID_DRIVER_READ:

                     ReadFromDriver( );

            break;

              case ID_DRIVER_IOCTL:

                     HandleIOCTL( );

            break;

              }           

              break;

              case WM_CREATE:

                     hWndCmdBar=CommandBar_Create(hInst,hWnd,IDC_CMDBAR);

                     CommandBar_InsertMenubar(hWndCmdBar,hInst,IDR_MENU,0);

                     break;

              case WM_PAINT:

                     hdc = BeginPaint(hWnd, &ps);

                     // TODO: Add any drawing code here...

                     RECT rt;

                     GetClientRect(hWnd, &rt);

                     DrawText(hdc, szHello, _tcslen(szHello), &rt, DT_CENTER);

                     EndPaint(hWnd, &ps);

                     break;

              case WM_DESTROY:

                     PostQuitMessage(0);

                     break;

              default:

                     return DefWindowProc(hWnd, message, wParam, lParam);

   }

   return 0;

}

 

4.       上面应用程序的详细步骤没有写,这个不会的话还没法学驱动,只能先去学习Windows程序设计了,主要就是实现几个菜单,然后菜单函数如上述3代码中所示就OK

5.       MyApp.bib文件中内容该为如下(否则操作系统windows目录下看不到MyApp.exe):

FILES

MyApp.exe  $(_FLATRELEASEDIR)/MyApp.exe               NK     U

 

OK,编译应用工程,生成系统镜像。

 

你可能感兴趣的:(thread,windows,function,null,application,dll)