我试图IoCreateDevice建个专门用于控制的设备,可是驱动总是在卸载的时候死机。哪位大侠有过这方面的经验?谢谢

解决方案 »

  1.   

    if( MinorFunction==IRP_MN_REMOVE_DEVICE)
        {
            //取消设备接口:
            IoSetDeviceInterfaceState(&dx->ifSymLinkName, FALSE);
            RtlFreeUnicodeString(&dx->ifSymLinkName);
            
            //调用IoDetachDevice()把fdo从设备栈中脱开:
            if (dx->NextStackDevice)
                IoDetachDevice(dx->NextStackDevice);
            //删除fdo:
            IoDeleteDevice(fdo);
        }
    http://laoluoc.yeah.net
      

  2.   

    转贴一份怎样在驱动层和应用层建立准消息机制
    TigerZD
    驱动程序与应用程序运行与不同的环境又紧密合作,但是应用程序通知驱动程序易(IOCTL等),驱动程序通知应用程序却不易。一般的方法是单纯通过EVENT来进行,但是这种方法有其缺点:
    1、EVENT只有信号态和非信号态两种区别,不能有附带的参数,因此一个EVENT只能对应一种事件,同时很多时候EVENT并不是在信号态,此时就需要应用程序在线程中等待,一旦事件较多那么线程就会较多,不但线程同步困难,程序也不易读写。
    2、Windows 98对EVENT操作没有完全支持,像IoCreateXxxEvent并不被支持,因此要获得应用程序创建的事件句柄并不简单,这样驱动程序的通用性也被破坏了。
    基于以上原因,单纯使用EVENT并不好,那么应该怎么做呢?经过实践,我总结出了一个较好的方法,原理是利用OVERLAPPED的异步调用、同时它又可以带参数的特性。具体做法如下:
    1、在驱动程序的设备扩展中定义一个IRP变量,并在适当时候(调用IoCreateDevice初始化设备扩展后)初始化其为NULL。如
    PIRP UserMessageIrp;
    2、定义一个IOCTL,如:
    #define IOCTL_DRIVER_USERMESSAGE CTL_CODE(FILE_DEVICE_UNKNOWN, \
    0x801,\
    METHOD_BUFFERED, \
    FILE_ANY_ACCESS)
    3、应用程序在启动或要监控驱动程序的状态时发送该IOCTL到驱动程序,注意应用程序在用CreateFile打开设备连接时一定要带FILE_FLAG_OVERLAPPED参数。HANDLE FileIOWaiter = CreateEvent( NULL, TRUE, FALSE, NULL);
    if( FileIOWaiter==NULL)
    return GetLastError();
    OVERLAPPED ol;
    ol.Offset = 0;
    ol.OffsetHigh = 0;
    ol.hEvent = FileIOWaiter;ULONG PnpMessage,nBytes;
    if(!DeviceIoControl(hDevice,//设备句柄
    IOCTL_DRIVER_USERMESSAGE
    NULL,
    0,
    &PnpMessage,
    sizeof(PnpMessage),
    &nBytes,
    &ol))
    {
    if(GetLastError()==ERROR_IO_PENDING)
    {
    while(WaitForSingleObject(FileIOWaiter, 100)==WAIT_TIMEOUT)
    {//驱动程序没有消息传过来,循环等待
    if(bInstanceisExit == TRUE)//应用程序退出标志
    {
    CancelIo(hDevice);//见5
    }
    }
    GetOverlappedResult(hDevice, &ol, &nBytes, FALSE);//
    //驱动程序有消息传过来,见6,得到数据。
    }
    }
    //处理得到的数据,接7。4、驱动程序在接到此IOCTL时如下处理:
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
    switch( ioControlCode)
    {
    ...
    case IOCTL_DRIVER_USERMESSAGE
    ntStatus =
    Irp->IoStatus.Status = STATUS_PENDING;
    Irp->IoStatus.Information = 0;
    IoMarkIrpPending(Irp);
    IoSetCancelRoutine(Irp,DriverUserMessageCancelIrp);//见5
    deviceExtension->UserMessageIrp = Irp;
    return STATUS_PENDING;
    ...
    }5、定义IRP的Cancel例程,这是在应用程序要退出而驱动程序并没有完成该IRP时调用。
    VOID DriverUserMessageCancelIrp( 
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp)
    {
    PDEVICE_EXTENSION deviceExtension;deviceExtension = (PDEVICE_EXTENSION)
    DeviceObject->DeviceExtension;IoReleaseCancelSpinLock(Irp->CancelIrql);// If this is our queued read, then unqueue it
    if( Irp==deviceExtension->UserMessageIrp)
    {
    deviceExtension->UserMessageIrp = NULL;
    }
    // Whatever Irp it is, just cancel it
    Irp->IoStatus.Status = STATUS_CANCELLED;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp,IO_NO_INCREMENT); 
    }
    6、在驱动程序需要通知应用程序时,举个例子,设备拔出时在处理IRP_MN_REMOVE_DEVICE时,在调用IoDetachDevice之前:
    (#define PNP_REMOVE_DEVICE 0 //驱动程序和应用程序共同定义的消息类型)
    ...
    ntStatus = DriverProcessUserMessageIrp(DeviceObject,PNP_REMOVE_DEVICE);
    ...
    //DriverProcessUserPnpIrp的定义如下:
    NTSTATUS
    DriverProcessUserMessageIrp(
    IN PDEVICE_OBJECT DeviceObject,
    ULONG ProcessReason)
    {
    NTSTATUS ntStatus;
    PVOID ioBuffer;
    ULONG outputBufferLength;
    PIO_STACK_LOCATION irpStack;
    PIRP Irp;
    PDEVICE_EXTENSION deviceExtension;deviceExtension = (PDEVICE_EXTENSION)
    DeviceObject->DeviceExtension;Irp = deviceExtension->UserMessageIrp;
    if(Irp == NULL)
    return STATUS_SUCCESS;//这种情况是在设备启动后,应用程序并没有发送
    //过该IRP,设备又要卸载时出现。irpStack = IoGetCurrentIrpStackLocation (Irp);// get pointers and lengths of the caller's (user's) IO buffer
    ioBuffer = Irp->AssociatedIrp.SystemBuffer;
    outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;if(ioBuffer!=NULL && sizeof(ProcessReason)<=outputBufferLength)
    {
    RtlCopyMemory(ioBuffer,
    &ProcessReason,
    sizeof(ProcessReason));
    }
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = sizeof(ProcessReason);IoSetCancelRoutine(Irp,NULL);//取消Cancel例程。
    IoCompleteRequest(Irp,IO_NO_INCREMENT); 
    return STATUS_SUCCESS;
    }
    7、此时应用程序的OVERLAPPED的EVENT会置位,WaitForSingleObject结束等待,应用程序应如此处理:
    switch(PnpMessage)//定义见3,是不是很像Windows消息处理例程?:)
    {
    ...
    case PNP_REMOVE_DEVICE:
    //处理过程就不必写了吧。
    break;
    ...
    }
    至此驱动程序和应用程序就完成了一次消息传递,其余可类似循环。
    以上程序段在98和2000下都经过测试。
    TigerZD .2002.7.11.(完)