WebUSB용 기기 빌드

WebUSB API를 최대한 활용할 수 있는 기기를 빌드합니다.

이 도움말에서는 WebUSB API를 최대한 활용하는 기기를 빌드하는 방법을 설명합니다. API 자체에 관한 간단한 소개는 웹에서 USB 기기에 액세스를 참고하세요.

배경

범용 직렬 버스 (USB)는 주변기기를 데스크톱 및 모바일 컴퓨팅 기기에 연결하는 가장 일반적인 물리적 인터페이스가 되었습니다. USB 사양은 버스의 전기적 특성과 기기와 통신하기 위한 일반적인 모델을 정의하는 것 외에도 일련의 기기 클래스 사양을 포함합니다. 이는 저장소, 오디오, 동영상, 네트워킹 등 기기 제조업체에서 구현할 수 있는 특정 기기 클래스의 일반적인 모델입니다. 이러한 기기 클래스 사양의 이점은 운영체제 공급업체가 클래스 사양('클래스 드라이버')을 기반으로 단일 드라이버를 구현할 수 있고 이 클래스를 구현하는 모든 기기가 지원된다는 것입니다. 이는 모든 제조업체가 자체 기기 드라이버를 작성해야 하는 것에 비해 크게 개선되었습니다.

하지만 일부 기기는 이러한 표준화된 기기 클래스 중 하나에 속하지 않습니다. 제조업체는 대신 기기를 공급업체별 클래스를 구현하는 것으로 라벨을 지정할 수 있습니다. 이 경우 운영체제는 공급업체의 드라이버 패키지에 제공된 정보(일반적으로 특정 공급업체별 프로토콜을 구현하는 것으로 알려진 공급업체 및 제품 ID 집합)를 기반으로 로드할 기기 드라이버를 선택합니다.

USB의 또 다른 기능은 기기가 연결된 호스트에 여러 인터페이스를 제공할 수 있다는 점입니다. 각 인터페이스는 표준화된 클래스를 구현하거나 공급업체별일 수 있습니다. 운영체제가 기기를 처리할 올바른 드라이버를 선택하면 각 인터페이스는 다른 드라이버에 의해 소유권 주장을 할 수 있습니다. 예를 들어 USB 웹캠은 일반적으로 USB 비디오 클래스 (카메라용)를 구현하는 인터페이스와 USB 오디오 클래스 (마이크용)를 구현하는 인터페이스를 제공합니다. 운영 체제는 단일 '웹캠 드라이버'를 로드하지 않고 대신 기기의 별도 기능을 담당하는 독립적인 동영상 및 오디오 클래스 드라이버를 로드합니다. 이러한 인터페이스 클래스 구성은 더 큰 유연성을 제공합니다.

API 기본사항

많은 표준 USB 클래스에는 상응하는 웹 API가 있습니다. 예를 들어 페이지는 getUserMedia()를 사용하여 동영상 클래스 기기에서 동영상을 캡처하거나 KeyboardEvents 또는 PointerEvents를 리슨하거나 Gamepad 또는 WebHID API를 사용하여 인간 인터페이스 (HID) 클래스 기기에서 입력 이벤트를 수신할 수 있습니다. 일부 기기에서는 표준화된 클래스 정의를 구현하지 않는 것처럼 일부 기기에서는 기존 웹 플랫폼 API에 해당하는 기능을 구현하지 않습니다. 이 경우 WebUSB API는 사이트에서 공급업체별 인터페이스를 요구하고 페이지 내에서 직접 지원을 구현하는 방법을 제공하여 이 공백을 메울 수 있습니다.

WebUSB를 통해 기기에 액세스하기 위한 구체적인 요구사항은 운영체제에서 USB 기기를 관리하는 방식의 차이로 인해 플랫폼마다 약간 다르지만 기본 요구사항은 기기에 페이지에서 제어하려는 인터페이스를 주장하는 드라이버가 이미 없어야 한다는 것입니다. 이는 OS 공급업체에서 제공하는 일반 클래스 드라이버 또는 공급업체에서 제공하는 기기 드라이버일 수 있습니다. USB 기기는 각각 자체 드라이버가 있을 수 있는 여러 인터페이스를 제공할 수 있으므로 일부 인터페이스는 드라이버에서 소유하고 다른 인터페이스는 브라우저에서 액세스할 수 있는 기기를 빌드할 수 있습니다.

예를 들어 고급 USB 키보드는 운영체제의 입력 하위 시스템에서 소유권을 주장할 HID 클래스 인터페이스와 구성 도구에서 사용할 수 있도록 WebUSB에서 계속 사용할 수 있는 공급업체별 인터페이스를 제공할 수 있습니다. 이 도구는 제조업체 웹사이트에서 제공할 수 있으므로 사용자가 플랫폼별 소프트웨어를 설치하지 않고도 매크로 키, 조명 효과와 같은 기기 동작의 측면을 변경할 수 있습니다. 이러한 기기의 구성 설명자는 다음과 같습니다.

필드 설명
구성 설명자
0x09 bLength 이 설명자의 크기
0x02 bDescriptorType 구성 설명자
0x0039 wTotalLength 이 설명자 계열의 총 길이
0x02 bNumInterfaces 인터페이스 수
0x01 bConfigurationValue Configuration 1
0x00 iConfiguration 구성 이름 (없음)
0b1010000 bmAttributes 원격 웨이크업 기능이 있는 자체 전원 공급 기기
0x32 bMaxPower 최대 전력은 2mA 단위로 표시됩니다.
인터페이스 설명자
0x09 bLength 이 설명자의 크기
0x04 bDescriptorType 인터페이스 설명자
0x00 bInterfaceNumber 인터페이스 0
0x00 bAlternateSetting 대체 설정 0 (기본값)
0x01 bNumEndpoints 엔드포인트 1개
0x03 bInterfaceClass HID 인터페이스 클래스
0x01 bInterfaceSubClass 부팅 인터페이스 서브클래스
0x01 bInterfaceProtocol 키보드
0x00 iInterface 인터페이스 이름 (없음)
HID 설명자
0x09 bLength 이 설명자의 크기
0x21 bDescriptorType HID 설명자
0x0101 bcdHID HID 버전 1.1
0x00 bCountryCode 하드웨어 대상 국가
0x01 bNumDescriptors 따라야 할 HID 클래스 설명자 수
0x22 bDescriptorType 보고서 설명자 유형
0x003F wDescriptorLength 보고서 설명자의 총 길이
엔드포인트 설명자
0x07 bLength 이 설명자의 크기
0x05 bDescriptorType 엔드포인트 설명자
0b10000001 bEndpointAddress 엔드포인트 1 (IN)
0b00000011 bmAttributes 인터럽트
0x0008 wMaxPacketSize 8바이트 패킷
0x0A bInterval 10ms 간격
인터페이스 설명자
0x09 bLength 이 설명자의 크기
0x04 bDescriptorType 인터페이스 설명자
0x01 bInterfaceNumber 인터페이스 1
0x00 bAlternateSetting 대체 설정 0 (기본값)
0x02 bNumEndpoints 엔드포인트 2개
0xFF bInterfaceClass 공급업체별 인터페이스 클래스
0x00 bInterfaceSubClass
0x00 bInterfaceProtocol
0x00 iInterface 인터페이스 이름 (없음)
엔드포인트 설명자
0x07 bLength 이 설명자의 크기
0x05 bDescriptorType 엔드포인트 설명자
0b10000010 bEndpointAddress 엔드포인트 1 (IN)
0b00000010 bmAttributes 대량
0x0040 wMaxPacketSize 64바이트 패킷
0x00 bInterval 일괄 엔드포인트에는 해당 사항 없음
엔드포인트 설명자
0x07 bLength 이 설명자의 크기
0x05 bDescriptorType 엔드포인트 설명자
0b00000011 bEndpointAddress 엔드포인트 3 (OUT)
0b00000010 bmAttributes 대량
0x0040 wMaxPacketSize 64바이트 패킷
0x00 bInterval 일괄 엔드포인트에는 해당 사항 없음

구성 설명자는 여러 설명자가 연결된 것으로 구성됩니다. 각 시계열은 식별할 수 있도록 bLengthbDescriptorType 필드로 시작합니다. 첫 번째 인터페이스는 연결된 HID 설명자와 운영체제에 입력 이벤트를 전달하는 데 사용되는 단일 엔드포인트를 포함하는 HID 인터페이스입니다. 두 번째 인터페이스는 기기에 명령어를 전송하고 응답으로 응답을 수신하는 데 사용할 수 있는 두 개의 엔드포인트가 있는 공급업체별 인터페이스입니다.

WebUSB 설명어

WebUSB는 펌웨어 수정 없이도 여러 기기에서 작동할 수 있지만, WebUSB 지원을 나타내는 특정 설명자로 기기를 표시하면 추가 기능이 사용 설정됩니다. 예를 들어 기기가 연결되어 있을 때 브라우저에서 사용자를 안내할 수 있는 방문 페이지 URL을 지정할 수 있습니다.

Chrome의 WebUSB 알림 스크린샷
WebUSB 알림.

바이너리 기기 객체 저장소 (BOS)는 USB 3.0에서 도입된 개념이지만 버전 2.1의 일부로 USB 2.0 기기에 백포팅되었습니다. WebUSB 지원을 선언하려면 먼저 BOS 설명자에 다음 플랫폼 기능 설명자를 포함해야 합니다.

필드 설명
바이너리 기기 객체 저장소 설명자
0x05 bLength 이 설명자의 크기
0x0F bDescriptorType 바이너리 기기 객체 저장소 설명어
0x001D wTotalLength 이 설명자 계열의 총 길이
0x01 bNumDeviceCaps BOS의 기기 기능 설명자 수
WebUSB 플랫폼 기능 설명어
0x18 bLength 이 설명자의 크기
0x10 bDescriptorType 기기 기능 설명어
0x05 bDevCapabilityType 플랫폼 기능 설명자
0x00 bReserved
{0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} PlatformCapablityUUID 리틀엔디언 형식의 WebUSB 플랫폼 기능 설명자 GUID
0x0100 bcdVersion WebUSB 설명자 버전 1.0
0x01 bVendorCode WebUSB의 bRequest 값
0x01 iLandingPage 방문 페이지 URL

플랫폼 기능 UUID는 이를 기기에 관한 기본 정보를 제공하는 WebUSB 플랫폼 기능 설명어로 식별합니다. 브라우저가 기기에 관한 추가 정보를 가져올 수 있도록 bVendorCode 값을 사용하여 기기에 추가 요청을 보냅니다. 현재 지정된 유일한 요청은 URL 설명자를 반환하는 GET_URL입니다. 문자열 설명자와 유사하지만 URL을 가장 적은 수의 바이트로 인코딩하도록 설계되었습니다. "https://google.com"의 URL 설명자는 다음과 같습니다.

필드 설명
URL 설명자
0x0D bLength 이 설명자의 크기
0x03 bDescriptorType URL 설명자
0x01 bScheme https://
"google.com" URL UTF-8로 인코딩된 URL 콘텐츠

기기가 처음에 연결되면 브라우저는 다음과 같은 표준 GET_DESCRIPTOR 제어 전송을 실행하여 BOS 설명자를 읽습니다.

bmRequestType bRequest wValue wIndex wLength 데이터 (응답)
0b10000000 0x06 0x0F00 0x0000 * BOS 설명자

이 요청은 일반적으로 두 번 이루어집니다. 첫 번째는 호스트가 대규모 전송을 커밋하지 않고도 wTotalLength 필드의 값을 찾을 수 있도록 충분히 큰 wLength를 사용하여 요청하고, 두 번째는 전체 설명자 길이가 알려진 후에 다시 요청합니다.

WebUSB 플랫폼 기능 설명자의 iLandingPage 필드가 0이 아닌 값으로 설정된 경우 브라우저는 bRequest을 플랫폼 기능 설명자의 bVendorCode 값으로 설정하고 wValueiLandingPage 값으로 설정하여 제어 전송을 실행하여 WebUSB 관련 GET_URL 요청을 실행합니다. GET_URL의 요청 코드 (0x02)는 wIndex에 포함됩니다.

bmRequestType bRequest wValue wIndex wLength 데이터 (응답)
0b11000000 0x01 0x0001 0x0002 * URL 설명자

다시 말하지만, 이 요청은 먼저 읽을 설명어의 길이를 프로브하기 위해 두 번 실행될 수 있습니다.

플랫폼별 고려사항

WebUSB API는 USB 기기에 액세스하기 위한 일관된 인터페이스를 제공하려고 하지만 개발자는 기기에 액세스하기 위한 웹브라우저 요구사항과 같이 애플리케이션에 적용되는 요구사항을 알고 있어야 합니다.

macOS

macOS에는 특별한 작업이 필요하지 않습니다. WebUSB를 사용하는 웹사이트는 기기에 연결하고 커널 드라이버나 다른 애플리케이션에서 소유하지 않은 인터페이스를 소유할 수 있습니다.

Linux

Linux는 macOS와 비슷하지만 기본적으로 대부분의 배포판은 USB 기기를 열 권한이 있는 사용자 계정을 설정하지 않습니다. udev라는 시스템 데몬은 기기에 액세스할 수 있는 사용자와 그룹을 할당하는 역할을 합니다. 이러한 규칙은 주어진 공급업체 및 제품 ID와 일치하는 기기의 소유권을 주변기기에 액세스할 수 있는 사용자의 공통 그룹인 plugdev 그룹에 할당합니다.

SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="XXXX", GROUP="plugdev"

XXXX를 기기의 16진수 공급업체 및 제품 ID로 바꿉니다. 예를 들어 ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e11"는 Nexus One 휴대전화와 일치합니다. 올바르게 인식되려면 일반적인 '0x' 접두사 없이 모두 소문자로 작성해야 합니다. 기기의 ID를 찾으려면 명령줄 도구 lsusb를 실행합니다.

이 규칙은 /etc/udev/rules.d 디렉터리의 파일에 배치해야 하며 기기가 연결되는 즉시 적용됩니다. udev를 다시 시작할 필요는 없습니다.

Android

Android 플랫폼은 Linux를 기반으로 하지만 시스템 구성을 수정할 필요가 없습니다. 기본적으로 운영체제에 내장된 드라이버가 없는 모든 기기를 브라우저에서 사용할 수 있습니다. 그러나 개발자는 사용자가 기기에 연결할 때 추가 단계가 표시된다는 점에 유의해야 합니다. 사용자가 requestDevice() 호출에 대한 응답으로 기기를 선택하면 Android는 Chrome에서 기기에 액세스하도록 허용할지 묻는 메시지를 표시합니다. 사용자가 기기에 연결할 권한이 이미 있는 웹사이트로 돌아가고 웹사이트에서 open()를 호출하는 경우에도 이 메시지가 다시 표시됩니다.

또한 기본적으로 포함되는 드라이버가 적기 때문에 Android에서 데스크톱 Linux보다 더 많은 기기에 액세스할 수 있습니다. 예를 들어 Android SDK에 직렬 기기와 통신하기 위한 API가 없으므로 USB-직렬 어댑터에서 일반적으로 구현하는 USB CDC-ACM 클래스가 누락되었습니다.

ChromeOS

ChromeOS도 Linux를 기반으로 하며 시스템 구성을 수정할 필요가 없습니다. permission_broker 서비스는 USB 기기에 대한 액세스를 제어하며, 소유권이 주장되지 않은 인터페이스가 하나 이상 있는 한 브라우저가 USB 기기에 액세스할 수 있도록 허용합니다.

Windows

Windows 드라이버 모델에는 추가 요구사항이 있습니다. 위의 플랫폼과 달리 로드된 드라이버가 없더라도 사용자 애플리케이션에서 USB 기기를 여는 기능은 기본값이 아닙니다. 대신 애플리케이션이 기기에 액세스하는 데 사용하는 인터페이스를 제공하려면 로드해야 하는 특수 드라이버인 WinUSB가 있습니다. 이는 시스템에 설치된 맞춤 드라이버 정보 파일 (INF)을 사용하거나 기기 펌웨어를 수정하여 열거 중에 Microsoft OS 호환성 설명자를 제공하는 방식으로 수행할 수 있습니다.

드라이버 정보 파일 (INF)

드라이버 정보 파일은 Windows에 기기를 처음 발견했을 때 취해야 할 조치를 알려줍니다. 사용자의 시스템에는 이미 WinUSB 드라이버가 포함되어 있으므로 INF 파일에서 공급업체 및 제품 ID를 이 새로운 설치 규칙과 연결하기만 하면 됩니다. 아래 파일은 기본 예입니다. 확장자가 .inf인 파일에 저장하고 'X'로 표시된 섹션을 변경한 다음 마우스 오른쪽 버튼으로 클릭하고 컨텍스트 메뉴에서 'Install'을 선택합니다.

[Version]
Signature   = "$Windows NT$"
Class       = USBDevice
ClassGUID   = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider    = %ManufacturerName%
CatalogFile = WinUSBInstallation.cat
DriverVer   = 09/04/2012,13.54.20.543

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%ManufacturerName% = Standard,NTx86,NTia64,NTamd64

[Standard.NTx86]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX

[Standard.NTia64]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX

[Standard.NTamd64]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX

; ========== Class definition ===========

[ClassInstall32]
AddReg = ClassInstall_AddReg

[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2

; =================== Installation ===================

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include = winusb.inf
Needs   = WINUSB.NT.Services

[USB_Install.HW]
AddReg = Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"

; =================== Strings ===================

[Strings]
ManufacturerName              = "Your Company Name Here"
ClassName                     = "Your Company Devices"
USB\MyCustomDevice.DeviceDesc = "Your Device Name Here"

[Dev_AddReg] 섹션은 기기의 DeviceInterfaceGUID 집합을 구성합니다. 애플리케이션이 Windows API를 통해 이를 찾고 연결하려면 모든 기기 인터페이스에 GUID가 있어야 합니다. New-Guid PowerShell cmdlet 또는 온라인 도구를 사용하여 임의의 GUID를 생성합니다.

개발 목적으로 Zadig 도구는 USB 인터페이스용으로 로드된 드라이버를 WinUSB 드라이버로 교체할 수 있는 간편한 인터페이스를 제공합니다.

Microsoft OS 호환성 설명자

위의 INF 파일 접근 방식은 모든 사용자의 머신을 미리 구성해야 하므로 번거롭습니다. Windows 8.1 이상에서는 맞춤 USB 설명자를 사용하여 대안을 제공합니다. 이러한 설명자는 기기가 처음에 연결될 때 Windows 운영체제에 일반적으로 INF 파일에 포함되는 정보를 제공합니다.

WebUSB 설명자를 설정하면 Microsoft의 OS 호환성 설명자도 쉽게 추가할 수 있습니다. 먼저 이 추가 플랫폼 기능 설명자로 BOS 설명자를 확장합니다. 이를 고려하도록 wTotalLengthbNumDeviceCaps를 업데이트해야 합니다.

필드 설명
Microsoft OS 2.0 플랫폼 기능 설명자
0x1C bLength 이 설명자의 크기
0x10 bDescriptorType 기기 기능 설명어
0x05 bDevCapabilityType 플랫폼 기능 설명자
0x00 bReserved
{0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} PlatformCapablityUUID 리틀엔디언 형식의 Microsoft OS 2.0 플랫폼 호환성 설명자 GUID
0x06030000 dwWindowsVersion 최소 호환 Windows 버전 (Windows 8.1)
0x00B2 wMSOSDescriptorSetTotalLength 설명어 집합의 총 길이
0x02 bMS_VendorCode 추가 Microsoft 설명자 검색을 위한 bRequest 값
0x00 bAltEnumCode 기기가 다른 열거 기능을 지원하지 않습니다.

WebUSB 설명자와 마찬가지로 이러한 설명자와 관련된 제어 전송에 사용할 bRequest 값을 선택해야 합니다. 이 예에서는 0x02를 선택했습니다. wIndex에 배치된 0x07는 기기에서 Microsoft OS 2.0 설명자 세트를 가져오는 명령어입니다.

bmRequestType bRequest wValue wIndex wLength 데이터 (응답)
0b11000000 0x02 0x0000 0x0007 * MS OS 2.0 설명자 집합

USB 기기에는 여러 기능이 있을 수 있으므로 설명자 세트의 첫 번째 부분은 다음 속성이 연결된 기능을 설명합니다. 아래 예에서는 복합 기기의 인터페이스 1을 구성합니다. 설명자는 OS에 이 인터페이스에 관한 두 가지 중요한 정보를 제공합니다. 호환 ID 설명자는 Windows에 이 기기가 WinUSB 드라이버와 호환된다고 알려줍니다. 레지스트리 속성 설명자는 위 INF 예의 [Dev_AddReg] 섹션과 유사하게 작동하며, 이 함수에 기기 인터페이스 GUID를 할당하도록 레지스트리 속성을 설정합니다.

필드 설명
Microsoft OS 2.0 설명자 세트 헤더
0x000A wLength 이 설명자의 크기
0x0000 wDescriptorType 설명어 집합 헤더 설명어
0x06030000 dwWindowsVersion 최소 호환 Windows 버전 (Windows 8.1)
0x00B2 wTotalLength 설명어 집합의 총 길이
Microsoft OS 2.0 구성 하위 집합 헤더
0x0008 wLength 이 설명자의 크기
0x0001 wDescriptorType 구성 하위 집합 헤더 설명
0x00 bConfigurationValue 구성 1에 적용 (일반적으로 1에서부터 구성 색인이 생성되었지만 0부터 색인이 생성됨)
0x00 bReserved 0으로 설정해야 합니다.
0x00A8 wTotalLength 이 헤더를 포함한 하위 집합의 총 길이
Microsoft OS 2.0 함수 하위 집합 헤더
0x0008 wLength 이 설명자의 크기
0x0002 wDescriptorType 함수 하위 집합 헤더 설명자
0x01 bFirstInterface 함수의 첫 번째 인터페이스
0x00 bReserved 0으로 설정해야 합니다.
0x00A0 wSubsetLength 이 헤더를 포함한 하위 집합의 총 길이
Microsoft OS 2.0 호환 ID 설명자
0x0014 wLength 이 설명자의 크기
0x0003 wDescriptorType 호환 ID 설명자
"WINUSB\0\0" CompatibileID 8바이트로 패딩된 ASCII 문자열
"\0\0\0\0\0\0\0\0" SubCompatibleID 8바이트로 패딩된 ASCII 문자열
Microsoft OS 2.0 레지스트리 속성 설명자
0x0084 wLength 이 설명자의 크기
0x0004 wDescriptorType 레지스트리 속성 설명자
0x0007 wPropertyDataType REG_MULTI_SZ
0x002A wPropertyNameLength 속성 이름의 길이
"DeviceInterfaceGUIDs\0" PropertyName UTF-16LE로 인코딩된 null 종료자가 있는 속성 이름
0x0050 wPropertyDataLength 속성 값의 길이
"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\0\0" PropertyData GUID와 UTF-16LE로 인코딩된 null 종결자 2개

Windows는 기기에서 이 정보를 한 번만 쿼리합니다. 기기가 유효한 설명자로 응답하지 않으면 다음에 기기가 연결될 때 다시 묻지 않습니다. Microsoft는 기기를 열거할 때 생성된 레지스트리 항목을 설명하는 USB 기기 레지스트리 항목 목록을 제공했습니다. 테스트할 때 Windows가 설명자를 다시 읽도록 하려면 기기에 대해 생성된 항목을 삭제합니다.

이러한 설명자를 사용하는 방법에 관한 자세한 내용은 Microsoft의 블로그 게시물을 참고하세요.

WebUSB 설명자와 Microsoft OS 설명자를 모두 포함하는 WebUSB 인식 기기를 구현하는 코드 예는 다음 프로젝트에서 확인할 수 있습니다.