첫 번째 USB 클라이언트 드라이버(UMDF)를 작성하는 방법
이 항목에서는 Microsoft Visual Studio 2019와 함께 제공되는 USB User-Mode 드라이버 템플릿을 사용하여 UMDF(사용자 모드 드라이버 프레임워크) 기반 클라이언트 드라이버를 작성합니다. 클라이언트 드라이버를 빌드하고 설치한 후에는 디바이스 관리자 에서 클라이언트 드라이버를 보고 디버거에서 드라이버 출력을 볼 수 있습니다.
UMDF(이 항목의 프레임워크라고 함)는 COM(구성 요소 개체 모델)을 기반으로 합니다. 모든 프레임워크 개체는 기본적으로 IUnknown 및 해당 메서드인 QueryInterface, AddRef 및 Release를 구현해야 합니다. AddRef 및 Release 메서드는 개체의 수명을 관리하므로 클라이언트 드라이버는 참조 횟수를 유지할 필요가 없습니다. QueryInterface 메서드를 사용하면 클라이언트 드라이버가 WDF(Windows Driver Frameworks) 개체 모델의 다른 프레임워크 개체에 대한 인터페이스 포인터를 가져올 수 있습니다. 프레임워크 개체는 복잡한 드라이버 작업을 수행하고 Windows 상호 작용합니다. 특정 프레임워크 개체는 클라이언트 드라이버가 프레임워크와 상호 작용할 수 있도록 하는 인터페이스를 노출합니다.
UMDF 기반 클라이언트 드라이버는 DLL(In-process COM 서버)로 구현되며, C++는 USB 디바이스에 대한 클라이언트 드라이버를 작성하기 위한 기본 설정 언어입니다. 일반적으로 클라이언트 드라이버는 프레임워크에서 노출하는 여러 인터페이스를 구현합니다. 이 항목에서는 프레임워크 인터페이스를 콜백 클래스로 구현하는 클라이언트 드라이버 정의 클래스를 참조합니다. 이러한 클래스가 인스턴스화되면 결과 콜백 개체는 특정 프레임워크 개체와 협력됩니다. 이 파트너 관계를 통해 클라이언트 드라이버는 프레임워크에서 보고하는 디바이스 또는 시스템 관련 이벤트에 응답할 수 있습니다. Windows 프레임워크에 특정 이벤트에 대해 알 수 있을 때마다 프레임워크는 클라이언트 드라이버의 콜백(사용 가능한 경우)을 호출합니다. 그렇지 않으면 프레임워크가 이벤트의 기본 처리를 진행합니다. 템플릿 코드는 드라이버, 디바이스 및 큐 콜백 클래스를 정의합니다.
템플릿에서 생성된 소스 코드에 대한 설명은 USB 클라이언트 드라이버에 대한 UMDF 템플릿 코드 이해를 참조하세요.
사전 요구 사항
사용자 모드 드라이버를 개발, 디버깅 및 설치하려면 다음 두 대의 컴퓨터가 필요합니다.
- Windows 운영 체제의 Windows 7 이상 버전을 실행하는 호스트 컴퓨터입니다. 호스트 컴퓨터는 드라이버를 작성하고 디버그하는 개발 환경입니다.
- 드라이버를 테스트하려는 운영 체제 버전을 실행하는 대상 컴퓨터(예: Windows 10, 버전 1903). 대상 컴퓨터에는 디버그하려는 사용자 모드 드라이버와 디버거 중 하나가 있습니다.
호스트 및 대상 컴퓨터가 동일한 버전의 Windows 실행하는 경우 Windows 7 이상 버전의 Windows 실행하는 컴퓨터가 하나만 있을 수 있습니다. 이 항목에서는 두 대의 컴퓨터를 사용하여 사용자 모드 드라이버를 개발, 디버깅 및 설치한다고 가정합니다.
시작하기 전에 다음 요구 사항을 충족하는지 확인합니다.
소프트웨어 요구 사항
호스트 컴퓨터에 Visual Studio 2019가 있습니다.
호스트 컴퓨터에는 Windows 10 최신 Windows 드라이버 키트(WDK) 버전 1903이 있습니다.
이 키트에는 USB 클라이언트 드라이버를 개발, 빌드 및 디버그하는 데 필요한 헤더, 라이브러리, 도구, 설명서 및 디버깅 도구가 포함됩니다. WDK를 가져오는 방법에서 최신 버전의 WDK를 가져올 수 있습니다.
호스트 컴퓨터에는 Windows 위한 최신 버전의 디버깅 도구가 있습니다. WDK에서 최신 버전을 다운로드하거나 Windows 디버깅 도구를 다운로드하여 설치할 수 있습니다.
두 컴퓨터를 사용하는 경우 사용자 모드 디버깅을 위해 호스트 및 대상 컴퓨터를 구성해야 합니다. 자세한 내용은 Visual Studio User-Mode 디버깅 설정을 참조하세요.
하드웨어 요구 사항
클라이언트 드라이버를 작성할 USB 디바이스를 가져옵니다. 대부분의 경우 USB 디바이스 및 해당 하드웨어 사양이 제공됩니다. 사양은 디바이스 기능 및 지원되는 공급업체 명령을 설명합니다. 사양을 사용하여 USB 드라이버의 기능 및 관련 디자인 결정을 결정합니다.
USB 드라이버 개발을 접하는 경우 OSR USB FX2 학습 키트 를 사용하여 WDK에 포함된 USB 샘플을 연구합니다. 여기에는 USB FX2 디바이스와 클라이언트 드라이버를 구현하는 데 필요한 모든 하드웨어 사양이 포함되어 있습니다.
추천 자료
- 모든 드라이버 개발자를 위한 개념
- 디바이스 노드 및 디바이스 스택
- Windows 드라이버 시작
- 사용자 모드 드라이버 프레임워크
- 페니 오윅과 가이 스미스가 쓴 Windows 드라이버 재단으로 드라이버 개발. 자세한 내용은 WDF를 사용하여 드라이버 개발을 참조하세요.
Instructions
1단계: Visual Studio 2019 USB 드라이버 템플릿을 사용하여 UMDF 드라이버 코드 생성
UMDF 드라이버 코드를 생성하는 방법에 대한 지침은 템플릿을 기반으로 UMDF 드라이버 작성을 참조하세요.
USB 관련 코드의 경우 Visual Studio 2019에서 다음 옵션을 선택합니다.
- 새 Project 대화 상자의 맨 위에 있는 검색 상자에 USB를 입력합니다.
- n 가운데 창에서 사용자 모드 드라이버, USB(UMDF V2)를 선택합니다.
- 다음을 핥습니다.
- 프로젝트 이름을 입력하고 저장 위치를 선택한 다음 만들기를 클릭합니다.
다음 스크린샷에서는 USB User-Mode 드라이버 템플릿에 대한 새 Project 대화 상자를 보여 줍니다.


이 항목에서는 프로젝트의 이름이 "MyUSBDriver_UMDF_"라고 가정합니다. 여기에는 다음 파일이 포함됩니다.
| 파일 | 설명 |
|---|---|
| Driver.h; Driver.c | IDriverEntry 인터페이스를 구현하는 콜백 클래스를 선언하고 정의합니다. 클래스는 프레임워크 드라이버 개체에 의해 호출되는 메서드를 정의합니다. 이 클래스의 주요 목적은 클라이언트 드라이버에 대한 디바이스 개체를 만드는 것입니다. |
| Device.h; Device.c | IPnpCallbackHardware 인터페이스를 구현하는 콜백 클래스를 선언하고 정의합니다. 클래스는 프레임워크 디바이스 개체에 의해 호출되는 메서드를 정의합니다. 이 클래스의 주요 목적은 PnP(플러그 앤 플레이) 상태 변경의 결과로 발생하는 이벤트를 처리하는 것입니다. 또한 클래스는 시스템에 로드되는 한 클라이언트 드라이버에 필요한 리소스를 할당하고 초기화합니다. |
| IoQueue.h; IoQueue.c | IQueueCallbackDeviceIoControl 인터페이스를 구현하는 콜백 클래스를 선언하고 정의합니다. 클래스는 프레임워크 큐 개체에 의해 호출되는 메서드를 정의합니다. 이 클래스의 목적은 프레임워크에서 큐에 대기 중인 I/O 요청을 검색하는 것입니다. |
| Internal.h | USB 디바이스와 통신하는 클라이언트 드라이버 및 사용자 애플리케이션에서 공유하는 일반적인 선언을 제공합니다. 또한 추적 함수 및 매크로를 선언합니다. |
| Dllsup.cpp | 드라이버 모듈의 진입점 구현을 포함합니다. |
| <Project name.inf> | 대상 컴퓨터에 클라이언트 드라이버를 설치하는 데 필요한 INF 파일입니다. |
| Exports.def | 드라이버 모듈의 진입점 함수 이름을 내보내는 DEF 파일입니다. |
2단계: 디바이스에 대한 정보를 추가하도록 INF 파일 수정
드라이버를 빌드하기 전에 디바이스에 대한 정보, 특히 하드웨어 ID 문자열을 사용하여 템플릿 INF 파일을 수정해야 합니다.
하드웨어 ID 문자열을 제공하려면
USB 디바이스를 호스트 컴퓨터에 연결하고 Windows 디바이스를 열거할 수 있습니다.
디바이스 관리자를 열고 디바이스에 대한 속성을 엽니다.
세부 정보 탭의 속성 아래에서 하드워드 ID를 선택합니다.
디바이스의 하드웨어 ID가 목록 상자에 표시됩니다. 하드웨어 ID 문자열을 선택하고 길게(또는 마우스 오른쪽 단추로 클릭) 복사합니다.
솔루션 탐색기에서 드라이버 파일을 확장하고 INF를 엽니다.
다음 하드웨어 ID 문자열을 바꿉니다.
[Standard.NT$ARCH$]%DeviceName%=MyDevice_Install, USB\VID_vvvv&PID_pppp
드라이버의 정보(INF) 파일에서 AddReg 항목을 확인합니다.
[CoInstallers_AddReg] ;
HKR,,CoInstallers32,0x00010008,"WudfCoinstaller.dll"
HKR,,CoInstallers32,0x00010008,"WudfUpdate_01011.dll"
HKR,,CoInstallers32,0x00010008,"WdfCoInstaller01011.dll,WdfCoInstaller"
HKR,,CoInstallers32,0x00010008,"WinUsbCoinstaller2.dll"
- WudfCoinstaller.dll(구성 공동 설치 관리자)
- <WUDFUpdate_버전>.dll(재배포 가능 공동 설치 관리자)
- Wdfcoinstallerversion<>.dll(KMDF용 공동 설치 관리자)
- Winusbcoinstaller2.dll((Winusb.sys 공동 설치 관리자)
- MyUSBDriver_UMDF_.dll(클라이언트 드라이버 모듈)
INF AddReg 지시문이 UMDF 재배포 가능 공동 설치 관리자(WUDFUpdate_<버전>.dll)를 참조하는 경우 구성 공동 설치 관리자(WUDFCoInstaller.dll)를 참조해서는 안 됩니다. INF에서 두 공동 설치 관리자를 모두 참조하면 설치 오류가 발생합니다.
모든 UMDF 기반 USB 클라이언트 드라이버에는 두 개의 Microsoft 제공 드라이버인 리플렉터와 WinUSB가 필요합니다.
리플렉터 - 드라이버가 성공적으로 로드되면 리플렉터가 커널 모드 스택에서 최상위 드라이버로 로드됩니다. 리플렉터를 커널 모드 스택의 최상위 드라이버여야 합니다. 이 요구 사항을 충족하기 위해 템플릿의 INF 파일은 리플렉터를 서비스로 지정하고 WinUSB는 INF에서 하위 필터 드라이버로 지정합니다.
[MyDevice_Install.NT.Services]AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall ; flag 0x2 sets this as the service for the deviceAddService=WinUsb,0x000001f8,WinUsb_ServiceInstall ; this service is installed because its a filter.WinUSB - 클라이언트 드라이버의 경우 WinUSB는 커널 모드 USB 드라이버 스택에 대한 게이트웨이이므로 설치 패키지에 Winusb.sys 대한 coinstaller가 포함되어야 합니다. 로드되는 또 다른 구성 요소는 클라이언트 드라이버의 호스트 프로세스(Wudfhost.exe)에서 WinUsb.dll 명명된 사용자 모드 DLL입니다. Winusb.dll 클라이언트 드라이버와 WinUSB 간의 통신 프로세스를 간소화하는 WinUSB 함수를 노출합니다.
3단계: USB 클라이언트 드라이버 코드 빌드
- Visual Studio 2019에서 드라이버 프로젝트 또는 솔루션을 엽니다.
- 솔루션 탐색기에서 솔루션을 마우스 오른쪽 단추로 클릭하고 Configuration Manager를 선택합니다.
- Configuration Manager에서 활성 솔루션 구성(예: 디버그 또는 릴리스) 및 관심 있는 빌드 유형에 해당하는 활성 솔루션 플랫폼(예: Win32)을 선택합니다.
- 디바이스 인터페이스 GUID가 프로젝트 전체에서 정확한지 확인합니다.
- 디바이스 인터페이스 GUID는 Trace.h에 정의되며 Device.c에서
MyUSBDriverUMDFCreateDevice참조됩니다. 이름이 "MyUSBDriver_UMDF_"인 프로젝트를 만들 때 Visual Studio 2019는 이름을GUID_DEVINTERFACE_MyUSBDriver_UMDF_가진 디바이스 인터페이스 GUID를 정의하지만 잘못된 매개 변수 "GUID_DEVINTERFACE_MyUSBDriverUMDF"를 사용하여 호출WdfDeviceCreateDeviceInterface합니다. 드라이버가 제대로 빌드되도록 잘못된 매개 변수를 Trace.h에 정의된 이름으로 바꿉니다.
- 디바이스 인터페이스 GUID는 Trace.h에 정의되며 Device.c에서
- 빌드 메뉴에서 솔루션 빌드를 클릭합니다.
자세한 내용은 드라이버 빌드를 참조하세요.
4단계: 테스트 및 디버깅을 위한 컴퓨터 구성
드라이버를 테스트하고 디버그하려면 호스트 컴퓨터에서 디버거를 실행하고 대상 컴퓨터에서 드라이버를 실행합니다. 지금까지 호스트 컴퓨터에서 Visual Studio 사용하여 드라이버를 빌드했습니다. 다음으로 대상 컴퓨터를 구성해야 합니다. 대상 컴퓨터를 구성하려면 드라이버 배포 및 테스트를 위해 컴퓨터 프로비전의 지침을 따릅니다.
5단계: 커널 디버깅에 추적 사용
템플릿 코드에는 함수 호출을 추적하는 데 도움이 되는 여러 추적 메시지(TraceEvents)가 포함되어 있습니다. 소스 코드의 모든 함수에는 루틴의 진입 및 종료를 표시하는 추적 메시지가 포함됩니다. 오류의 경우 추적 메시지에는 오류 코드와 의미 있는 문자열이 포함됩니다. 드라이버 프로젝트에 WPP 추적을 사용할 수 있으므로 빌드 프로세스 중에 생성된 PDB 기호 파일에는 추적 메시지 서식 지정 지침이 포함되어 있습니다. WPP 추적을 위해 호스트 및 대상 컴퓨터를 구성하는 경우 드라이버는 추적 메시지를 파일 또는 디버거로 보낼 수 있습니다.
WPP 추적을 위해 호스트 컴퓨터를 구성하려면
PDB 기호 파일에서 추적 메시지 서식 지정 지침을 추출하여 TMF(추적 메시지 형식) 파일을 만듭니다.
Tracepdb.exe 사용하여 TMF 파일을 만들 수 있습니다. 이 도구는 WDK의 <설치 폴더>Windows Kits\10\bin\<architecture> 폴더에 있습니다. 다음 명령은 드라이버 프로젝트에 대한 TMF 파일을 만듭니다.
tracepdb -f [PDBFiles] -p [TMFDirectory]
-f 옵션은 PDB 기호 파일의 위치와 이름을 지정합니다. -p 옵션은 Tracepdb에서 만든 TMF 파일의 위치를 지정합니다. 자세한 내용은 Tracepdb 명령을 참조하세요.
지정된 위치에는 세 개의 파일(프로젝트의 .c 파일당 하나씩)이 표시됩니다. GUID 파일 이름이 지정됩니다.
디버거에서 다음 명령을 입력합니다.
.load Wmitrace
.chain
!wmitrace.searchpath +***<TMF file location>
다음 명령을 실행합니다.
- Wmitrace.dll 확장을 로드합니다.
- 디버거 확장이 로드되는 것을 설명합니다.
- 디버거 확장의 검색 경로에 TMF 파일의 위치를 추가합니다.
다음과 유사한 출력이 표시됩니다.
Trace Format search path is: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;c:\drivers\tmf
WPP 추적을 위해 대상 컴퓨터를 구성하려면
- 대상 컴퓨터에 Tracelog 도구가 있는지 확인합니다. 도구는 WDK의 <install_folder> Windows Kits\10\Tools\<arch> 폴더에 있습니다. 자세한 내용은 Tracelog 명령 구문을 참조하세요.
- 명령 창을 열고 관리자 권한으로 실행합니다.
- 다음 명령을 입력합니다.
**tracelog -start MyTrace -guid \#c918ee71-68c7-4140-8f7d-c907abbcb05d -flag 0xFFFF -level 7-rt -kd**
이 명령은 MyTrace라는 추적 세션을 시작합니다.
guid 인수는 클라이언트 드라이버인 추적 공급자의 GUID를 지정합니다. Visual Studio 2019 프로젝트에서 Trace.h에서 GUID를 가져올 수 있습니다. 다른 옵션으로 다음 명령을 입력하고 .guid 파일에서 GUID를 지정할 수 있습니다. 파일에는 하이픈 형식의 GUID가 포함되어 있습니다.
**tracelog -start MyTrace -guid c:\\drivers\\Provider.guid -flag 0xFFFF -level 7-rt -kd**
다음 명령을 입력하여 추적 세션을 중지할 수 있습니다.
**tracelog -stop MyTrace**
6단계: 대상 컴퓨터에 드라이버 배포
- 솔루션 탐색기 창에서 프로젝트 namePackage>를 선택하고 길게(또는 마우스 오른쪽 단추로 클릭)<속성을 선택합니다.
- 왼쪽 창에서 구성 속성 > 드라이버 설치 > 배포로 이동합니다.
- 배포를 사용하도록 설정하고 드라이버 저장소로 가져오기를 확인합니다.
- 원격 컴퓨터 이름의 경우 대상 컴퓨터의 이름을 지정합니다.
- 설치 및 확인을 선택합니다.
- 확인을 선택합니다.
- 디버그 메뉴에서 디버깅 시작을 선택하거나 키보드에서 F5 키를 누릅니다.
참고
하드웨어 ID 드라이버 업데이트에서 디바이스의 하드웨어 ID를 지정하지 마세요. 하드웨어 ID는 드라이버의 정보(INF) 파일에서만 지정해야 합니다.
7단계: 디바이스 관리자에서 드라이버 보기
다음 명령을 입력하여 디바이스 관리자를 엽니다.
devmgmt
Device Manager에 다음 노드가 표시되는지 확인합니다.
USB 디바이스
MyUSBDriver_UMDF_Device
8단계: 디버거에서 출력 보기
추적 메시지가 호스트 컴퓨터의 디버거 직접 실행 창 에 표시되는지 확인합니다.
출력은 다음과 같은 형태가 됩니다.
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Entry
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Exit
설명
프레임워크와 클라이언트 드라이버가 함께 작동하여 Windows 상호 작용하고 USB 디바이스로 전송된 요청을 처리하는 방법을 살펴보겠습니다. 이 그림에서는 UMDF 기반 USB 클라이언트 드라이버용으로 시스템에 로드된 모듈을 보여 줍니다.

각 모듈의 용도는 다음과 같습니다.
- 애플리케이션 - USB 디바이스와 통신하기 위해 I/O 요청을 발급하는 사용자 모드 프로세스입니다.
- I/O 관리자 - 수신된 애플리케이션 요청을 나타내는 I/O 요청 패킷(IRP)을 만들고 대상 디바이스에 대한 커널 모드 디바이스 스택의 맨 위에 전달하는 Windows 구성 요소입니다.
- 리플렉터- 커널 모드 디바이스 스택(WUDFRd.sys) 맨 위에 설치된 Microsoft 제공 커널 모드 드라이버입니다. 리플렉터에서는 I/O 관리자로부터 받은 IRP를 클라이언트 드라이버 호스트 프로세스로 리디렉션합니다. 요청을 받으면 프레임워크와 클라이언트 드라이버가 요청을 처리합니다.
- 호스트 프로세스 - 사용자 모드 드라이버가 실행되는 프로세스(Wudfhost.exe). 프레임워크 및 I/O 디스패처도 호스팅합니다.
- 클라이언트 드라이버 - USB 디바이스에 대한 사용자 모드 함수 드라이버입니다.
- UMDF - 클라이언트 드라이버를 대신하여 Windows 대부분의 상호 작용을 처리하는 프레임워크 모듈입니다. 클라이언트 드라이버가 일반적인 드라이버 작업을 수행하는 데 사용할 수 있는 DDI(사용자 모드 디바이스 드라이버 인터페이스)를 노출합니다.
- Dispatcher - 호스트 프로세스에서 실행되는 메커니즘 는 사용자 모드 드라이버에서 처리되고 사용자 모드 스택의 맨 아래에 도달한 후 커널 모드로 요청을 전달하는 방법을 결정합니다. 그림에서 디스패처는 Winusb.dll 사용자 모드 DLL로 요청을 전달합니다.
- Winusb.dll - 클라이언트 드라이버와 WinUSB(커널 모드로 로드된 Winusb.sys) 간의 통신 프로세스를 간소화하는 WinUSB Functions 를 노출하는 Microsoft에서 제공하는 사용자 모드 DLL입니다.
- Winusb.sys - USB 디바이스에 대한 모든 UMDF 클라이언트 드라이버에 필요한 Microsoft 제공 드라이버입니다. 드라이버는 리플렉터 아래에 설치되어야 하며 커널 모드에서 USB 드라이버 스택에 대한 게이트웨이 역할을 해야 합니다. 자세한 내용은 WinUSB를 참조하세요.
- USB 드라이버 스택 - USB 디바이스와의 프로토콜 수준 통신을 처리하는 Microsoft에서 제공하는 드라이버 집합입니다. 자세한 내용은 Windows USB 호스트 쪽 드라이버를 참조하세요.
애플리케이션이 USB 드라이버 스택에 대한 요청을 수행할 때마다 Windows I/O 관리자가 리플렉터에 요청을 보내 사용자 모드에서 클라이언트 드라이버로 보냅니다. 클라이언트 드라이버는 WinUSB 함수를 내부적으로 호출하여 WinUSB 에 요청을 보내는 특정 UMDF 메서드를 호출하여 요청을 처리합니다. 요청을 받으면 WinUSB는 요청을 처리하거나 USB 드라이버 스택에 전달합니다.
관련 항목
USB 클라이언트 드라이버에 대한 UMDF 템플릿 코드 이해
USB 디바이스에 대해 UMDF 드라이버에서 USB 선택적 일시 중단 및 시스템 절전 모드 해제를 사용하도록 설정하는 방법
USB 클라이언트 드라이버 개발 시작