Uso di interfacce di dispositivo (WDF)
Un'interfaccia del dispositivo è un collegamento simbolico a un dispositivo Plug and Play (PnP) che un'applicazione può usare per accedere al dispositivo. Un'applicazione in modalità utente può passare il nome del collegamento simbolico dell'interfaccia a un elemento API, ad esempio la funzione CreateFile Di Microsoft Win32. Per ottenere il nome di collegamento simbolico di un'interfaccia dispositivo, l'applicazione in modalità utente può chiamare funzioni di Configuration Manager o Funzioni SetupApi. Per altre informazioni, vedere Enumerazione delle interfacce del dispositivo installate.
Ogni interfaccia del dispositivo appartiene a una classe di interfaccia del dispositivo. Ad esempio, uno stack di driver per un dispositivo CD-ROM potrebbe fornire un'interfaccia appartenente alla classe GUID_DEVINTERFACE_CDROM. Uno dei driver del dispositivo CD-ROM registra un'istanza della classe GUID_DEVINTERFACE_CDROM per informare il sistema e le applicazioni che è disponibile un dispositivo CD-ROM. Per altre informazioni sulle classi di interfaccia del dispositivo, vedere Panoramica delle classi di interfaccia dispositivo.
Registrazione di un'interfaccia dispositivo
Per registrare un'istanza di una classe di interfaccia del dispositivo, un driver basato su framework può chiamare WdfDeviceCreateDeviceInterface prima o dopo l'avvio del dispositivo. Se il driver supporta più istanze dell'interfaccia, può assegnare una stringa di riferimento univoca a ogni istanza.
Dopo che il driver ha registrato un'interfaccia del dispositivo, il driver può chiamare WdfDeviceRetrieveDeviceInterfaceString per ottenere il nome di collegamento simbolico assegnato dal sistema all'interfaccia del dispositivo.
Per informazioni su altri modi in cui i driver possono registrare le interfacce di dispositivo, vedere Registrazione di una classe di interfaccia dispositivo.
Abilitazione e disabilitazione di un'interfaccia del dispositivo
Le interfacce create prima dell'avvio del dispositivo (ad esempio da EvtDriverDeviceAdd, EvtChildListCreateDevice o EvtDevicePrepareHardware) vengono abilitate automaticamente dal framework quando il dispositivo passa attraverso l'enumerazione PnP e viene avviato. Per impedire l'abilitazione automatica dell'interfaccia durante l'avvio di PnP, chiamare WdfDeviceSetDeviceInterfaceStateEx dalla stessa funzione di callback (impostare il parametro EnableInterface su FALSE) per tale interfaccia prima dell'avvio di PnP.
Le interfacce create dopo l'avvio del dispositivo non verranno abilitate automaticamente. Il driver deve chiamare WdfDeviceSetDeviceInterfaceState o WdfDeviceSetDeviceInterfaceStateEx per abilitare tali interfacce.
Tutte le interfacce vengono disabilitate automaticamente quando il dispositivo viene sottoposto a rimozione PnP. Si noti che qualsiasi stato di alimentazione del dispositivo cambia o il ribilanciamento della risorsa PnP non modifica lo stato dell'interfaccia.
Un driver può disabilitare e riabilitare un'interfaccia del dispositivo, se necessario. Ad esempio, se un driver determina che il dispositivo ha smesso di rispondere, il driver può chiamare WdfDeviceSetDeviceInterfaceState o WdfDeviceSetDeviceInterfaceStateEx per disabilitare le interfacce del dispositivo e impedire alle applicazioni di ottenere nuovi handle all'interfaccia. Gli handle esistenti per l'interfaccia non sono interessati. Se il dispositivo diventa disponibile in un secondo momento, il driver può chiamare di nuovo WdfDeviceSetDeviceInterfaceState o WdfDeviceSetDeviceInterfaceStateEx per riabilitare le interfacce.
Ricezione di richieste di accesso a un'interfaccia del dispositivo
Quando un'applicazione o un componente in modalità kernel richiede l'accesso all'interfaccia del dispositivo di un driver, il framework chiama la funzione di callback EvtDeviceFileCreate del driver. Il driver può chiamare WdfFileObjectGetFileName per ottenere il nome del dispositivo o del file a cui accede l'applicazione o il componente in modalità kernel. Se il driver ha specificato una stringa di riferimento quando ha registrato l'interfaccia del dispositivo, il sistema operativo include la stringa di riferimento nel nome del file o del dispositivo restituito da WdfFileObjectGetFileName .
Accesso all'interfaccia del dispositivo di un altro driver
Questa sezione illustra come un driver Kernel-Mode Driver Framework (KMDF) o un driver User-Mode Driver Framework (UMDF) versione 2 registra per la notifica di arrivo o rimozione di un'interfaccia dispositivo fornita da un altro driver e quindi crea una destinazione di I/O remota per comunicare con il dispositivo rappresentato dall'interfaccia del dispositivo.
Per informazioni su come eseguire questa operazione in un driver UMDF versione 1, vedere Using Device Interfaces in UMDF Drivers .For information on how to do this in a UMDF driver, see Using Device Interfaces in UMDF Drivers.
Per eseguire la registrazione per la notifica degli eventi dell'interfaccia del dispositivo, un driver KMDF chiama IoRegisterPlugPlayNotification, mentre un driver UMDF 2 chiama CM_Register_Notification. In entrambi i casi, il driver chiama la routine appropriata dalla relativa funzione di callback EvtDriverDeviceAdd .
Nell'esempio di codice seguente viene illustrato come un driver UMDF 2 locale esegue la registrazione per le notifiche e quindi apre la destinazione di I/O remota.
Il driver remoto esegue la registrazione per un'interfaccia del dispositivo chiamando WdfDeviceCreateDeviceInterface da 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; }
Il driver locale chiama CM_Register_Notification da EvtDriverDeviceAdd per registrarsi per la notifica quando è disponibile un'interfaccia del dispositivo. Fornire un puntatore a una routine di callback di notifica che il framework chiama quando sono disponibili interfacce del dispositivo.
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; }
Il sistema chiama la routine di callback di notifica del driver locale ogni volta che l'interfaccia del dispositivo specificata arriva o viene rimossa. La routine di callback può esaminare il parametro EventData per determinare quale interfaccia del dispositivo è arrivata. Potrebbe quindi accodare un elemento di lavoro per aprire l'interfaccia 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; }
Dalla funzione di callback dell'elemento di lavoro, il driver locale chiama WdfIoTargetCreate per creare la destinazione remota e WdfIoTargetOpen per aprire una destinazione di I/O remota.
Quando si chiama WdfIoTargetOpen, il driver registra facoltativamente una funzione di callback EvtIoTargetQueryRemove per ricevere la notifica di rimozione, insieme alla possibilità di rifiutare la rimozione. Se il driver non fornisce EvtIoTargetQueryRemove, il framework chiude la destinazione di I/O quando il dispositivo viene rimosso.
In rari casi, un driver UMDF 2 può chiamare CM_Register_Notification una seconda volta, per registrarsi per la notifica della rimozione del dispositivo. Ad esempio, se il driver chiama CreateFile per ottenere un handle all'interfaccia del dispositivo, deve registrarsi per la notifica della rimozione del dispositivo in modo che possa rispondere correttamente ai tentativi di rimozione delle query. Nella maggior parte dei casi, il driver UMDF 2 chiama CM_Register_Notification una sola volta e si basa sul supporto WDF per la rimozione del dispositivo.
VOID EvtWorkItem( _In_ WDFWORKITEM WorkItem ) { // // create and open remote target // return; }