继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;

}


结果:


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

  1. 基于WDF的PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)

    原文出处:http://www.cnblogs.com/jacklu/p/4687325.html 本篇文章将对PCIe驱动程序的源文件代码作详细解释与说明.整个WDF驱动程序工程共包含4个头文件(已 ...

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

    原文出处:http://www.cnblogs.com/jacklu/p/4646601.html 本科毕业设计是这方面的工作,所以想开几篇博客来介绍使用WDF开发PCI/PCIe接口卡的驱动程序方法 ...

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

    原文出处:http://www.cnblogs.com/jacklu/p/4619110.html 本科毕业设计是这方面的工作,所以想开几篇博客来介绍使用WDF开发PCI/PCIe接口卡的驱动程序方法 ...

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

    MSDN原文:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff554695(v=vs.85).aspx Windows 驱动程序 ...

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

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

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

    转自:http://jingyan.baidu.com/article/456c463b60fb380a583144a9.html windows下安装nodejs及框架express nodejs从 ...

  7. Windows环境搭建Web自动化测试框架Watir

    Windows环境搭建Web自动化测试框架Watir 一.前言     Web自动化测试一直是一个比较迫切的问题,对于现在web开发的敏捷开发,却没有相对应的敏捷测试,故开此主题,一边研究,一边将We ...

  8. windows环境下安装yaf框架

    windows环境下安装yaf框架 在windows下安装yaf框架 准备工作: php环境(过程略,wamp,xampp,phpstudy都行,php版本大于5.3) git工具(需要从github ...

  9. 汉澳sinox通过ndis执行windows驱动程序

    汉澳sinox不仅能通过wine执行windows应用程序.还能通过ndis执行windows驱动程序 汉澳sinox使用 Windows NDIS 驱动程序 详细实现方法是用ndisgen把wind ...

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

    Windows驱动程序开发基础,转载标明出处:http://blog.csdn.net/ikerpeng/article/details/38793995 以下说一下开发出来驱动程序以后怎样编译.一般 ...

随机推荐

  1. Go笔记-函数

    [函数定义]         func function_name([parameter1 type,parameter2 type])[return_value1 return_type1,retu ...

  2. 51NOD 1222 最小公倍数计数 [莫比乌斯反演 杜教筛]

    1222 最小公倍数计数 题意:求有多少数对\((a,b):a<b\)满足\(lcm(a,b) \in [1, n]\) \(n \le 10^{11}\) 卡内存! 枚举\(gcd, \fra ...

  3. NOIP2016提高组初赛(C++语言)试题 个人的胡乱分析 Part 2.

    洛谷秋令营day1模拟赛原地爆炸,心态崩了.于是打算写一下初赛题放松一下. 上次胡乱分析到了选择题,这次我想说说后面的题. 问题求解 T1.有一个1x8的方格图形,黑白两色填涂每个方格,两个黑格并不能 ...

  4. EFCore数据库迁移命令整理

    前言  因为现在用.net core 开发新项目,过程中需要经常涉及到数据命令的迁移,今天分别整EFCore 的两种迁移数据库的方式 1 程序包管理器控制台 , Package Manager Con ...

  5. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  6. ubuntu16.04安装ftp服务器

    参考文章: http://www.linuxidc.com/Linux/2017-01/139233.htm 1.检查是否安装vsftpd,如果安装了跳过第二步 vsftpd -v 2.安装vsftp ...

  7. Treap-平衡树学习笔记

    平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...

  8. 【HTTP协议】---HTTPS协议

    HTTPS协议 一.为什么需要https 1.HTTP是明文传输的,也就意味着,介于发送端.接收端中间的任意节点都可以知道你们传输的内容是什么.这些节点可能是路由器.代理等. 举个最常见的例子,用户登 ...

  9. centos/linux下的安装Nginx

    1.安装gcc编译器 先查看gcc编译器是否安装 在shell控制台输入gcc-v 如果没有安装请看下一步 使用yuma安装gcc yum intsall gcc 看到如下视图则说明安装成功 2.安装 ...

  10. Yii2中后台用前台的代码设置验证码显示不出来?

    我说的是直接修改advanced模板.细心人会发现模板里在contact里有,登录也想要就仿照contact中的做法.前台好了,后台登录也要验证码,就把前台代码拿过来,可惜前后台的SiteContro ...