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

继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设备添加例程

NTSTATUS

CharSample_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例程

VOID

CharSample_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

// #endif

if ((n>=‘0‘) && (n<=‘9‘))

{ //若为数字,则处理

n-=‘0‘; //n=数字(0-9)

len=strlen(szEngNum[n])+1;

//获取输出缓冲区地址buffer

status = WdfRequestRetrieveOutputBuffer(Request, (size_t)len, &buffer, NULL);

if (!NT_SUCCESS(status)) {

WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);

break;

}

//这里buffer表示输出缓冲区地址

//输出:E文数组szEngNum[]中取出对应的数字的中文码,拷贝到输出缓冲区

strncpy((PCHAR)buffer,szEngNum[n],len);

//完成I/O请求,驱动程序传给应用程序的数据长度为len

WdfRequestCompleteWithInformation(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"

PCHAR

GetDevicePath(

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 device

CHAR bufOutput[10]; // Output from device

ULONG 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 driver

if (!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获取设备路径

PCHAR

GetDevicePath(

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;

}

结果:

时间: 2024-10-28 20:43:14

windows驱动程序wdf--KMDF大致框架的相关文章

PCI/PCIe接口卡Windows驱动程序(1)-WDF概述及开发环境搭建

本科毕业设计是这方面的工作,所以想开几篇博客来介绍使用WDF开发PCI/PCIe接口卡的驱动程序方法. 这个系列的博客将首先用一个篇幅为不懂Windows 下PCI/PCIe驱动开发的介绍WDF和开发环境搭建,接下来几篇将直接讲述程序编写, 看完这几篇后,希望能够帮助读者了解如何通过500行左右的代码实现一个标准的PCIe接口卡驱动程序. 毕设题目的PCIe板卡是BAR0下映射两个5K的内存,偏移地址为0x20000和0x22000,源代码在: https://github.com/luluji

PCI/PCIe接口卡Windows驱动程序(2)-开发者需要了解的WDF中的一些重要的概念

本科毕业设计是这方面的工作,所以想开几篇博客来介绍使用WDF开发PCI/PCIe接口卡的驱动程序方法. 在上一篇简要介绍了WDF和开发环境搭建后,本篇将讲述几个WDF中的概念,对开发者了解WDF非常有帮助,属于“内功部分”: 本篇文章结构将没那么清晰,当句句都是作者通过看书.看论文.看MSDN提炼出来的,希望对读者能够有所帮助. 1.WinDBG是唯一的内核驱动调试利器,但是开发PCIe的WDF驱动可以采用“黑盒”方式,所以windbg不是必须的: 2.WDF比WDM好,别再用WDM了: 3.驱

PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)

本篇文章将对PCIe驱动程序的源文件代码作详细解释与说明.整个WDF驱动程序工程共包含4个头文件(已经在上篇文章中讲解)和3个.c文件(Driver.c  Device.c   Queue.c) Driver.c 在看复杂的代码前,先给出程序流程图 1 #include "driver.h" 2 #include "driver.tmh" 3 4 #ifdef ALLOC_PRAGMA 5 #pragma alloc_text (INIT, DriverEntry)

Windows 驱动程序工具包中的头文件

MSDN原文:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff554695(v=vs.85).aspx Windows 驱动程序工具包 (WDK) 包含构建内核模式和用户模式驱动程序所需的所有头文件(.h 文件).头文件在 WDK 安装文件夹中的 Include 文件夹中.示例:C:\Program Files (x86)\Windows Kits\10\Include. 头文件包含版本信息,因此不论驱动程序在哪个版本的 W

用于所有Windows驱动程序开发者的概念

用户模式和内核模式 虚拟地址空间 设备节点和设备堆栈 I/O 请求数据包 驱动程序堆栈 微型驱动程序和驱动程序对 Windows 驱动程序工具包中的头文件 为不同版本的 Windows 编写驱动程序

Windows驱动程序开发基础(四)驱动的编译调试和安装

Windows驱动程序开发基础,转载标明出处:http://blog.csdn.net/ikerpeng/article/details/38793995 下面说一下开发出来驱动程序以后如何编译.一般有以下几种方式: 1. 建立Makefile文件,用nmake工具进行编译和链接: 2. 建立Makefile,sources, dirs文件,用build工具编译. 3. 用集成开发环境进行编译链接. 我采用的是第三种方式,通过VS2010+wdk配置Windows驱动程序开发环境.地址:   h

Windows驱动程序基础(三)Windows系统基础

Windows驱动程序基础系列,转载请标明出处:http://blog.csdn.net/ikerpeng/article/details/38778375 Windows运行模式:用户模式和内核模式 Windows从总体上来说分为:内核模式和用户模式,Intel的i386系列CPU逻辑概念上有4个特权层:Ring0(特权最高),Ring1,Ring2,Ring3. 内核模式则运行在Ring0上面,用户模式就运行在Ring3上. 运行在内核模式下面的Windows组件是安全的(驱动程序就是运行在

(转)windows下安装nodejs及框架express

转自:http://jingyan.baidu.com/article/456c463b60fb380a583144a9.html windows下安装nodejs及框架express nodejs从诞生至今一直被热捧,笔者最近也装了个node环境打算了解一下.安装步骤简单比较简单,所以在这里不会详细讲解每一步,只把安装过程中的问题解决了. 工具/原料 nodejs 框架express 方法/步骤 从node官网下载安装文件,官网地址:http://nodejs.org/   这个安装程序也很常

Windows环境搭建Web自动化测试框架Watir(基于Ruby) 第1章

一.前言     Web自动化测试一直是一个比较迫切的问题,对于现在web开发的敏捷开发,却没有相对应的敏捷测试,故开此主题,一边研究,一边将Web自动化测试应用于工作中,进而形成能够独立成章的博文,希望能够为国内web自动化测试的发展做一点绵薄的贡献吧,笑~ 二.Watir搭建流程 图1-1 需要安装的工具     下载地址:http://railsinstaller.org/     因为安装Ruby还需要用到其他的一些开发工具集,所以建议从网站http://railsinstaller.o

Windows环境搭建Web自动化测试框架Watir(基于Ruby)

web自动化测试一直是一个比较迫切的问题 图1-1 需要安装的工具 http://railsinstaller.org/ 因为安装Ruby还需要用到其他的一些开发工具集,所以建议从网站http://railsinstaller.org/ 下载,而且使用该安装包的话,它会帮你把环境变量也设置完毕,我使用的版本是:railsinstaller-2.2.4.exe,建议下载最新版本. 开始安装RailsInstaller工具包,安装到默认位置即可. 这个对勾建议打上,它会帮你配置git和ssh,安装过