几个重要windows驱动函数分析

来源:互联网 发布:php bootstrap 编辑:程序博客网 时间:2024/06/05 04:39
1.  AFX_MANAGE_STATE(AfxGetStaticModuleState()) 
 
动态链接到MFC的规则DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。
但是,所有从DLL输出的函数应该以如下语句开始:AFX_MANAGE_STATE(AfxGetStaticModuleState())  
此语句用来正确地切换MFC模块状态。
--------------------------------------------------------------------------------------------------------------------
这是因为操作系统所致:  
在windows操作系统中,在程序中调用资源时需要指定instance handle,对于exe中的代码,
一般是0x400000,但dll中就不是了,所以若需调用dll中的资源,则需用GetModuleHandle,
但这样就无法让MFC自动来处理很多事情,所以AFX_MANAGE_STATE(AfxGetStaticModuleState())
的意思就是把当前dll的相关参数存入MFC的“AfxManger”,当MFC的哪个接口需要相关dll的参数时,
就可以从“AfxManager”中直接提取,所谓的“模块切换”也就是dll参数的切换。
--------------------------------------------------------------------------------------------------------------------
(1)一個exe,dll都是一個執行模块;  
(2)MFC會為每個加載進來的模块,初始化它們自己的狀態,保存在AFX_MODULE_STATE這個數據結構的一個全局變量中;  
(3)當需要使用dialog,icon,string這種資源時,程序就會根據當前的模塊狀態去尋找,加載這些資源;  
(4)所以如果你的導出函數包含使用資源或創建窗口等的代碼是,必須在函數開始處加上宏定義AFX_MANAGE_STATE(AfxGetStaticModuleState());如果沒有,則不加也可以.

2.GUID

(全球唯一标识)是微软使用的一个术语,由一个特定的算法,给某一个实体,如Word文档,创建一个唯一的标识,GUID值就是这个唯一的标识码。GUID广泛应用于微软的产品中,用于识别接口、复制品、记录以及其他对象。不同类型的对象对应不同的GUID值。例如,一个微软Access数据库使用的是16字节域为复制品创建一个唯一标识


3.CTL_CODE 定义说明 

DDK中有一个CTL_CODE宏,用这个宏我们可以很方便的定义IOCTL。

不管是IRP_MJ_DEVICE_CONTROL还是IRP_INTERNAL_DEVICE_CONTROL包,IOCTL都用如下形式定义:

#define IOCTL_Device_Function CTL_CODE(DeviceType, Function,Method, Access)

DeviceType:设备类型,和DEVICE_OBJECT结构中的DeviceType必须一致。注意:0x8000以下的数字被微软占用了。

Function Code:功能代码,可以自定义,用来区分操作类型。注意:0x800以下的数字被微软占用了。

Method:IO缓冲类型,有METHOD_BUFFERED,METHOD_IN_DIRECT,METHOD_OUT_DIRECT,METHOD_NEITHER四种类型。

Access:指明调用者的访问权限,有FILE_ANY_ACCESS,FILE_READ_DATA,FILE_WRITE_DATA三个选项可选。

       FILE_ANY_ACCESS表明用户拥有所有的权限,

       FILE_READ_DATA表明权限为只读,

       FILE_WRITE_DATA表明权限为可写。

       FILE_WRITE_DATA |FILE_READ_DATA表明权限为可读可写,但还没达到FILE_ANY_ACCESS的权限。

IO缓冲的四种类型解释:

METHOD_BUFFERED 表明输入输出都用系统缓冲,这种策略下输入输出指向的是同一个内存块,该内存块有IOManager管理。输入的时候把数据拷贝到缓冲中,然后缓冲再拷贝到驱动;输出的时候数据拷贝到缓冲中,然后缓冲拷贝到用户空间。由于用的是同一块缓冲,所以调用者自己得管理好里面的数据,防止弄混。缓冲区地址存放在IRP.AssociatedIrp.SystemBuffer中,输入数据大小为Parameter.DeviceIoControl.InputBufferLength,输出数据大小为Parameter.DeviceIoControl.OutputBufferLength,两者都在IO_STACK_LOCATION结构中。

METHOD_IN_DIRECT表明输出用缓冲,输入用直接IO。这种策略下输出和上面的方法一致,而输入则是直接访问指定的内存区域,不通过缓冲。IOManager先把输入数据的内存块锁定,然后把地址存放在IRP.MdlAddress中。输入输出数据块的大小和上面一致。

METHOD_OUT_DIRECT 表明输入用缓冲,输出直接IO。IOManager把输出数据的内存快锁定,存放在IRP.MdlAddress中,驱动直接通过该地址访问数据,输入数据通过系统缓冲,存放在IRP.AssociatedIrp.SystemBuffer中。输入输出数据块的大小和上面一致。

METHOD_NEITHER 表明输入输出都不用缓冲,I/OManager把调用者的输入缓冲区的地址放到IRP当前I/O堆栈单元的Parameters.DeviceIoControl.TypeInputBuffer域中,把输出缓冲区的地址存放到IRP的UserBuffer域中。这两个地址都是用户空间地 址。

从上面的说明可以看出,在执行缓冲I/O时,I/O管理器将在非份页池中分配内存,如果调用者的缓冲区比较大时,分配的非份页池也将比较大。非份页池是系统比较宝贵的资源,因此,如果调用者的缓冲区比较大时,我们一般采用直接I/O的方式(例如磁盘读写请求等),这样不仅节省系统资源,另一方面由于省去了I/O管理器在系统缓冲 区和调用者缓冲区之间的数据拷贝,也提高了效率,这对存在大量数据传送的驱动程序尤其明显。不过需要注意的是,直接io要求驱动和IOCTL的发起者运行在同一个线程里。

用户定义IOCTL时要注意以下几条原则:

1. FunctionCode总是定义成0x800以上的数字,因为0x800以下的数字被微软占用了。

2. 仔细考虑访问权限,如果指定了你不具备的权限,那么IO Manager会忽略IOCTL

3. 仔细考虑要访问的内存区域,如果去读写一个关键内存,那么系统会重启

驱动内部执行IOCTL时要注意以下几条原则:

1. 接收到IOCTL时,要先检查整个32比特的数据完整性

2. 用IoValidateDeviceIoControlAccess检查访问权限是否有效

3.严格遵照Parameter.DeviceIoControl.InputBufferLength和Parameter.DeviceIoControl.OutputBufferLength指定的大小访问输入输出区域,否则系统会重启

4. 驱动中申请一块内存后,总是先用RtlZeroMemory清空区域

5. 直接io策略中,用MmGetSystemAddressForMdlSafe获取相应内存区域时,要判断是否为NULL

6. 直接io中,用ProbeForRead 和ProbeForWrite检查内存是否可以访问。


4

DeviceIoControl

 基本信息:
发送控制代码直接到指定的设备驱动程序,使相应的移动设备以执行相应的操作。
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped);
_Inout_opt_ LPOVERLAPPED lpOverlapped);

说明编辑

对设备执行指定的操作
返回值
Long,非零表示成功,零表示失败。会设置GetLastError
参数表
参数类型及说明
hDevice Long,设备句柄
dwIoControlCode Long,应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs。
lpInBuffer Any,应用程序传递给驱动程序的数据缓冲区地址。
nInBufferSize Long,应用程序传递给驱动程序的数据缓冲区大小,字节数。
lpOutBuffer Any,驱动程序返回给应用程序的数据缓冲区地址。
nOutBufferSize Long,驱动程序返回给应用程序的数据缓冲区大小,字节数。
lpBytesReturned Long,驱动程序实际返回给应用程序的数据字节数地址。
lpOverlapped OVERLAPPED,这个结构用于重叠操作。针对同步操作,请用ByVal As Long传递零值


   


0 0