共用方式為


使用裝置介面 (WDF)

裝置介面是應用程式可用來存取裝置的隨插即用 (PnP) 裝置的符號連結。 使用者模式應用程式可以將介面的符號連結名稱傳遞至 API 元素,例如 Microsoft Win32 CreateFile 函式。 若要取得裝置介面的符號連結名稱,使用者模式應用程式可以呼叫 configuration Manager 函 式或 SetupApi 函式。 如需詳細資訊,請參閱 列舉已安裝的裝置介面

每個裝置介面都屬於 裝置介面類別別。 例如,CD-ROM 裝置的驅動程式堆疊可能會提供屬於 GUID_DEVINTERFACE_CDROM 類別的介面。 其中一個 CD-ROM 裝置的驅動程式會註冊 GUID_DEVINTERFACE_CDROM 類別的實例,以通知系統和應用程式 CD-ROM 裝置可供使用。 如需裝置介面類別別的詳細資訊,請參閱 裝置介面類別別概觀

註冊裝置介面

若要註冊裝置介面類別別的實例,架構型驅動程式可以在裝置啟動之前或之後呼叫 WdfDeviceCreateDeviceInterface 。 如果驅動程式支援介面的多個實例,它可以為每個實例指派唯一的參考字串。

驅動程式註冊裝置介面之後,驅動程式可以呼叫 WdfDeviceRetrieveDeviceInterfaceString ,以取得系統指派給裝置介面的符號連結名稱。

如需驅動程式可註冊裝置介面之其他方式的詳細資訊,請參閱 註冊裝置介面類別別

啟用和停用裝置介面

在裝置啟動之前建立的介面 (例如從 EvtDriverDeviceAddEvtChildListCreateDeviceEvtDevicePrepareHardware) ,當裝置通過 PnP 列舉並開始時,架構會自動啟用。 若要防止在 PnP 啟動期間自動啟用介面,請從相同的回呼函式呼叫 WdfDeviceSetDeviceInterfaceStateEx , (將該介面的 EnableInterface 參數設定為 FALSE) ,再啟動 PnP。

裝置啟動之後建立的介面將不會自動啟用。 驅動程式必須呼叫 WdfDeviceSetDeviceInterfaceStateWdfDeviceSetDeviceInterfaceStateEx ,才能啟用這類介面。

當裝置進行 PnP 移除時,會自動停用所有介面。 請注意,任何裝置電源狀態變更或 PnP 資源重新平衡都不會變更介面的狀態。

如有必要,驅動程式可以停用並重新啟用裝置介面。 例如,如果驅動程式判斷其裝置已停止回應,驅動程式可以呼叫WdfDeviceSetDeviceSetDeviceSetDeviceSetDeviceSetDeviceStateEx來停用裝置的介面,並禁止應用程式取得介面的新控制碼。 (介面的現有控制碼不會受到影響。) 如果裝置稍後可用,驅動程式可以再次呼叫 WdfDeviceSetDeviceInterfaceStateWdfDeviceSetDeviceSetDeviceInterfaceStateEx 來重新啟用介面。

接收存取裝置介面的要求

當應用程式或核心模式元件要求存取驅動程式的裝置介面時,架構會呼叫驅動程式的 EvtDeviceFileCreate 回呼函式。 驅動程式可以呼叫 WdfFileObjectGetFileName ,以取得應用程式或核心模式元件正在存取的裝置或檔案名。 如果驅動程式在註冊裝置介面時指定參考字串,則作業系統會在 WdfFileObjectGetFileName 傳 回的檔案或裝置名稱中包含參考字串。

存取另一個驅動程式的裝置介面

本節說明Kernel-Mode Driver Framework (KMDF) 驅動程式或 User-Mode Driver Framework (UMDF) 第 2 版驅動程式如何註冊以通知另一個驅動程式提供的裝置介面抵達或移除,然後建立 遠端 I/O 目標 ,以與裝置介面所代表的裝置通訊。

如需如何在 UMDF 第 1 版驅動程式中執行這項操作的詳細資訊,請參閱 在 UMDF 驅動程式中使用裝置介面

若要註冊裝置介面事件的通知,KMDF 驅動程式會呼叫 IoRegisterPlugPlayNotification,而 UMDF 2 驅動程式 會呼叫CM_Register_Notification。 在這兩種情況下,驅動程式會從其 EvtDriverDeviceAdd 回呼函式呼叫適當的常式。

下列程式碼範例示範本機 UMDF 2 驅動程式如何註冊通知,然後開啟遠端 I/O 目標。

  1. 遠端驅動程式會從EvtDriverDeviceAdd呼叫WdfDeviceCreateDeviceInterface來註冊裝置介面。

        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. 本機驅動程式會從EvtDriverDeviceAdd呼叫CM_Register_Notification,以在裝置介面可用時註冊通知。 提供當裝置介面可用時,架構會呼叫的通知回呼常式指標。

    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. 每次指定的裝置介面送達或移除時,系統都會呼叫本機驅動程式的通知回呼常式。 回呼常式可以檢查 EventData 參數,以判斷哪些裝置介面已抵達。 然後,它可能會將工作專案排入佇列,以開啟裝置介面。

    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. 從工作專案回呼函式中,本機驅動程式會呼叫 WdfIoTargetCreate 來建立遠端目標,而 WdfIoTargetOpen 則會開啟遠端 I/O 目標。

    呼叫 WdfIoTargetOpen時,驅動程式會選擇性地註冊 EvtIoTargetQueryRemove 回呼函式來接收移除通知,以及拒絕移除的機會。 如果驅動程式未提供 EvtIoTargetQueryRemove,架構會在移除裝置時關閉 I/O 目標。

    在罕見的情況下,UMDF 2 驅動程式可以再次呼叫 CM_Register_Notification ,以註冊裝置移除通知。 例如,如果驅動程式呼叫 CreateFile 以取得裝置介面的 HANDLE,它應該註冊裝置移除的通知,以便正確回應查詢移除嘗試。 在大部分情況下,UMDF 2 驅動程式只會呼叫 CM_Register_Notification 一次,並依賴 WDF 支援進行裝置移除。

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

註冊裝置介面抵達和裝置移除的通知