zoukankan      html  css  js  c++  java
  • windows驱动程序wdf--KMDF大致框架 分类: windows驱动程序WDM 2015-01-04 16:18 338人阅读 评论(0) 收藏

    继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... ");

        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 ", GetLastError());
            return 0;
        }

    printf("OK. ");

    CHAR bufInput[1]; // Input to device
    CHAR bufOutput[10]; // Output from device
    ULONG nOutput; // Count written to bufOutput

    printf("请输入数字(0-9) "); 
    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(" %s",bufOutput);
    printf(" ");
    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! ");
            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. ");

            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. ");
            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 ");

            SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
            LocalFree(pDeviceInterfaceDetailData);
            exit(1);
        }

        return pDeviceInterfaceDetailData->DevicePath;

    }


    结果:KMDF大致框架


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    How To Scan QRCode For UWP (4)
    How To Crop Bitmap For UWP
    How To Scan QRCode For UWP (3)
    How To Scan QRCode For UWP (2)
    How To Scan QRCode For UWP (1)
    How to change windows applicatioin's position via Win32 API
    8 Ways to Become a Better Coder
    How to resize or create a thumbnail image from file stream on UWP
    C# winform压缩文件夹带进度条
    MS ACCESS MID函数
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706470.html
Copyright © 2011-2022 走看看