Uso de interfaces de dispositivo (WDF)

Una interfaz de dispositivo es un vínculo simbólico a un dispositivo Plug and Play (PnP) que una aplicación puede usar para acceder al dispositivo. Una aplicación en modo de usuario puede pasar el nombre del vínculo simbólico de la interfaz a un elemento de API, como la función CreateFile de Microsoft Win32. Para obtener el nombre del vínculo simbólico de una interfaz de dispositivo, la aplicación en modo de usuario puede llamar a funciones de Configuration Manager o a funciones SetupApi. Para obtener más información, consulte Enumeración de interfaces de dispositivo instaladas.

Cada interfaz de dispositivo pertenece a una clase de interfaz de dispositivo. Por ejemplo, una pila de controladores para un dispositivo CD-ROM puede proporcionar una interfaz que pertenezca a la clase GUID_DEVINTERFACE_CDROM. Uno de los controladores del dispositivo CD-ROM registraría una instancia de la clase GUID_DEVINTERFACE_CDROM para informar al sistema y las aplicaciones de que un dispositivo CD-ROM está disponible. Para obtener más información sobre las clases de interfaz de dispositivo, vea Información general sobre las clases de interfaz de dispositivo.

Registro de una interfaz de dispositivo

Para registrar una instancia de una clase de interfaz de dispositivo, un controlador basado en marco puede llamar a WdfDeviceCreateDeviceInterface antes o después de que se inicie el dispositivo. Si el controlador admite varias instancias de la interfaz, puede asignar una cadena de referencia única a cada instancia.

Una vez que el controlador ha registrado una interfaz de dispositivo, el controlador puede llamar a WdfDeviceRetrieveDeviceInterfaceString para obtener el nombre de vínculo simbólico que el sistema ha asignado a la interfaz del dispositivo.

Para obtener información sobre otras formas en que los controladores pueden registrar interfaces de dispositivo, consulte Registro de una clase de interfaz de dispositivo.

Habilitar y deshabilitar una interfaz de dispositivo

Las interfaces creadas antes de que se inicie el dispositivo (por ejemplo, desde EvtDriverDeviceAdd, EvtChildListCreateDevice o EvtDevicePrepareHardware) se habilitan automáticamente en el marco cuando el dispositivo pasa por la enumeración PnP y se inicia. Para evitar que la interfaz se habilite automáticamente durante el inicio de PnP, llame a WdfDeviceSetDeviceInterfaceStateEx desde la misma función de devolución de llamada (establezca el parámetro EnableInterface en FALSE) para esa interfaz antes de iniciar PnP.

Las interfaces creadas después de que el dispositivo ya se inicie no se habilitarán automáticamente. El controlador debe llamar a WdfDeviceSetDeviceInterfaceState o WdfDeviceSetDeviceInterfaceStateEx para habilitar estas interfaces.

Todas las interfaces se deshabilitan automáticamente cuando el dispositivo se somete a la eliminación de PnP. Tenga en cuenta que los cambios de estado de energía del dispositivo o el reequilibrio de recursos PnP no cambian el estado de la interfaz.

Un controlador puede deshabilitar y volver a habilitar una interfaz de dispositivo si es necesario. Por ejemplo, si un controlador determina que su dispositivo ha dejado de responder, el controlador puede llamar a WdfDeviceSetDeviceInterfaceState o WdfDeviceSetDeviceInterfaceStateEx para deshabilitar las interfaces del dispositivo y prohibir que las aplicaciones obtengan nuevos identificadores a la interfaz. (Los identificadores existentes de la interfaz no se ven afectados). Si el dispositivo está disponible más adelante, el controlador puede llamar a WdfDeviceSetDeviceInterfaceState o WdfDeviceSetDeviceInterfaceStateEx de nuevo para volver a habilitar las interfaces.

Recepción de solicitudes para acceder a una interfaz de dispositivo

Cuando una aplicación o un componente en modo kernel solicitan acceso a la interfaz de dispositivo de un controlador, el marco llama a la función de devolución de llamada EvtDeviceFileCreate del controlador. El controlador puede llamar a WdfFileObjectGetFileName para obtener el nombre del dispositivo o archivo al que accede la aplicación o el componente en modo kernel. Si el controlador especificó una cadena de referencia cuando registró la interfaz del dispositivo, el sistema operativo incluye la cadena de referencia en el nombre de archivo o dispositivo que WdfFileObjectGetFileName devuelve.

Acceso a la interfaz de dispositivo de otro controlador

En esta sección se muestra cómo un controlador de Kernel-Mode Driver Framework (KMDF) o un controlador de User-Mode Driver Framework (UMDF) versión 2 se registra para la notificación de la llegada o eliminación de una interfaz de dispositivo proporcionada por otro controlador y, a continuación, crea un destino de E/S remoto para comunicarse con el dispositivo representado por la interfaz del dispositivo.

Para obtener información sobre cómo hacerlo en un controlador de la versión 1 de UMDF, consulte Uso de interfaces de dispositivo en controladores UMDF.

Para registrarse para recibir notificaciones de eventos de interfaz de dispositivo, un controlador KMDF llama a IoRegisterPlugPlayNotification, mientras que un controlador UMDF 2 llama a CM_Register_Notification. En ambos casos, el controlador llama a la rutina adecuada desde su función de devolución de llamada EvtDriverDeviceAdd .

En el ejemplo de código siguiente se muestra cómo se registra un controlador UMDF 2 local para las notificaciones y, a continuación, se abre el destino de E/S remoto.

  1. El controlador remoto se registra para una interfaz de dispositivo mediante una llamada a WdfDeviceCreateDeviceInterface desde EvtDriverDeviceAdd.

        UNICODE_STRING ref;
        RtlInitUnicodeString(&ref, MY_HID_FILTER_REFERENCE_STRING);
        status = WdfDeviceCreateDeviceInterface(
                     hDevice,
                     (LPGUID) &GUID_DEVINTERFACE_MY_HIDFILTER_DRIVER,
                     &ref // ReferenceString
                 );
    
        if (!NT_SUCCESS (status)) {
            MyKdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status));
            return status;
        }
    
    
  2. El controlador local llama a CM_Register_Notification desde EvtDriverDeviceAdd para registrarse para recibir notificaciones cuando hay disponible una interfaz de dispositivo. Proporcione un puntero a una rutina de devolución de llamada de notificación a la que el marco llama cuando las interfaces de dispositivo están disponibles.

    DWORD cmRet;
        CM_NOTIFY_FILTER cmFilter;
    
        ZeroMemory(&cmFilter, sizeof(cmFilter));
        cmFilter.cbSize = sizeof(cmFilter);
        cmFilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
        cmFilter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_MY_HIDFILTER_DRIVER;
    
        cmRet = CM_Register_Notification(
                    &cmFilter,                     // PCM_NOTIFY_FILTER pFilter,
                    (PVOID) hDevice,               // PVOID pContext,
                    MyCmInterfaceNotification,    // PCM_NOTIFY_CALLBACK pCallback,
                    &fdoData->CmNotificationHandle // PHCMNOTIFICATION pNotifyContext
                    );
        if (cmRet != CR_SUCCESS) {
            MyKdPrint( ("CM_Register_Notification failed, error %d\n", cmRet));
            status = STATUS_UNSUCCESSFUL;
            return status;
        }   
    
  3. El sistema llama a la rutina de devolución de llamada de notificación del controlador local cada vez que llega o se quita la interfaz de dispositivo especificada. La rutina de devolución de llamada puede examinar el parámetro EventData para determinar qué interfaz de dispositivo ha llegado. Después, podría poner en cola un elemento de trabajo para abrir la interfaz del dispositivo.

    DWORD 
    MyCmInterfaceNotification(
        _In_ HCMNOTIFICATION       hNotify,
        _In_opt_ PVOID             Context,
        _In_ CM_NOTIFY_ACTION      Action,
        _In_reads_bytes_(EventDataSize) PCM_NOTIFY_EVENT_DATA EventData,
        _In_ DWORD                 EventDataSize
        )
    {
        PFDO_DATA fdoData;
        UNICODE_STRING name;
        WDFDEVICE device;
        NTSTATUS status;
        WDFWORKITEM workitem;
    
        UNREFERENCED_PARAMETER(hNotify);
        UNREFERENCED_PARAMETER(EventDataSize);
    
        device = (WDFDEVICE) Context;
        fdoData = ToasterFdoGetData(device);
    
        switch(Action) {
        case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL: 
            MyKdPrint( ("MyCmInterfaceNotification: Arrival of %S\n",
                EventData->u.DeviceInterface.SymbolicLink));
    
            //
            // Enqueue a work item to open target
            //
    
            break;
        case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL: 
            MyKdPrint( ("MyCmInterfaceNotification: removal of %S\n",
                EventData->u.DeviceInterface.SymbolicLink));
            break;
        default:
            MyKdPrint( ("MyCmInterfaceNotification: Arrival unknown action\n"));
            break;
        }
    
        return 0;
    }
    
  4. Desde la función de devolución de llamada del elemento de trabajo, el controlador local llama a WdfIoTargetCreate para crear el destino remoto y WdfIoTargetOpen para abrir un destino de E/S remoto.

    Al llamar a WdfIoTargetOpen, el controlador registra opcionalmente una función de devolución de llamada EvtIoTargetQueryRemove para recibir una notificación de eliminación, junto con la oportunidad de rechazar la eliminación. Si el controlador no proporciona EvtIoTargetQueryRemove, el marco cierra el destino de E/S cuando se quita el dispositivo.

    En raras ocasiones, un controlador UMDF 2 puede llamar a CM_Register_Notification segunda vez, para registrarse para la notificación de eliminación de dispositivos. Por ejemplo, si el controlador llama a CreateFile para obtener un IDENTIFICADOR a la interfaz del dispositivo, debe registrarse para la notificación de eliminación de dispositivos para que pueda responder correctamente a los intentos de eliminación de consultas. En la mayoría de los casos, el controlador UMDF 2 llama a CM_Register_Notification solo una vez y se basa en la compatibilidad con WDF para la eliminación de dispositivos.

    VOID 
    EvtWorkItem(
        _In_ WDFWORKITEM WorkItem
    )
    {
        // 
        // create and open remote target
        //
    
        return;
    }
    

Registro para la notificación de la llegada de la interfaz de dispositivo y la eliminación de dispositivos