您的位置:首页 > 其它

windows驱动程序wdf--KMDF大致框架

2015-01-04 16:18 288 查看
继WDM后微软出了WDF,封装了WDM中的一些基本代码逻辑。本人菜鸟,也不知道本质上有何区别,只觉得是多了Wdf开头的函数,基本的编程框架上有点出入。
KMDF是WDF的内核级部分,为了理清KMDF的结构,又觉得内核编程很复杂,HelloWorld类型的程序实在说明不了什么 修改一下《windows设备驱动WDF开发》的CharSample,查了WDK帮助文档加上注释以帮助自己理解KMDF的大致运作过程。

CharSample原本是应用层输入数字字符,驱动读取输入缓冲区返还相应的中文,自己修改为返还英文(调试过程出现过数据类型的错误,Char CHAR int INT size_t 注意ANSI C的函数)
另外,KMDF的IO处理例程中Create Close Cleanup要自己处理 Read Write DeviceControl可由IO队列管理,所以自行添加一个Create例程

驱动:

//基本KMDF,全部内容写入同一源文件#pragma warning(disable:4200) //#pragma warning(disable:4201) // nameless struct/union#pragma warning(disable:4214) // bit field types other than int
#include <ntddk.h>#include <wdf.h>#include <initguid.h>
#ifndef DEBUGGING#define DEBUGGING 1#endif
//全局标识符DEFINE_GUID(CharSample_DEVINTERFACE_GUID, \0xbd083159, 0xeb56, 0x437e, 0xbb, 0x98, 0x17, 0x65, 0xe4, 0x40, 0x81, 0xe);
//控制命令#define CharSample_IOCTL_800 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

//全局变量CHAR szEngNum[10][8] ={"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };

//入口函数NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
//CharSample设备添加例程NTSTATUS CharSample_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit);
//DeviceIoControl例程VOID CharSample_EvtIoDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode );

//Create例程(无操作)VOID CharSample_EvtDeviceFileCreate( IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject ); //入口函数NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, //入口参数 IN PUNICODE_STRING RegistryPath) //入口参数{ WDF_DRIVER_CONFIG config; //驱动对象配置结构 NTSTATUS status;//_asm int 3;//对象配置、指定设备添加例程入口WDF_DRIVER_CONFIG_INIT(&config,CharSample_EvtDeviceAdd); //对象配置、指定设备添加例程入口 status = WdfDriverCreate( DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes &config, // Driver Config Info WDF_NO_HANDLE // hDriver );return status;}

//CharSample设备添加例程NTSTATUSCharSample_EvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ){ NTSTATUS status; WDFDEVICE device; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDF_FILEOBJECT_CONFIG fileConfig; //文件配置信息//例程的首句PAGED_CODE,表示该例程的代码占用分页内存。//只能在PASSIVE_LEVEL中断级别调用该例程,否则会蓝屏。//如不说明,则占用系统的非分页内存,要珍惜使用。 PAGED_CODE();
//设置Create例程WDF_FILEOBJECT_CONFIG_INIT( &fileConfig,CharSample_EvtDeviceFileCreate,WDF_NO_EVENT_CALLBACK,WDF_NO_EVENT_CALLBACK ); WdfDeviceInitSetFileObjectConfig(DeviceInit,&fileConfig,WDF_NO_OBJECT_ATTRIBUTES); //创建设备,没有对象属性和设备对象环境变量结构 status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device); if (!NT_SUCCESS(status)) { return status; }
//初始化缺省队列配置,设置I/O请求分发处理方式为串行。//对这个实例而言,选择串行或并行都可以,但不能选手工。 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential);
//设置EvtIoDeviceControl例程,处理应用程序的DeviceIoControl()函数调用 ioQueueConfig.EvtIoDeviceControl = CharSample_EvtIoDeviceControl;
//创建队列 status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, NULL); if (!NT_SUCCESS(status)) { return status; }
//创建设备GUID接口 status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &CharSample_DEVINTERFACE_GUID, NULL); if (!NT_SUCCESS(status)) { }
return status;}

//DeviceIoControl例程VOIDCharSample_EvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ){ NTSTATUS status; PVOID buffer;CHAR n; INT len; PAGED_CODE();
switch(IoControlCode) {
case CharSample_IOCTL_800:if (InputBufferLength == 0 || OutputBufferLength < 2){ //检查输入、输出参数有效性WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);}else{//输入缓冲区地址可通过调用WdfRequestRetrieveInputBuffer函数获得//输出缓冲区地址可通过调用WdfRequestRetrieveOutputBuffer函数获得
//获取输入缓冲区地址buffer//要求1字节空间status = WdfRequestRetrieveInputBuffer(Request, 1, &buffer, NULL);if (!NT_SUCCESS(status)) {WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); break;}
//这里buffer表示输入缓冲区地址//输入n=应用程序传给驱动程序的数字ASCII码n = *(CHAR *)buffer;// #if DEBUGGING // _asm int 3// #endifif ((n>='0') && (n<='9')){ //若为数字,则处理n-='0'; //n=数字(0-9) len=strlen(szEngNum
)+1;//获取输出缓冲区地址bufferstatus = WdfRequestRetrieveOutputBuffer(Request, (size_t)len, &buffer, NULL);if (!NT_SUCCESS(status)) {WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);break;}
//这里buffer表示输出缓冲区地址//输出:E文数组szEngNum[]中取出对应的数字的中文码,拷贝到输出缓冲区strncpy((PCHAR)buffer,szEngNum
,len);
//完成I/O请求,驱动程序传给应用程序的数据长度为lenWdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, len);}else //否则返回无效参数WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);} break;
default : status = STATUS_INVALID_DEVICE_REQUEST;WdfRequestCompleteWithInformation(Request, status, 0); break; }
return;}

//Create例程(无操作)VOID CharSample_EvtDeviceFileCreate( IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject){ NTSTATUS status=STATUS_SUCCESS;WdfRequestComplete(Request,status);}

应用层:// Test_CharSample.cpp : Defines the entry point for the console application.//
#include "stdafx.h"
#include <windows.h>#include <setupapi.h>#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <winioctl.h>
#include "public.h"
PCHARGetDevicePath( IN LPGUID InterfaceGuid );
int main(int argc, char* argv[]){PCHAR DevicePath; HANDLE hDevice = INVALID_HANDLE_VALUE;
printf("Application Test_CharSample starting...\n");
DevicePath = GetDevicePath((LPGUID)&CharSample_DEVINTERFACE_GUID);
hDevice = CreateFile(DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if (hDevice == INVALID_HANDLE_VALUE) {printf("ERROR opening device: (%0x) returned from CreateFile\n", GetLastError()); return 0; }
printf("OK.\n");
CHAR bufInput[1]; // Input to deviceCHAR bufOutput[10]; // Output from deviceULONG nOutput; // Count written to bufOutput
printf("请输入数字(0-9)\n"); l0: bufInput[0] = _getch();if ((bufInput[0]<'0') || (bufInput[0]>'9')) goto l0;_putch(bufInput[0]); // Call device IO Control interface (CharSample_IOCTL_800) in driverif (!DeviceIoControl(hDevice,CharSample_IOCTL_800,bufInput,1,bufOutput,10,&nOutput,NULL) ){printf("ERROR: DeviceIoControl returns %0x.", GetLastError()); goto exit;} printf("\n%s",bufOutput);printf("\n");exit:
if (hDevice != INVALID_HANDLE_VALUE) { CloseHandle(hDevice); }return 0;}

//根据全局ID获取设备路径PCHARGetDevicePath( IN LPGUID InterfaceGuid ){ HDEVINFO HardwareDeviceInfo; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetailData = NULL; ULONG Length, RequiredLength = 0; BOOL bResult;
//获取设备信息设置 HardwareDeviceInfo = SetupDiGetClassDevs( InterfaceGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) { printf("SetupDiGetClassDevs failed!\n"); exit(1); }
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //设备存在 枚举接口 bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo, 0, InterfaceGuid, 0, &DeviceInterfaceData);
if (bResult == FALSE) {
LPVOID lpMsgBuf;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL )) {
printf("Error: %s", (LPSTR)lpMsgBuf); LocalFree(lpMsgBuf); }
printf("SetupDiEnumDeviceInterfaces failed.\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); exit(1); } //获取设备接口的详细信息结构的大小//通过两次调用 SetupDiGetDeviceInterfaceDetail SetupDiGetDeviceInterfaceDetail( HardwareDeviceInfo, &DeviceInterfaceData, NULL, 0, &RequiredLength, NULL ); //详细信息结构初始化 pDeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LMEM_FIXED, RequiredLength);
if (pDeviceInterfaceDetailData == NULL) { SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); printf("Failed to allocate memory.\n"); exit(1); }
pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Length = RequiredLength;
bResult = SetupDiGetDeviceInterfaceDetail( HardwareDeviceInfo, &DeviceInterfaceData, pDeviceInterfaceDetailData,//成功调用此函数后pDeviceInterfaceDetailData指向有效的SP_DEVICE_INTERFACE_DETAIL_DATA Length, &RequiredLength, NULL);
if (bResult == FALSE) {
LPVOID lpMsgBuf;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL )) {
MessageBox(NULL, (LPCTSTR) lpMsgBuf, "Error", MB_OK); LocalFree(lpMsgBuf); }
printf("Error in SetupDiGetDeviceInterfaceDetail\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); LocalFree(pDeviceInterfaceDetailData); exit(1); }
return pDeviceInterfaceDetailData->DevicePath;
}

结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐