精华内容
下载资源
问答
  • WDF驱动开发手册

    2017-06-19 16:08:11
    WDF驱动开发手册
  • 我将带领大家学习WDM驱动开发,包括重要的理论与实践。 我们逐步深入,在系列一和二的基础上慢慢推进,开始学习WDF驱动模型,包括面向对象和事件机制、重要的WDF对象,具体章节包括: 1)WDF编程框架:面向对象和...
  • VS2012菜鸟WDF驱动开发系列

    热门讨论 2013-01-26 18:40:20
    基于VS2012的菜鸟WDF驱动开发系列
  • 最近因为工作关系,接触了一下WDF驱动开发。 WDF驱动其实是微软公司提供的一套驱动开发的框架。有了这个框架之后,开发驱动会简单一些。WDF本身是从WDM基础上封装而成的。WDF里面封装了很多对象,如WDFDRIVER等。...

    最近因为工作关系,接触了一下WDF驱动开发。

    WDF驱动其实是微软公司提供的一套驱动开发的框架。有了这个框架之后,开发驱动会简单一些。WDF本身是从WDM基础上封装而成的。WDF里面封装了很多对象,如WDFDRIVER等。如果要学习使用WDF来开发驱动,个人感觉还是需要WDM的一些基础,不然很多东西挺难理解的。

    写了一个简单的WDF驱动(非pnp),基本步骤如下:

    创建framework 驱动对象

    几乎任何一个WDF驱动一开始就要创建一个framework的驱动对象,这个对象是所有其他对象的parent对象。

     

            //初始化WDF_DRIVER_CONFIG
    	WDF_DRIVER_CONFIG_INIT(
    							   &cfg,
    							   NULL //不提供adddevice函数							);
    
    	cfg.DriverInitFlags = WdfDriverInitNonPnpDriver;  //非pnp驱动
    	cfg.DriverPoolTag   = (ULONG)'PEPU';  
    	cfg.EvtDriverUnload = EvtDriverUnload;  //卸载函数
    
    	//
    	//创建一个framework的驱动对象。
    	status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&cfg,&drv);
    	if(!NT_SUCCESS(status))
    	{
    		goto DriverEntry_Complete;
    	}
    
    	KdPrint(("Create wdf driver object successfully\n"));

    这样,一个framework的驱动对象就创建好了。

    创建一个设备(control device)

    1. 要创建一个control device,首先得先分配一块内存

    	//分配一块内存
    	device_init = WdfControlDeviceInitAllocate(drv,&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);  
    	if( device_init == NULL )  
    	{    
    		status = STATUS_INSUFFICIENT_RESOURCES;    
    		goto DriverEntry_Complete;  
    	}

    WdfControlDeviceInitAllocate函数分配了一块内存给结构WDFDEVICE_INIT,这个结构在创建control device的时候会被用到。更多细节看MSDN:http://msdn.microsoft.com/en-us/library/windows/hardware/ff545841(v=vs.85).aspx

    2. 然后给这个设备绑定一个设备名字,注意这个设备名字只能被内核模式下的代码所看到,比如其他的内核驱动,用户模式代码是看不到的。

    就好象是WDM里面的IoCreateDevice函数的第三个参数。

    	//设备名字,如: L"\\Device\\MyWDF_Device",只能被其他的内核驱动看到。
    	RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);  
    
    	//将这个设备名字存入DEVICE_INIT结构中
    	status = WdfDeviceInitAssignName(device_init,&ustring);
    
    	if(!NT_SUCCESS(status))
    	{
    		goto DriverEntry_Complete;
    	}
    
    	KdPrint(("Device name Unicode string: %wZ (this name can only be used by other kernel mode code, like other drivers)\n", &ustring));
    

     

    3. 给设备绑定2个回调。

    	//设置2个回调,FileCreate和FileClose
    	WDF_FILEOBJECT_CONFIG_INIT(&f_cfg,EvtDeviceFileCreate,EvtFileClose,NULL);
    
    	//存入DEVICE_INIT结构中
    	WdfDeviceInitSetFileObjectConfig(device_init,&f_cfg,WDF_NO_OBJECT_ATTRIBUTES);

    这样当用户模式的代码调用CreateFile和CloseHandle的时候,这2个回调会被调用。

     

    4. 初始化设备属性并且创建设备

    这里创建一个control device

    	WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);
    	
    	//创建一个设备. (control device)
    	status = WdfDeviceCreate(&device_init,&object_attribs,&control_device);
    	if(!NT_SUCCESS(status))
    	{
    		KdPrint(("create device failed\n"));
    		goto DriverEntry_Complete;
    	}


    5. 创建一个符号连接

    有了这个符号连接,用户模式代码才能找到这个设备。就好像WDM里面IoCreateSymbolicLink()做的事情。

    	//创建一个符号连接
    	RtlInitUnicodeString(&ustring,MYWDF_LINKNAME);	
    	status = WdfDeviceCreateSymbolicLink(control_device,&ustring);	
    	if( !NT_SUCCESS(status) )  
    	{	
    		KdPrint(("Failed to create Link\n"));	 
    		goto DriverEntry_Complete;  
    	}	
    
    	KdPrint(("Create symbolic link successfully, %wZ (user mode code should use this name, like in CreateFile())\n", &ustring));
    


    6. 完成设备的创建

    	WdfControlFinishInitializing(control_device);


    到这里,一个设备就创建成功了。这是一个control device,有关control device可以查看http://msdn.microsoft.com/en-us/library/windows/hardware/ff545424(v=vs.85).aspx

     

    framework驱动对象的创建和设备对象的创建都发生在DriverEntry()里面。

     

    回调函数的实现

    接下来就是回调函数的实现,这里就写了几行简单的代码。

    static VOID EvtDriverUnload( WDFDRIVER Driver )
    {  
    	KdPrint(("unload driver\n"));
    	KdPrint(("Doesn't need to clean up the devices, since we only have control device here\n"));
    }/* EvtDriverUnload */
    
    VOID EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject )
    {
    	KdPrint(("EvtDeviceFileCreate"));
    
    	WdfRequestComplete(Request, STATUS_SUCCESS);
    }
    
    VOID EvtFileClose( __in  WDFFILEOBJECT FileObject )
    {
    	KdPrint(("EvtFileClose"));
    }

    只有在FileCreate里面写了一行代码直接将irp请求完成。

    这样一个最最简单的WDF驱动就写完了。

    完整代码

    #include <fltKernel.h>
    #include <wdf.h>
    #include <wdfdriver.h>
    #include <wdfrequest.h>
    
    #define MYWDF_KDEVICE L"\\Device\\MyWDF_Device"//设备名称,其他内核模式下的驱动可以使用
    #define MYWDF_LINKNAME L"\\DosDevices\\MyWDF_LINK"//符号连接,这样用户模式下的程序可以使用这个驱动设备。
    
    
    
    //声明回调
    EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
    EVT_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate;
    EVT_WDF_FILE_CLOSE EvtFileClose;
    
    
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject , IN PUNICODE_STRING RegistryPath )
    {  
    	NTSTATUS status;	
    	WDF_OBJECT_ATTRIBUTES object_attribs;
    
    	//驱动对象相关
    	WDF_DRIVER_CONFIG cfg;//驱动的配置
    	WDFDRIVER drv = NULL;//wdf framework 驱动对象
    
    	//设备对象相关
    	PWDFDEVICE_INIT device_init = NULL;
    	UNICODE_STRING ustring;
    	WDF_FILEOBJECT_CONFIG f_cfg;
    	WDFDEVICE control_device;
    	PDEVICE_OBJECT dev = NULL;
    
    	KdPrint(("DriverEntry [start]\n"));
    	
    
    	//初始化WDF_DRIVER_CONFIG
    	WDF_DRIVER_CONFIG_INIT(
    							   &cfg,
    							   NULL //不提供AddDevice函数
    							);
    
    	cfg.DriverInitFlags = WdfDriverInitNonPnpDriver;  //指定非pnp驱动
    	cfg.DriverPoolTag   = (ULONG)'PEPU';  
    	cfg.EvtDriverUnload = EvtDriverUnload;  //指定卸载函数
    
    	//创建一个framework驱动对象,在WDF程序里面,WdfDriverCreate是必须要调用的。
    	//framework驱动对象是其他所有wdf对象的父对象,换句话说framework驱动对象是wdf对象树的顶点,它没有父对象了。
    	status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&cfg,&drv);
    	if(!NT_SUCCESS(status))
    	{
    		goto DriverEntry_Complete;
    	}
    
    	KdPrint(("Create wdf driver object successfully\n"));
    
    
    	//创建一个设备
    
    	//先要分配一块内存WDFDEVICE_INIT,这块内存在创建设备的时候会用到。
    	device_init = WdfControlDeviceInitAllocate(drv,&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);  
    	if( device_init == NULL )  
    	{    
    		status = STATUS_INSUFFICIENT_RESOURCES;    
    		goto DriverEntry_Complete;  
    	}
    
    	//创建设备的名字,内核模式下,名字类似: L"\\Device\\MyWDF_Device"
    	RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);  
    
    	//将设备名字存入device_init中
    	status = WdfDeviceInitAssignName(device_init,&ustring);
    
    	if(!NT_SUCCESS(status))
    	{
    		goto DriverEntry_Complete;
    	}
    
    	KdPrint(("Device name Unicode string: %wZ (this name can only be used by other kernel mode code, like other drivers)\n", &ustring));
    
    	//配置FILEOBJECT配置文件,设置FILECREATE,FILECLOSE回调。
    	WDF_FILEOBJECT_CONFIG_INIT(&f_cfg,EvtDeviceFileCreate,EvtFileClose,NULL);
    
    	//将FILEOBJECT的设置存入device_init中
    	WdfDeviceInitSetFileObjectConfig(device_init,&f_cfg,WDF_NO_OBJECT_ATTRIBUTES);
    
    	//初始化设备属性
    	WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);
    	
    	//根据前面创建的device_init来创建一个设备. (control device)
    	status = WdfDeviceCreate(&device_init,&object_attribs,&control_device);
    	if(!NT_SUCCESS(status))
    	{
    		KdPrint(("create device failed\n"));
    		goto DriverEntry_Complete;
    	}
    
    	//创建符号连接,这样用户模式下的程序可以使用这个驱动。这个是必须的,不然用户模式下的程序不能访问这个设备。
    	RtlInitUnicodeString(&ustring,MYWDF_LINKNAME);	
    	status = WdfDeviceCreateSymbolicLink(control_device,&ustring);	
    	if( !NT_SUCCESS(status) )  
    	{	
    		KdPrint(("Failed to create Link\n"));	 
    		goto DriverEntry_Complete;  
    	}	
    
    	KdPrint(("Create symbolic link successfully, %wZ (user mode code should use this name, like in CreateFile())\n", &ustring));
    
    	WdfControlFinishInitializing(control_device);//创建设备完成。
    
    	/*******************************************
    	到这里,我们就成功创建了一个control device。
    	control device 是不支持png和power的,而且我们也不需要手工是删除。
    	因为framework会帮我们删除,看MSDN
    	
    	If your driver creates control device objects but does not create framework device objects that support PnP and power management, 
    	the driver does not have to delete the control device objects. 
    	
    	In this case, the framework deletes the control device objects after the driver's EvtDriverUnload callback function returns. 
    
    	更多细节看MSDN,如
    	http://msdn.microsoft.com/en-us/library/windows/hardware/ff545424(v=vs.85).aspx
    	*******************************************/
    
    
    	KdPrint(("Create device object successfully\n"));
    
    
    	KdPrint(("DriverEntry succeeds [end]\n"));
    	
    DriverEntry_Complete:
    
    	return status;
    }
    
    
    
    static VOID EvtDriverUnload( WDFDRIVER Driver )
    {  
    	KdPrint(("unload driver\n"));
    	KdPrint(("Doesn't need to clean up the devices, since we only have control device here\n"));
    }/* EvtDriverUnload */
    
    VOID EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject )
    {
    	KdPrint(("EvtDeviceFileCreate"));
    
    	WdfRequestComplete(Request, STATUS_SUCCESS);
    }
    
    VOID EvtFileClose( __in  WDFFILEOBJECT FileObject )
    {
    	KdPrint(("EvtFileClose"));
    }
    

    用DDK编译一下就可以了,顺便贴一下sources里面的内容

    TARGETNAME=mywdf
    TARGETTYPE=DRIVER
    DRIVERTYPE=UNKNOWN
    
    KMDF_VERSION_MAJOR=1
    KMDF_VERSION_MINOR=9
    UMDF_MINOR_VERSION=9
    
    WINDDK=c:\winddk\7600.16385.0
    
    TARGETLIBS= $(DDK_LIB_PATH)\Rtlver.lib \
                $(DDK_LIB_PATH)\Wdmsec.lib
    
    #C_DEFINES=$(C_DEFINES)
    
    INCLUDES=$(WINDDK)\inc\wdf\kmdf\$(KMDF_VERSION_MAJOR)$(KMDF_VERSION_MINOR);..\
    
    SOURCES = \
    	mywdf.c

    这样就得到了一个mywdf.sys,然后安装。一直以来,驱动的安装总是让人那么纠结。一堆的配置inf,好在已经有很多现成的了。网上搜索就可以搜到一堆,这里就不在介绍了。

    安装完驱动后,这个驱动有什么用呢?其实啥用都没有,但是可以写几行代码证实一下。如:

    #include "stdafx.h"
    #include <Windows.h>
    
    #define MYDEVICE L"\\\\.\\MyWDF_LINK"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	HANDLE hDevice = CreateFile(MYDEVICE,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    
    	if (hDevice == INVALID_HANDLE_VALUE)
    	{
    		wprintf(L"Failed to open device %s, err: %x\n", MYDEVICE, GetLastError());
    	}
    	else
    	{
    		wprintf(L"Open device %s successfully\n", MYDEVICE);
    		CloseHandle(hDevice);
    
    		wprintf(L"Closed handle\n");
    	}
    
    	return 0;
    }
    
    

    这是个用户模式代码,运行一下,就会发现

    用debugview看一下驱动的输出,看到了驱动里面的log,这就说明用户模式的代码CreateFile和CloseHandle成功的引起驱动调用2个回调。




     



     

     

     

    展开全文
  • 介绍了复杂的驱动开发工作。阐述了驱动程序开发人员必须了解的硬件和软件体系结构。重点围绕开发两类驱动程序所必须采用的实际开发步骤。
  • WDF里面,大多数对象都支持自定义的数据,比如给设备对象创建一个context。 对象上下文 先自定义一个结构,比如 typedef struct { WDFQUEUE _DefaultQueue; }DEVICE_CONTEXT; 里面放了一个对象WDFQUEUE. 然后给...

    https://blog.csdn.net/zj510/article/details/16987349

    WDF里面,大多数对象都支持自定义的数据,比如给设备对象创建一个context。

    对象上下文

    先自定义一个结构,比如

    typedef struct
    {
        WDFQUEUE _DefaultQueue;
    }DEVICE_CONTEXT;
    里面放了一个对象WDFQUEUE. 然后给设备对象创建一个上下文内存块。在使用之前先要声明一下这个结构,相当于告诉框架,我们需要使用一个context。

    WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT);
    如果不需要context,那么可以这么初始化一个设备属性,WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);

    如果需要context,那么要换个函数,WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&object_attribs, DEVICE_CONTEXT); 这样就会分配一个DEVICE_CONTEXT的内存块,并且将内存块的指针保存到WDF_OBJECT_ATTRIBUTES里面。看一下WDF_OBJECT_ATTRIBUTES的定义:

    typedef struct _WDF_OBJECT_ATTRIBUTES {
      ULONG                          Size;
      PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback;
      PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback;
      WDF_EXECUTION_LEVEL            ExecutionLevel;
      WDF_SYNCHRONIZATION_SCOPE      SynchronizationScope;
      WDFOBJECT                      ParentObject;
      size_t                         ContextSizeOverride;
      PCWDF_OBJECT_CONTEXT_TYPE_INFO ContextTypeInfo;
    } WDF_OBJECT_ATTRIBUTES, *PWDF_OBJECT_ATTRIBUTES;
    最后一个成员ContextTypeInfo就指向分配出来的context内存块。

    可以根据对象来得到这个context:

        dev_ctx = WdfObjectGetTypedContext(control_device, DEVICE_CONTEXT);
        RtlZeroMemory(dev_ctx, sizeof(DEVICE_CONTEXT));
    上面2行代码的意思就是获取设备对象control_device的上下文内存块,并且清零。

     

    IO QUEUE,存放WDFREQUEST的队列

    WDF提供了一个对象WDFREQUEST, WDFREQUEST其实是对WDM里面IRP的一个封装。WDF还提供了另外一个对象也就是WDFQUEUE,这个队列会存放IRP请求。

    我们可以给设备对象control_device创建一个IOQUEUE,比如:(WDFQUEUE存放在了设备对象的上下文里面)

    默认队列不能使用WdfIoQueueDispatchManual,不然创建queue会失败。这个我试过。

        WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&qcfg, WdfIoQueueDispatchParallel);    
        qcfg.PowerManaged = WdfFalse;  //非pnp驱动,也就无需电源管理了.
        qcfg.EvtIoDefault = EvtIoPDPControlDevice; 
     
        //创建一个queue
        status = WdfIoQueueCreate(control_device,&qcfg,WDF_NO_OBJECT_ATTRIBUTES,&dev_ctx->_DefaultQueue);  
        if( !NT_SUCCESS(status) )  
        {     
            KdPrint(("Create IoQueue failed, %x\n", status));
            goto DriverEntry_Complete;    
        }
    注意, 需要在WdfControlFinishInitializing(control_device);之前创建IOQUEUE. 我试过在WdfControlFinishInitializing(control_device);后面创建,会失败。

    在这个例子里面,我们提供了一个EvtIoDefault的回调函数,简单实现一下,就是打印一下WDFREQUEST的type并且完成这个请求。

    static VOID EvtIoPDPControlDevice( WDFQUEUE Queue , WDFREQUEST Request )
    {
        //
        WDF_REQUEST_PARAMETERS Params;  
        WDF_REQUEST_PARAMETERS_INIT(&Params);  
        WdfRequestGetParameters(Request,&Params);
     
        KdPrint(("EvtIoPDPControlDevice, type: %x\n", Params.Type));
        
        WdfRequestComplete(Request, STATUS_SUCCESS);
     
    }
     

    完整代码:

    #include <fltKernel.h>
    #include <wdf.h>
    #include <wdfdriver.h>
    #include <wdfrequest.h>
     
    #define MYWDF_KDEVICE L"\\Device\\MyWDF_Device"//设备名称,其他内核模式下的驱动可以使用
    #define MYWDF_LINKNAME L"\\DosDevices\\MyWDF_LINK"//符号连接,这样用户模式下的程序可以使用这个驱动设备。
     
    typedef struct
    {
        WDFQUEUE _DefaultQueue;
    }DEVICE_CONTEXT;
     
    WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT);
     
     
    //声明回调
    EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
    EVT_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate;
    EVT_WDF_FILE_CLOSE EvtFileClose;
     
    EVT_WDF_IO_QUEUE_IO_DEFAULT EvtIoPDPControlDevice;
     
     
     
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject , IN PUNICODE_STRING RegistryPath )
    {  
        NTSTATUS status;    
        WDF_OBJECT_ATTRIBUTES object_attribs;
     
        //驱动对象相关
        WDF_DRIVER_CONFIG cfg;//驱动的配置
        WDFDRIVER drv = NULL;//wdf framework 驱动对象
     
        //设备对象相关
        PWDFDEVICE_INIT device_init = NULL;
        UNICODE_STRING ustring;
        WDF_FILEOBJECT_CONFIG f_cfg;
        WDFDEVICE control_device;
        PDEVICE_OBJECT dev = NULL;
        DEVICE_CONTEXT* dev_ctx = NULL;
     
        //IO QUEUE相关
        WDF_IO_QUEUE_CONFIG qcfg;
     
        KdPrint(("DriverEntry [start]\n"));
        
     
        //初始化WDF_DRIVER_CONFIG
        WDF_DRIVER_CONFIG_INIT(
                                   &cfg,
                                   NULL //不提供AddDevice函数
                                );
     
        cfg.DriverInitFlags = WdfDriverInitNonPnpDriver;  //指定非pnp驱动
        cfg.DriverPoolTag   = (ULONG)'PEPU';  
        cfg.EvtDriverUnload = EvtDriverUnload;  //指定卸载函数
     
        //创建一个framework驱动对象,在WDF程序里面,WdfDriverCreate是必须要调用的。
        //framework驱动对象是其他所有wdf对象的父对象,换句话说framework驱动对象是wdf对象树的顶点,它没有父对象了。
        status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&cfg,&drv);
        if(!NT_SUCCESS(status))
        {
            goto DriverEntry_Complete;
        }
     
        KdPrint(("Create wdf driver object successfully\n"));
     
     
        //创建一个设备
     
        //先要分配一块内存WDFDEVICE_INIT,这块内存在创建设备的时候会用到。
        device_init = WdfControlDeviceInitAllocate(drv,&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);  
        if( device_init == NULL )  
        {    
            status = STATUS_INSUFFICIENT_RESOURCES;    
            goto DriverEntry_Complete;  
        }
     
        //创建设备的名字,内核模式下,名字类似: L"\\Device\\MyWDF_Device"
        RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);  
     
        //将设备名字存入device_init中
        status = WdfDeviceInitAssignName(device_init,&ustring);
     
        if(!NT_SUCCESS(status))
        {
            goto DriverEntry_Complete;
        }
     
        KdPrint(("Device name Unicode string: %wZ (this name can only be used by other kernel mode code, like other drivers)\n", &ustring));
     
        //配置FILEOBJECT配置文件,设置FILECREATE,FILECLOSE回调。
        WDF_FILEOBJECT_CONFIG_INIT(&f_cfg,EvtDeviceFileCreate,EvtFileClose,NULL);
     
        //将FILEOBJECT的设置存入device_init中
        WdfDeviceInitSetFileObjectConfig(device_init,&f_cfg,WDF_NO_OBJECT_ATTRIBUTES);
     
        //初始化设备属性
    //    WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);
     
        //在设备属性里面增加一个DEVICE_CONTEXT,跟WDF_OBJECT_ATTRIBUTES_INIT相比,WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE
        //会分配一块内存并且存入WDF_OBJECT_ATTRIBUTES里面 (object_attribs.ContextTypeInfo)。DEVICE_CONEXT是个自定义结构。
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&object_attribs, DEVICE_CONTEXT);
     
        
        //根据前面创建的device_init来创建一个设备. (control device)
        status = WdfDeviceCreate(&device_init,&object_attribs,&control_device);
        if(!NT_SUCCESS(status))
        {
            KdPrint(("create device failed\n"));
            goto DriverEntry_Complete;
        }
     
        //得到设备的上下文
        dev_ctx = WdfObjectGetTypedContext(control_device, DEVICE_CONTEXT);
        RtlZeroMemory(dev_ctx, sizeof(DEVICE_CONTEXT));
        
        //创建IO queue
     
        //初始化IO QUEUE CONFIG, WdfIoQueueDispatchParallel意思是
        //The framework presents requests to the driver's request handlers as soon as the requests are available. 
        WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&qcfg, WdfIoQueueDispatchParallel);    
        qcfg.PowerManaged = WdfFalse;  //非pnp驱动,无需电源管理。
        qcfg.EvtIoDefault = EvtIoPDPControlDevice; 
     
        //给设备control_device创建IO QUEUE
        status = WdfIoQueueCreate(control_device,&qcfg,WDF_NO_OBJECT_ATTRIBUTES,&dev_ctx->_DefaultQueue);  
        if( !NT_SUCCESS(status) )  
        {     
            KdPrint(("Create IoQueue failed, %x\n", status));
            goto DriverEntry_Complete;    
        }
            
     
        //创建符号连接,这样用户模式下的程序可以使用这个驱动。这个是必须的,不然用户模式下的程序不能访问这个设备。
        RtlInitUnicodeString(&ustring,MYWDF_LINKNAME);    
        status = WdfDeviceCreateSymbolicLink(control_device,&ustring);    
        if( !NT_SUCCESS(status) )  
        {    
            KdPrint(("Failed to create Link\n"));     
            goto DriverEntry_Complete;  
        }    
     
        KdPrint(("Create symbolic link successfully, %wZ (user mode code should use this name, like in CreateFile())\n", &ustring));
     
        WdfControlFinishInitializing(control_device);//创建设备完成。
     
        /*******************************************
        到这里,我们就成功创建了一个control device。
        control device 是不支持png和power的,而且我们也不需要手工是删除。
        因为framework会帮我们删除,看MSDN
        
        If your driver creates control device objects but does not create framework device objects that support PnP and power management, 
        the driver does not have to delete the control device objects. 
        
        In this case, the framework deletes the control device objects after the driver's EvtDriverUnload callback function returns. 
        更多细节看MSDN,如
        http://msdn.microsoft.com/en-us/library/windows/hardware/ff545424(v=vs.85).aspx
        *******************************************/
     
     
        KdPrint(("Create device object successfully\n"));
     
        
     
     
        KdPrint(("DriverEntry succeeds [end]\n"));
        
    DriverEntry_Complete:
     
        return status;
    }
     
     
     
    static VOID EvtDriverUnload( WDFDRIVER Driver )
    {  
        KdPrint(("unload driver\n"));
        KdPrint(("Doesn't need to clean up the devices, since we only have control device here\n"));
    }/* EvtDriverUnload */
     
    VOID EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject )
    {
        KdPrint(("EvtDeviceFileCreate"));
     
        WdfRequestComplete(Request, STATUS_SUCCESS);
    }
     
    VOID EvtFileClose( __in  WDFFILEOBJECT FileObject )
    {
        KdPrint(("EvtFileClose"));
    }
     
    static VOID EvtIoPDPControlDevice( WDFQUEUE Queue , WDFREQUEST Request )
    {
        //从WDFREQUEST里面获取参数
        WDF_REQUEST_PARAMETERS Params;  
        WDF_REQUEST_PARAMETERS_INIT(&Params);  
        WdfRequestGetParameters(Request,&Params);
     
        KdPrint(("EvtIoPDPControlDevice, type: %x\n", Params.Type));
        
        WdfRequestComplete(Request, STATUS_SUCCESS);
     
    }

    简单调用一下:

    // MyTest.cpp : Defines the entry point for the console application.
    //
     
    #include "stdafx.h"
    #include <Windows.h>
     
    #define MYDEVICE L"\\\\.\\MyWDF_LINK"
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        HANDLE hDevice = CreateFile(MYDEVICE,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
     
        if (hDevice == INVALID_HANDLE_VALUE)
        {
            wprintf(L"Failed to open device %s, err: %x\n", MYDEVICE, GetLastError());
            
        }
        else
        {
            wprintf(L"Open device %s successfully\n", MYDEVICE);
     
            byte buf[10] = {0};
            DWORD dwRet = 0;
            BOOL b = ReadFile(hDevice, buf, 10, &dwRet, NULL);
            wprintf(L"call ReadFile, ret: %d\n", b);
     
            b = WriteFile(hDevice, buf, 10, &dwRet, NULL);
            wprintf(L"call WriteFile, ret: %d\n", b);
     
            CloseHandle(hDevice);
     
            wprintf(L"Closed handle\n");
        }
     
        return 0;
    }
     

    可以看到:


    驱动打印出了2个IO, 一个类型是3,一个是4. 查看一下msdn,3确实是READ, 4是WRITE,正确。也就是说用户模式代码引起了驱动调用2次回调EvtIoPDPControlDevice。这正是我们想要的,没有问题。

    typedef enum _WDF_REQUEST_TYPE { 
      WdfRequestTypeCreate                  = 0x0,
      WdfRequestTypeCreateNamedPipe         = 0x1,
      WdfRequestTypeClose                   = 0x2,
      WdfRequestTypeRead                    = 0x3,
      WdfRequestTypeWrite                   = 0x4,
      WdfRequestTypeQueryInformation        = 0x5,
      WdfRequestTypeSetInformation          = 0x6,
      WdfRequestTypeQueryEA                 = 0x7,
      WdfRequestTypeSetEA                   = 0x8,
      WdfRequestTypeFlushBuffers            = 0x9,
      WdfRequestTypeQueryVolumeInformation  = 0xa,
      WdfRequestTypeSetVolumeInformation    = 0xb,
      WdfRequestTypeDirectoryControl        = 0xc,
      WdfRequestTypeFileSystemControl       = 0xd,
      WdfRequestTypeDeviceControl           = 0xe,
      WdfRequestTypeDeviceControlInternal   = 0xf,
      WdfRequestTypeShutdown                = 0x10,
      WdfRequestTypeLockControl             = 0x11,
      WdfRequestTypeCleanup                 = 0x12,
      WdfRequestTypeCreateMailSlot          = 0x13,
      WdfRequestTypeQuerySecurity           = 0x14,
      WdfRequestTypeSetSecurity             = 0x15,
      WdfRequestTypePower                   = 0x16,
      WdfRequestTypeSystemControl           = 0x17,
      WdfRequestTypeDeviceChange            = 0x18,
      WdfRequestTypeQueryQuota              = 0x19,
      WdfRequestTypeSetQuota                = 0x1A,
      WdfRequestTypePnp                     = 0x1B,
      WdfRequestTypeOther                   = 0x1C,
      WdfRequestTypeUsb                     = 0x40,
      WdfRequestTypeNoFormat                = 0xFF,
      WdfRequestTypeMax                     = 0x100
    } WDF_REQUEST_TYPE;

     

    展开全文
  • 众所周知,自Windows 2000开始,开发驱动程序必以WDM...为改善这种局面,微软推出了新的驱动程序开发环境WDF。要预先指出的是,这不是另起炉灶改弦更张,而是以WDM为基础进行了建模和封装,显著特点是降低了开发难度。
  • 之前没有做过驱动开发,一切从〇开始。陆陆续续看了些书,windows设备驱动程序wdf开发等。但是总是云里雾里的。所以想一点一点的积累下在驱动方面的知识。 首先我将记录下如何搭建调试环境?前提是wmware已装完毕,...

    之前没有做过驱动开发,一切从〇开始。陆陆续续看了些书,windows设备驱动程序wdf开发等。但是总是云里雾里的。所以想一点一点的积累下在驱动方面的知识。

    首先我将记录下如何搭建调试环境?前提是wmware已装完毕,已有两台guest os. (xp 和win7)。下面针对两类系统的调试进行说明。

    驱动开发最好使用vmware虚拟机,好处不多说了。首先针对vmware虚拟机的设置(保证虚拟机是关机状态)

    1. 设置VM与Windbg通信的串口

    打开目标系统的Virtual Machine Setting选项,在Hardware中添加新硬件:1)选择Serial Port2serial Port Type 选择“Output to named pipe”;3Specify Socket的选项如图1吧;4)最终的配置结果如图2所示。然后启动VM的目标系统吧。

    注意事项:一般情况下是串口2:Serial Port 2,原因是默认VM安装虚拟打印机占用Serial Port 1.

    图1 

    图1

    图2

    图2

    2. 设置Guest OS的启动项

    进入WinXP的虚拟机操作系统,打开系统盘(C:\),将文件夹查看选项全开了,那在C盘根目录下有一个叫boot.ini的启动项文件,先去掉只读属性,以文本文件的方式打开,拷贝原来的启动项,作如下修改:

    Multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /debug /debugport=com2 /baudrate=115200

    注意事项:如果步骤1中的serial port选择的是serial port 1是话,此处为com1.如果是serial port 2的话此处为com2.

    3.配置WinDbg的快捷方式

    在winddk的安装目录(C:\WinDDK\7600.16385.0\Debuggers)找到windbg.exe执行程序。在桌面创建快捷方式,并且修改属性如下:

    "C:\WinDDK\7600.16385.0\Debuggers\windbg.exe" -b -k com:port=\\.\pipe\com_1,baud=115200,pipe

    注意事项:host os 使用对应的windbg.exe,原因是windbg.exe有32和64位之分。

    • 针对win7驱动调试的设置
    1. WM和windbg的通信串口设置(同guest os为xp的设置一致)
    2. 设置guest os 启动项
    首先,运行msconfig进入引导tab页,点击高级选项,将调试选上,并且注意调试端口要和通信串口的设置保持一致,重启guest os.
    其次, 方法一:启动guest os后,以管理员权限启动dbgview.exe。
    方法二:如果想调试Kdprint的话可以修改注册表
    [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/Debug Print Filter] DEFAULT=dword:0000000f
    3. 配置windbg的快捷方式(同guest os为xp的设置一致)

    •  单步调试

    1.  加载符号文件

    在windbg上键入:.reload

    键入:ld charsample

    键入:lm l 

    2.  设置断点

    点击菜单“File”-> ”OpenSource File…”, 选择驱动程序目录下的源文件queue.cpp并打开。将光标移动到某指令位置,使用F9设置断点,则该处代码显示为红色,就表示断点已经设置了。

    3. 使用F11可进行单步调试


    转载于:https://www.cnblogs.com/yongqiangyue/archive/2013/04/24/3984781.html

    展开全文
  • 菜鸟WDF驱动开发系列

    2014-08-13 22:04:43
    http://joeyliu.blog.51cto.com/3647812/943368
    http://joeyliu.blog.51cto.com/3647812/943368
    
    展开全文
  • 近期在学习WDF开发,查找到的网络链接将逐步汇集起来,主要是方便自己学习,省的收藏那么多。 《Windows设备驱动程序WDF开发》 ...OEMDLLUNI虚拟打印驱动说明 ...OEMUNI Unidrv Render ...微软统一打印驱动开发资料
  • KMDF属于即插即用驱动程序的驱动模型: 1.一个DriverEntry例程。 2.一个EvtDriverDeviceAdd例程,类似于WDM的AddDevice例程。 3.一个或多个IO队列。 4.一个活多个IO事件回调例程,类似于WDM的Disp...
  • 我在做WDF驱动开发的时候,安装驱动的时候出现 无法加载这个硬件的设备驱动程序。驱动程序可能已损坏或不见了。 (代码 39) INF文件我是按照例子更改的 ;Module Name: ; PCISample.INF ; ;Abstract: ; INF ...
  • win7 vs2012+wdk8.0 搭建wdf驱动开发环境

    千次阅读 2016-07-13 15:08:52
    开发环境搭建: 系统:win7 x64 工具:vs2012 + WDK8.0 插件:wdfcoinstaller.msi (1)先安装vs2012,再安装wdk8.0,这样在打开vs2012时可以创建windows drivers类型的工程。 注:vs2012不能安装wdk8.1,wdk8.1必须...
  • 好吧,我承认我的这个菜鸟系列教程没什么方向性的,因为我毕竟不是什么高手,而且是属于自学范畴,我只能通过不断的自我摸索来找寻属于自己的方向感,不得不承认这...从写应用程序转向写驱动程序,最让人头痛的是IDE的
  • 当用户模式的程序调用驱动的时候,怎么传递数据呢? 通常用户模式程序和驱动的数据交互有3种办法:buffer方式,direct方式和其他...我们考虑给WDF驱动增加一个功能:将WRITE请求的数据写入设备对象上下文,然后当READ请
  • 驱动和调用者进行内存操作的时候,比如驱动读取写入调用者的内存。windows上面总共有3种方法:DO_BUFFERED_IO,DO_DIRECT_IO和其他。 内核模式下操作调用者buffer WDM:各种方式有不同的使用方法,参考...
  • windows wdf 驱动开发总结(1)--usb驱动

    千次阅读 2010-10-07 09:49:00
    (一)EZ-USB-Fx2 USB驱动相关 (1)WDF_IO_QUEUE_CONFIG_INIT_...功能:初始化驱动WDF_IO_QUEUE_CONFIG结构 VOID WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(  __out PWDF_IO_QUEUE_CONFIG Config,  __in WDF_IO
  • win7下写的xp系统的wdf驱动,在使用虚拟机调试的时候,虚拟机上用KMDManager 加载驱动,run的时候,提示“系统找不到指定的文件”。 该虚拟机上的xp系统是刚装完的,很干净,还没有装其他的。 但是在win7 下...
  • windows wdf 驱动开发总结(5)--PCI 驱动

    千次阅读 2010-10-07 10:50:00
    PCI驱动相关(CY7C09449)(AMCC5933)   PCI总线标准是一种将系统外部设备连接起来的总线标准,它是PC中最重要的总线。其它总线ISA总线,USB总线都挂在PCI总线上。 (2.1)WDF_INTERRUPT_CONFIG_INIT 函数功能:...
  • vs2012+wdk8.0 搭建wdf驱动开发环境

    万次阅读 2014-11-22 12:12:35
    开发环境搭建: 系统:win7 x64 工具:vs2012 + WDK8.0 插件:wdfcoinstaller.msi (1)先安装vs2012,再安装wdk8.0,这样在打开vs2012时可以创建windows drivers类型的工程。 注:vs2012不能安装wdk8.1,wdk8.1...
  • 每一位新手在开始学习驱动开发的时候相信总会看大量的资料,如我第一篇提到的几本书的确是不错的,但名著总有一个问题就是,开篇一开始总是会铺陈太多的基本理论,这会让我们觉得手足无措,更不知如何下手。...
  • windows wdf 驱动开发总结(2)--usb驱动

    千次阅读 2010-10-07 09:50:00
    (14) WDF_REQUEST_SEND_OPTIONS_INIT 函数功能:initializes a driver's WDF_REQUEST_SEND_OPTIONS structure VOID  WDF_REQUEST_SEND_OPTIONS_INIT(  OUT PWDF_REQUEST_SEND_OPTIONS Options,
  • Developing Drivers with the Windows Driver Foundation 中文版 自己利用闲暇的时间, 自己翻译的, 后续还有一些资源提供, 多谢支持. 我的淘宝账号:osoon2008 售价:10元 由于工作关系, 无法长时间挂在...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 368
精华内容 147
关键字:

wdf驱动开发