继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. Apache 配置SSI速记

    1. 启用模块 httpd.conf LoadModule filter_module modules/mod_filter.so 2. <Directory 的Options配置中增加Incl ...

  2. CentOS 6.3 SSH连接时很慢的解决方法

    SSH的配置文件,默认开启了DNS反向解析,这使得处于同一个局域网下的终端,在SSH到服务器的时候异常缓慢,如果从是外网SSH到服务器的话,速度则是正常的.我们只需要关闭DNS反向解析即可. 修改/e ...

  3. Shell与脚本

    shell是Linux操作系统的用户接口,我们经常需要编写脚本让操作系统自动执行一系列指令的需求,本文将简单介绍开发shell脚本的所需的语言特性. shell脚本是指令序列,其指令可以直接在终端中执 ...

  4. vuex学习笔记

    一.vuex的目的 把组件的共享状态抽取出来,以一个全局单例模式管理.在这种模式下,组件树构成了一个巨大的视图,不管在树的哪个位置,任何组件都能获取状态或触发行为. 二.vuex集中式管理数据 安装 ...

  5. DNA序列局部比对(Smith–Waterman algorithm)

    生物信息原理作业第三弹:DNA序列局部比对,利用Smith–Waterman算法,python3.6代码实现. 实例以及原理均来自https://en.wikipedia.org/wiki/Smith ...

  6. 在.NetCore中使用Myrmec检测文件真实格式

    Myrmec 是什么? Myrmec 是一个用于检测文件格式的库,Myrmec不同于其它库或者手写检测代码,Myrmec不依赖文件扩展名(在实际使用中,你的用户很可能使用虚假的扩展名欺骗你的应用程序) ...

  7. Composer 结合 Git 创建 “服务类库”

    Composer 结合 Git 创建 "服务类库" 我一直认为,现在的 PHP 已经进展到了工程化的领域.以前的 PHP 开发者,以快为美,速度和规模永远都是矛盾体.现在的 PHP ...

  8. System.in实现数据的键盘输入

    System.in The "standard" input stream. This stream is already open and ready to supply inp ...

  9. 开启Nginx的目录文件列表功能

    ngx_http_autoindex_module  此模块用于自动生成目录列表,ngx_http_autoindex_module只在 ngx_http_index_module模块未找到索引文件时 ...

  10. Docker MySQL备份

    建立备份的MySQL容器 docker run --name mysql-back -e MYSQL_ROOT_PASSWORD=root -v /srv/mysql/backup:/mysql/ba ...