Usando interfaces de dispositivo (WDF)

Uma interface do dispositivo é um link simbólico para um dispositivo PnP (Plug and Play) que um aplicativo pode usar para acessar o dispositivo. Um aplicativo no modo de usuário pode passar o nome simbólico do link da interface para um elemento de API, como a função CreateFile do Microsoft Win32. Para obter o nome simbólico do link de uma interface do dispositivo, o aplicativo de modo de usuário pode chamar funções do Configuration Manager ou funções SetupApi. Para obter mais informações, consulte Enumerando interfaces de dispositivo instaladas.

Cada interface do dispositivo pertence a uma classe de interface do dispositivo. Por exemplo, uma pilha de driver para um dispositivo CD-ROM pode fornecer uma interface que pertence à classe GUID_DEVINTERFACE_CDROM. Um dos drivers do dispositivo CD-ROM registraria uma instância da classe GUID_DEVINTERFACE_CDROM para informar ao sistema e aos aplicativos que um dispositivo CD-ROM está disponível. Para obter mais informações sobre classes de interface do dispositivo, consulte Visão geral das classes de interface do dispositivo.

Registrando uma interface do dispositivo

Para registrar uma instância de uma classe de interface de dispositivo, um driver baseado em estrutura pode chamar WdfDeviceCreateDeviceInterface antes ou depois do dispositivo ser iniciado. Se o driver der suporte a várias instâncias da interface, ele poderá atribuir uma cadeia de caracteres de referência exclusiva a cada instância.

Depois que o driver tiver registrado uma interface do dispositivo, o driver poderá chamar WdfDeviceRetrieveDeviceInterfaceString para obter o nome de link simbólico que o sistema atribuiu à interface do dispositivo.

Para obter informações sobre outras maneiras pelas quais os drivers podem registrar interfaces de dispositivo, consulte Registrando uma classe de interface do dispositivo.

Habilitar e desabilitar uma interface do dispositivo

As interfaces criadas antes do início do dispositivo (por exemplo, de EvtDriverDeviceAdd, EvtChildListCreateDevice ou EvtDevicePrepareHardware) são habilitadas automaticamente pela estrutura quando o dispositivo passa pela enumeração PnP e é iniciado. Para impedir que a interface seja habilitada automaticamente durante o início do PnP, chame WdfDeviceSetDeviceInterfaceStateEx da mesma função de retorno de chamada (defina o parâmetro EnableInterface como FALSE) para essa interface antes do PnP iniciar.

As interfaces criadas após a inicialização do dispositivo não serão habilitadas automaticamente. O driver deve chamar WdfDeviceSetDeviceInterfaceState ou WdfDeviceSetDeviceInterfaceStateEx para habilitar essas interfaces.

Todas as interfaces são desabilitadas automaticamente quando o dispositivo passa pela remoção de PnP. Observe que as alterações de estado de energia do dispositivo ou o reequilíbrio de recursos PnP não alteram o estado da interface.

Um driver pode desabilitar e reabilitar uma interface do dispositivo, se necessário. Por exemplo, se um driver determinar que seu dispositivo parou de responder, o driver poderá chamar WdfDeviceSetDeviceInterfaceState ou WdfDeviceSetDeviceInterfaceStateEx para desabilitar as interfaces do dispositivo e proibir aplicativos de obter novos identificadores para a interface. (Os identificadores existentes para a interface não são afetados.) Se o dispositivo posteriormente ficar disponível, o driver poderá chamar WdfDeviceSetDeviceInterfaceState ou WdfDeviceSetDeviceInterfaceStateEx novamente para reabilitar as interfaces.

Recebendo solicitações para acessar uma interface do dispositivo

Quando um aplicativo ou componente do modo kernel solicita acesso à interface do dispositivo de um driver, a estrutura chama a função de retorno de chamada EvtDeviceFileCreate do driver. O driver pode chamar WdfFileObjectGetFileName para obter o nome do dispositivo ou arquivo que o aplicativo ou o componente do modo kernel está acessando. Se o driver especificou uma cadeia de caracteres de referência quando registrou a interface do dispositivo, o sistema operacional incluirá a cadeia de caracteres de referência no nome do arquivo ou do dispositivo que WdfFileObjectGetFileName retorna.

Acessando a interface do dispositivo de outro driver

Esta seção mostra como um driver KMDF (Kernel-Mode Driver Framework) ou um driver do UMDF (User-Mode Driver Framework) versão 2 se registra para notificação de chegada ou remoção de uma interface de dispositivo fornecida por outro driver e cria um destino de E/S remoto para se comunicar com o dispositivo representado pela interface do dispositivo.

Para obter informações sobre como fazer isso em um driver UMDF versão 1, consulte Usando interfaces de dispositivo em drivers UMDF.

Para se registrar para notificação de eventos de interface do dispositivo, um driver KMDF chama IoRegisterPlugPlayNotification, enquanto um driver UMDF 2 chama CM_Register_Notification. Em ambos os casos, o driver chama a rotina apropriada de sua função de retorno de chamada EvtDriverDeviceAdd .

O exemplo de código a seguir mostra como um driver UMDF 2 local se registra para notificações e, em seguida, abre o destino de E/S remoto.

  1. O driver remoto registra-se para uma interface do dispositivo chamando WdfDeviceCreateDeviceInterface de 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. O driver local chama CM_Register_Notification de EvtDriverDeviceAdd para se registrar para notificação quando uma interface do dispositivo estiver disponível. Forneça um ponteiro para uma rotina de retorno de chamada de notificação que a estrutura chama quando as interfaces do dispositivo estão disponíveis.

    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. O sistema chama a rotina de retorno de chamada de notificação do driver local sempre que a interface do dispositivo especificada chega ou é removida. A rotina de retorno de chamada pode examinar o parâmetro EventData para determinar qual interface do dispositivo chegou. Em seguida, ele pode enfileirar um item de trabalho para abrir a interface do 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. Na função de retorno de chamada do item de trabalho, o driver local chama WdfIoTargetCreate para criar o destino remoto e WdfIoTargetOpen para abrir um destino de E/S remoto.

    Ao chamar WdfIoTargetOpen, o driver registra opcionalmente uma função de retorno de chamada EvtIoTargetQueryRemove para receber notificação de remoção, juntamente com a oportunidade de recusar a remoção. Se o driver não fornecer EvtIoTargetQueryRemove, a estrutura fechará o destino de E/S quando o dispositivo for removido.

    Em casos raros, um driver UMDF 2 pode chamar CM_Register_Notification uma segunda vez para se registrar para notificação de remoção do dispositivo. Por exemplo, se o driver chamar CreateFile para obter um HANDLE para a interface do dispositivo, ele deverá se registrar para notificação de remoção do dispositivo para que ele possa responder corretamente às tentativas de remoção de consulta. Na maioria dos casos, o driver UMDF 2 chama CM_Register_Notification apenas uma vez e depende do suporte do WDF para remoção do dispositivo.

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

Registrando-se para notificação de chegada da interface do dispositivo e remoção de dispositivo