昨天太忙,没来得及写,今天晚上火车要回武汉了,5.1估计没空写,这两天又有不少新发现想要些出来跟大家分享,但是一下子又理不清出头绪,还是不能着急,慢慢写,不要让列位看官越看越糊涂才好。
上一篇咱们写到了USB驱动必须实现的三个入口函数:USBInstallDriver,USBUnInstallDriver和USBDeviceAttach。这一篇就主要介绍一下这几个函数(及另外两个函数:ActivateDevice和USBDeviceNotificationCallback,有时间的话,后来发现没时间写这么长了Attach都写不完,只好下篇再写)。
其实网上搜索到的关于WinceUSB驱动开发的文章都有介绍这些函数,这些函数干什么用的,里面调用了那些东东都有说明,但是似乎天下文章一大抄的原则永远没有改变,每篇文章说的内容都差不多,还有些该说明的细节根本没有一篇提到过,根本就不是给新手入门看的,我想可能学习Wince驱动开发最大的疑惑就是哪些是我们该做的,哪些是不需要我们作的,我在学习的时候,看了这些所谓的入门文章,还是没有完全搞清楚,所以我才专门用一篇的篇幅把我研究所得写出来,可能会对新入门的朋友有所帮助。
先说USBInstallDriver,这个函数在驱动程序DLL被加载的时候会被调用,但是不是任何情况下加载驱动都会调用这个函数入口,前面提到过USB驱动的注册表键值,当系统能够根据注册表定位到驱动程序dll并且成功加载的话,这个函数就不会被调用了。反之,当不能够找到匹配的驱动或者不能够成功加载驱动的时候,系统会弹出一个对话框,让用户输入一个驱动程序名称,这个时候,系统就会加载用户输入的这个驱动程序文件,并调用其中的USBInstallDriver函数了。USBUnInstallDriver函数呢,我很迷惑,《WindowCE驱动开发指南》有一句话说WinCE永远不会调用它,我也不明白,但是就我测试的结果来看,确实没发现这个函数被调用过。
USBInstallDriver函数里面作什么的呢?说白了,就是写注册表,让系统下次能够通过注册表信息匹配到这个驱动程序文件。其他文章都说了,怎么写注册表,就是用USBD.dll中的RegisterClientDriverID和RegisterClientSettings两个函数,少不了LoadLibrary,GetProcAddress,FreeLibrary。网上看到过一个问题,问驱动程序不是被USBD进程加载的么?为什么不能直接用这个两个函数,还要LoadLibrary和GetProcAddress来调用这些函数呢?我不知道怎么去解答这个问题,只觉得即使在一个进程里面,似乎不这样你也得不到这两个函数的地址吧。至于到处都说USBInstallDriver里面不要用Reg的API函数去操作注册表,却没有个所以然,这个应该是因为这些注册表主键可能会根据操作系统的变更而变更的,而不论你是哪个操作系统,RegisterClientDriverID和RegisterClientSettings都会找到对应的正确的注册表主键去添加值,所以建议不要用regAPI来操作,换句话说你用了RegAPI去操作注册表,写入信息,也不会有什么问题,除非你的wince系统中那些驱动信息不应该写在那几个主键下了。
要注意的一点是:在RegisterClientSettings的参数中,给的USB_DRIVER_SETTINGS(内有9个ID)如果和你的设备的ID对不上,结果就是系统仍然不能够通过注册表信息加载你的驱动程序,所以,那个提示你输入驱动程序的对话框还会继续弹出来,但是USBInstallDriver成功返回的话,其中写入注册表的信息是成功写入了的(如果不成功,也会继续弹出那个对话框)。
在USBInstallDriver函数调用完之后,驱动程序dll会被释放掉,然后系统再读取注册表信息去找匹配的驱动来加载,所以才会出现上述情况。因此如果你写入的USB_DRIVER_SETTINGS是和你的设备匹配的,系统就会加载你的驱动,去继续干活了。
这次系统加载会干什么呢?会调用驱动DLL中的USBDeviceAttach入口函数。这个函数的学问就大啦,函数的声明如下:
BOOL USBDeviceAttach(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId,
LPBOOL fAcceptControl,
LPCUSB_DRIVER_SETTINGS lpDriverSettings, DWORD dwUnused)
lpUsbFuncs是usb的一些函数接口,定义在USBDI.H头文件中,大家自己先看看,对照msdn看看。今天只取其中一个函数说一下:lpGetDeviceInfo
在USBDeviceAttach中写这么一行:
LPCUSB_DEVICE lpUsbDev = (lpUsbFuncs->lpGetDeviceInfo)(hDevice);
如果取出的lpUsbDev是NULL的话,那就说明该设备无法使用,咱们也不用继续折腾了,不为空的话,建议大家把这个lpUsbDev指向的那些数据对照msdn搞清楚其含义,这也有助于你理解usb规范中的一些东西。这个结构里面套结构,套的很深很深,而且我看MSDN2005和我的eVc4中的头文件中的定义有些地方有出入,大家自己研究一下,捉摸一下吧,结构就对照自己的头文件中的定义去探索,各成员的含义就对照MSDN去解读,完成了,差不多就进了一大步了。
马上要开会,所以今天就写到这里,大家也可以自己研究研究,然后和我交流,我只觉得一个人在这黑漆八乌地探索实在是......要是有个伴就好了~ :P有个老师就更爽了~~~