• 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大致框架


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

  • 相关阅读:
    Python3 文件
    Python 字典
    Python OS
    Python函数zip-map
    Python 3.5 filter
    python3.5.2库getpass
    JavaScript学习四
    cocos creator学习
    JavaScript学习三
    JavaScript学习3
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706470.html
Copyright © 2020-2023  润新知