最近的一个开发任务中,我的应用程序需要调用驱动程序去做一些事情,考虑到应用的情形,计划使用一个UMDF驱动程序来实现。虽然是一名老程序员了,但对于Windows桌面系统的开发还是头一次做,对于UMDF驱动更是连名字都没有听过。同时时间比较紧,也不可能从头去查帮助,读文档,只能以最快的方式来做。前后共计在这个驱动上花了不到两天的时间,才将UMDF驱动开发的大概流程弄懂,以下做以记录,但愿对于后来者有所帮助。
基本过程
既然为了赶时间,我这里自然不会去分析原理,只能涉及按照这种方法可以快速介入,在自己不熟悉的领域里快速开发。遇到难题还是得仔细阅读帮助文档,或者请教高手。
1, 首先使用VS按照UMDF驱动的向导创建一个新的驱动,创建过程不再细述,按照向导的步骤执行即可。这样我们就有了一个驱动的基本框架。它应该可以编译通过并安装,如果在编译和安装过程中有问题,请先检查VS的开发环境。
2, 添加自己的代码。这样创建的驱动其Read/Write函数是否有,及如何调用我还真没有明白,我只知道IoControl函数,及添加相应的代码。
在ioQueue.cpp中的找到CMyIoQueue::OnDeviceIoControl函数,它就是上层调用DeviceoControl时,会调用到驱动的函数,即驱动的IoControl入口。这个函数有5个参数:
__in IWDFIoRequest *FxRequest,我们可以访问的数据结构都在它里面。
__in ULONG ControlCode,是控制码,我们应该根据不同的控制码去执行对应的代码。
其它的参数都没有用。
分别得到输出和输出Buffer:
FxRequest->GetInputMemory( &pInMem );
FxRequest->GetOutputMemory( &pOutMem );
将输入Buffer拷贝到本地的一段内存中,我们不能直接访问 pInMem指向的内存,只能将其拷出来使用(是不是能读不记得了,谁有兴趣可以试一下)
hr=pInMem->CopyToBuffer(0x0, &localBuffer, dwSize );
本地做完处理以后,将要传出去的数据拷贝到pOutMem.
hr=pOutMem->CopyFromBuffer(0x0, &localOut, sizeof(localOut));
最后通知调用者给它传出了多少数据:
FxRequest->CompleteWithInformation( hr, sizeof(localOut));
3, 注意事项
1, 要传出数据一定要使用OutMemory,当然写这点文字时我用的是VS11 Beta,以后的版本是否会有改变,还需要留意,这个花了我挺长时间,一开始,我一直想把数据用InoutMemory传回,但上层总得不到。后来想到可能它就设计成了不能通过InputMemory传数据出去。
2, Complete是一定要调的,有两个函数,Complete和CompleteWithInformation,前者只是表示驱动中的过程已经做完,后者可以同时给出我们在OutMemory中放了多少字节的数据。如果不调用这个函数,上层调用DeviceIoControl时,就会失败,GetLastError会说是操作被Pending。
3, 因微软的例子中没有给出IO操作的代码,我当时来网上到处搜别人写的例子。当时看到有人会将FxRequest Release,如果将它Release,就会引起驱动程序出错,而不能再使用。由此我想到:1,不能轻易相信别人的代码,尤其是网页上(包括我的,哈哈)。2,一定要时刻注意自己加入新的代码以后程序有什么样的新的行为,一定要及时发现异常,以及时介定是哪次加入的代码有问题,这样才会少浪费时间。
4, 关于运行权限的一些概念:
每个UMDF驱动都有一个专门的进程来加载它(程序名忘记了),其运行权限是Local Service。所以有些需要更高运行权限(如Admin)的函数无法在UMDF驱动中使用。