다음을 통해 공유


WDF(디바이스 인터페이스) 사용

디바이스 인터페이스는 애플리케이션이 디바이스에 액세스하는 데 사용할 수 있는 PnP(플러그 앤 플레이) 디바이스에 대한 기호 링크입니다. 사용자 모드 애플리케이션은 인터페이스의 기호 링크 이름을 Microsoft Win32 CreateFile 함수와 같은 API 요소에 전달할 수 있습니다. 디바이스 인터페이스의 기호 링크 이름을 가져오기 위해 사용자 모드 애플리케이션은 구성 관리자 함수 또는 SetupApi 함수를 호출할 수 있습니다. 자세한 내용은 설치된 디바이스 인터페이스 열거를 참조하세요.

각 디바이스 인터페이스는 디바이스 인터페이스 클래스에 속합니다. 예를 들어 CD-ROM 디바이스에 대한 드라이버 스택은 GUID_DEVINTERFACE_CDROM 클래스에 속하는 인터페이스를 제공할 수 있습니다. CD-ROM 디바이스의 드라이버 중 하나는 GUID_DEVINTERFACE_CDROM 클래스의 instance 등록하여 시스템 및 애플리케이션에 CD-ROM 디바이스를 사용할 수 있음을 알릴 것입니다. 디바이스 인터페이스 클래스에 대한 자세한 내용은 디바이스 인터페이스 클래스 개요를 참조하세요.

디바이스 인터페이스 등록

디바이스 인터페이스 클래스의 instance 등록하기 위해 프레임워크 기반 드라이버는 디바이스가 시작되기 전이나 후에 WdfDeviceCreateDeviceInterface를 호출할 수 있습니다. 드라이버가 인터페이스의 여러 인스턴스를 지원하는 경우 각 instance 고유한 참조 문자열을 할당할 수 있습니다.

드라이버가 디바이스 인터페이스를 등록한 후 드라이버는 WdfDeviceRetrieveDeviceInterfaceString을 호출하여 시스템이 디바이스 인터페이스에 할당한 기호 링크 이름을 가져올 수 있습니다.

드라이버가 디바이스 인터페이스를 등록할 수 있는 다른 방법에 대한 자세한 내용은 디바이스 인터페이스 클래스 등록을 참조하세요.

디바이스 인터페이스 사용 및 사용 안 함

디바이스가 시작되기 전에 만든 인터페이스(예: EvtDriverDeviceAdd, EvtChildListCreateDevice 또는 EvtDevicePrepareHardware)는 디바이스가 PnP 열거형을 통과하고 시작될 때 프레임워크에서 자동으로 사용하도록 설정됩니다. PnP 시작 중에 인터페이스가 자동으로 사용하도록 설정되지 않도록 하려면 PnP가 시작되기 전에 해당 인터페이스에 대해 동일한 콜백 함수(EnableInterface 매개 변수를 FALSE로 설정)에서 WdfDeviceSetDeviceInterfaceStateEx를 호출합니다.

디바이스가 이미 시작된 후에 만든 인터페이스는 자동으로 사용하도록 설정되지 않습니다. 이러한 인터페이스를 사용하려면 드라이버가 WdfDeviceSetDeviceInterfaceState 또는 WdfDeviceSetDeviceInterfaceStateEx 를 호출해야 합니다.

디바이스가 PnP 제거를 거치면 모든 인터페이스가 자동으로 비활성화됩니다. 디바이스 전원 상태가 변경되거나 PnP 리소스 재조정이 인터페이스의 상태를 변경하지 않습니다.

드라이버는 필요한 경우 디바이스 인터페이스를 사용하지 않도록 설정하고 다시 사용하도록 설정할 수 있습니다. 예를 들어 드라이버가 디바이스의 응답을 중지했다고 판단하는 경우 드라이버는 WdfDeviceSetDeviceInterfaceState 또는 WdfDeviceSetDeviceInterfaceStateEx 를 호출하여 디바이스의 인터페이스를 사용하지 않도록 설정하고 애플리케이션이 인터페이스에 대한 새 핸들을 가져오는 것을 금지할 수 있습니다. (인터페이스에 대한 기존 핸들은 영향을 받지 않습니다.) 나중에 디바이스를 사용할 수 있게 되면 드라이버는 WdfDeviceSetDeviceInterfaceState 또는 WdfDeviceSetDeviceInterfaceStateEx 를 다시 호출하여 인터페이스를 다시 활성화할 수 있습니다.

디바이스 인터페이스에 액세스하기 위한 요청 수신

애플리케이션 또는 커널 모드 구성 요소가 드라이버의 디바이스 인터페이스에 대한 액세스를 요청하는 경우 프레임워크는 드라이버의 EvtDeviceFileCreate 콜백 함수를 호출합니다. 드라이버는 WdfFileObjectGetFileName 을 호출하여 애플리케이션 또는 커널 모드 구성 요소가 액세스하는 디바이스 또는 파일의 이름을 가져올 수 있습니다. 드라이버가 디바이스 인터페이스를 등록할 때 참조 문자열을 지정한 경우 운영 체제는 WdfFileObjectGetFileName 이 반환하는 파일 또는 디바이스 이름에 참조 문자열을 포함합니다.

다른 드라이버의 디바이스 인터페이스에 액세스

이 섹션에서는 KMDF(Kernel-Mode Driver Framework) 드라이버 또는 UMDF(User-Mode Driver Framework) 버전 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;
    }
    

디바이스 인터페이스 도착 및 디바이스 제거 알림 등록