USB 디바이스에 연결하는 방법(UWP 앱)
Windows에서는 USB 디바이스와 상호 작용하는 UWP 앱을 작성할 수 있습니다.
이 문서에서는 다음을 설명합니다.
- DeviceWatcher 개체를 사용하여 디바이스를 검색하는 방법
- 통신을 위해 디바이스를 여는 방법
- 사용이 완료되면 디바이스를 닫는 방법
중요 API
USB 디바이스와 상호 작용하는 UWP 앱을 작성할 때 앱은 제어 명령을 보내고, 디바이스 정보를 가져오고, 대량 및 인터럽트 엔드포인트에 데이터를 읽고 쓸 수 있습니다. 이 모든 작업을 수행하려면 먼저 디바이스를 찾고 연결을 설정해야 합니다.
시작하기 전에
- 이 항목은 시리즈의 첫 번째 항목입니다. 이 자습서를 시작하기 전에 이 자습서에서 확장할 수 있는 기본 Visual Studio 프로젝트를 만들어야 합니다. 자세한 내용은 UWP 앱 시작을 참조하세요 .
- 코드 예제는 CustomUsbDeviceAccess 샘플을 기반으로 합니다. 이 코드 갤러리 페이지에서 전체 샘플을 다운로드할 수 있습니다.
- 자습서에서 사용되는 USB 디바이스는 SuperMUTT 디바이스입니다.
- Windows.Devices.Usb 네임스페이스를 사용하여 USB 디바이스와 상호 작용하는 Windows 앱을 작성하려면 디바이스에 Winusb.sys 드라이버가 함수 드라이버로 로드되어 있어야 합니다. Winusb.sys Microsoft에서 제공하며 \Windows\System32\drivers 폴더의 Windows에 포함되어 있습니다.
순서도: 디바이스 찾기
USB 디바이스에 연결하려면 먼저 다양한 검색 패턴을 기반으로 디바이스를 찾은 다음 연결해야 합니다.
- 특정 디바이스 인터페이스 GUID를 사용하여 모든 USB 디바이스에 연결합니다.
- 특정 공급업체 ID 및 제품 ID와 특정 디바이스 인터페이스 GUID가 있는 USB 디바이스에 연결합니다.
- 디바이스 인터페이스 GUID를 모르고 특정 공급업체 ID 및 제품 ID를 사용하여 USB 디바이스에 연결합니다.
- 알려진 디바이스 클래스가 있는 USB 디바이스에 연결합니다.
주요 개념
디바이스 인터페이스 GUID란?
커널 모델 드라이버는 초기화하는 동안 디바이스 인터페이스 GUID라는 GUID를 등록하고 노출합니다. 일반적으로 앱은 노출된 GUID를 사용하여 연결된 드라이버와 해당 디바이스를 찾은 다음 디바이스에 대한 핸들을 엽니다. 검색된 핸들은 후속 읽기 및 쓰기 작업에 사용됩니다.
그러나 Winusb.sys 경우 드라이버가 디바이스 인터페이스 GUID를 노출하는 대신 다음 두 가지 방법 중 하나로 제공할 수 있습니다.
- 디바이스의 MS OS 설명자에서 디바이스 제조업체는 DeviceInterfaceGUID 를 디바이스의 확장 속성 설명자에서 사용자 지정 속성으로 설정합니다. 자세한 내용은 Microsoft OS 설명자의 "확장 속성 설명자" 문서를 참조하세요.
- 사용자 지정 INF를 통해 수동으로 Winusb.sys 설치한 경우 INF는 INF에 GUID를 등록했습니다. WinUSB(Winusb.sys) 설치를 참조하세요.
디바이스에 대한 디바이스 인터페이스 GUID가 발견되면 UWP 앱은 해당 디바이스 인터페이스 GUID와 일치하는 모든 디바이스를 찾을 수 있습니다.
WINDOWS에서 USB 디바이스 식별은 어떻게 표시하나요?
모든 USB 디바이스에는 공급업체 ID와 제품 ID라는 두 가지 정보가 있어야 합니다.
USB-IF는 해당 식별자를 할당하고 디바이스 제조업체는 해당 식별자를 디바이스에 노출해야 합니다. 그렇다면 어떻게 그 정보를 얻을 수 있을까요?
디바이스에 디바이스 드라이버가 로드되지 않은 경우에도, 즉 Windows에서 이를 "알 수 없는 디바이스"로 검색하는 경우에도 하드웨어 ID 속성 값의 장치 관리자 식별자를 볼 수 있습니다. 이 값은 이러한 두 식별자의 조합입니다. 예를 들어 SuperMUTT 디바이스의 경우 하드웨어 ID 는 "USB\VID_045E&PID_F001"입니다. 공급업체 ID는 "0x045E"이고 제품 ID는 "0xF001"입니다.
디바이스에 대한 INF가 있는 경우 모델 섹션에서 해당 문자열을 가져옵니다.
다양한 레지스트리 설정을 검사할 수 있습니다. 가장 쉬운 방법은 다음을 확인하는 것입니다.
<하드웨어 IDHKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\>
자세한 내용은 USB 디바이스 레지스트리 항목을 참조하세요.
하드웨어 ID는 앱 매니페스트에서 디바이스를 식별하는 데 사용됩니다.
<Device Id="vidpid:045e f001">
UWP 앱은 특정 공급업체 및 제품 ID와 일치하는 모든 디바이스를 찾을 수 있습니다. 디바이스 인터페이스 GUID를 지정하여 검색 결과의 범위를 좁힐 수 있습니다.
USB 디바이스 클래스란?
대부분의 USB 디바이스는 USB-IF에서 승인한 디바이스 클래스 사양을 준수합니다. 이러한 사양을 사용하면 비슷한 특성의 디바이스가 표준 방식으로 해당 기능을 나타낼 수 있습니다. 이 방법의 가장 큰 장점은 디바이스가 Microsoft에서 제공하는 기본 제공 드라이버 또는 일반 Winusb.sys 드라이버를 사용할 수 있다는 것입니다.
일부 디바이스는 USB-IF 사양을 따르지 않을 수 있습니다. 대신 공급업체에서 정의한 기능을 노출합니다. 이러한 디바이스의 경우 공급업체에서 디바이스 드라이버를 제공해야 하거나 Winusb.sys 사용할 수 있습니다.
디바이스가 공급업체에서 정의되거나 디바이스 클래스를 준수하는지 여부에 관계없이 이 디바이스 클래스 관련 정보를 설명해야 합니다.
- 클래스 코드: 디바이스가 속한 디바이스 클래스를 나타냅니다.
- 하위 클래스 코드: 디바이스 클래스 내에서 는 디바이스의 하위 클래스를 나타냅니다.
- 프로토콜 코드: 디바이스에서 사용하는 프로토콜입니다.
예를 들어 SuperMUTT 디바이스는 공급업체에서 정의한 디바이스이며 해당 정보는 클래스 코드에서 FF로 표시됩니다. 디바이스에서 클래스 코드를 FEh로, 서브클래스 코드를 02h로 표시하고 프로토콜 코드 00h를 표시하는 경우 디바이스가 클래스 규격 IrDA 브리지 디바이스라는 결론을 내릴 수 있습니다. UWP 앱은 다음 디바이스 클래스에 속하는 디바이스와 통신할 수 있습니다.
- ActiveSync
- CdcControl
- DeviceFirmwareUpdate
- IrDA
- 측정
- PalmSync
- PersonalHealthcare
- 물리적
- VendorSpecific
UWP 앱은 특정 클래스, 하위 클래스 및 프로토콜 코드 집합과 일치하는 모든 디바이스를 찾을 수 있습니다.
디바이스에 대한 AQS(고급 쿼리 구문) 문자열 가져오기
검색하려는 디바이스에 대한 식별 정보가 포함된 AQS(고급 쿼리 문자열)를 생성합니다. 공급업체/제품 ID, 디바이스 인터페이스 GUID 또는 디바이스 클래스를 지정하여 문자열을 생성할 수 있습니다.
공급업체 ID/제품 ID 또는 디바이스 인터페이스 GUID를 제공하려면 GetDeviceSelector의 오버로드를 호출합니다.
SuperMUTT 디바이스의 예제에서 GetDeviceSelector 는 이 문자열과 유사한 AQS 문자열을 검색합니다.
"System.Devices.InterfaceClassGuid:="{DEE824EF-729B-4A0E-9C14-B7117D33A817}" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND System.DeviceInterface.WinUsb.UsbVendorId:=1118 AND System.DeviceInterface.WinUsb.UsbProductId:=61441"
참고 문자열에 표시되는 디바이스 인터페이스 GUID는 지정한 GUID가 아닙니다. 해당 GUID는 UWP 앱에 대해 Winusb.sys 등록된 실제 디바이스 인터페이스 GUID입니다.
디바이스 또는 해당 클래스, 하위 클래스 및 프로토콜 코드의 디바이스 클래스를 알고 있는 경우 GetDeviceClassSelector 를 호출하여 AQS 문자열을 생성합니다.
ClassCode, SubclassCode 및 ProtocolCode 속성 값을 지정하여 UsbDeviceClass 개체를 만듭니다. 또는 디바이스의 디바이스 클래스를 알고 있는 경우 특정 UsbDeviceClasses 속성을 지정하여 생성자를 호출할 수 있습니다.
디바이스 찾기 - 기본 방법
USB 디바이스를 찾는 가장 간단한 방법입니다. 자세한 내용은 빠른 시작: 일반적으로 사용되는 디바이스 열거를 참조하세요.
- 검색된 AQS 문자열을 FindAllAsync에 전달합니다. 호출은 DeviceInformationCollection 개체를 검색합니다.
- 컬렉션을 반복합니다. 각 반복은 DeviceInformation 개체를 가져옵니다.
- DeviceInformation.Id 속성 값을 가져옵니다. 문자열 값은 디바이스 instance 경로입니다. 예를 들어 "\\\\?\\USB#VID_045E&PID_078F#6&1b8ff026&0&5#{dee824ef-729b-4a0e-9c14-b7117d33a817}"입니다.
- 디바이스 instance 문자열을 전달하여 FromIdAsync를 호출하고 UsbDevice 개체를 가져옵니다. 그런 다음 , UsbDevice 개체를 사용하여 컨트롤 전송 전송과 같은 다른 작업을 수행할 수 있습니다. 앱이 UsbDevice 개체 사용을 완료하면 앱은 Close를 호출하여 해제해야 합니다. 참고 UWP 앱이 일시 중단되면 디바이스가 자동으로 닫힙니다. 향후 작업에 부실 핸들을 사용하지 않도록 하려면 앱에서 UsbDevice 참조를 해제해야 합니다.
private async void OpenDevice()
{
UInt32 vid = 0x045E;
UInt32 pid = 0x0611;
string aqs = UsbDevice.GetDeviceSelector(vid, pid);
var myDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);
try
{
usbDevice = await UsbDevice.FromIdAsync(myDevices[0].Id);
}
catch (Exception exception)
{
ShowStatus(exception.Message.ToString());
}
finally
{
ShowStatus("Opened device for communication.");
}
}
DeviceWatcher를 사용하여 디바이스 찾기
또는 디바이스를 동적으로 열거할 수 있습니다. 그런 다음 디바이스가 추가 또는 제거되거나 디바이스 속성이 변경되면 앱에서 알림을 받을 수 있습니다. 자세한 내용은 디바이스가 추가, 제거 또는 변경된 경우 알림을 받는 방법을 참조하세요.
DeviceWatcher 개체를 사용하면 앱이 시스템에서 추가 및 제거될 때 디바이스를 동적으로 검색할 수 있습니다.
디바이스가 시스템에 추가되거나 시스템에서 제거되는 시기를 감지하는 DeviceWatcher 개체를 만듭니다. CreateWatcher를 호출하고 AQS 문자열을 지정하여 개체를 만들어야 합니다.
DeviceWatcher 개체에서 추가 및 제거된 이벤트에 대한 처리기를 구현하고 등록합니다. 이러한 이벤트 처리기는 동일한 식별 정보가 있는 디바이스가 시스템에서 추가되거나 제거될 때 호출됩니다.
DeviceWatcher 개체를 시작하고 중지합니다.
앱은 디바이스가 시스템에서 추가되거나 제거될 때 검색을 시작할 수 있도록 Start를 호출하여 DeviceWatcher 개체를 시작해야 합니다. 반대로 앱은 디바이스를 더 이상 검색할 필요가 없는 경우 Stop을 호출하여 DeviceWatcher를 중지해야 합니다. 샘플에는 사용자가 DeviceWatcher를 시작하고 중지할 수 있는 두 개의 단추가 있습니다.
이 코드 예제에서는 SuperMUTT 디바이스의 인스턴스를 찾기 위해 디바이스 감시자를 만들고 시작하는 방법을 보여 줍니다.
void CreateSuperMuttDeviceWatcher(void)
{
UInt32 vid = 0x045E;
UInt32 pid = 0x0611;
string aqs = UsbDevice.GetDeviceSelector(vid, pid);
var superMuttWatcher = DeviceInformation.CreateWatcher(aqs);
superMuttWatcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>
(this.OnDeviceAdded);
superMuttWatcher.Removed += new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>
(this.OnDeviceRemoved);
superMuttWatcher.Start();
}
디바이스 열기
디바이스를 열려면 앱이 정적 메서드 FromIdAsync를 호출하고 디바이스 instance 경로(DeviceInformation.Id)를 전달하여 비동기 작업을 시작해야 합니다. 해당 작업 가져오기의 결과는 데이터 전송 수행과 같은 디바이스와의 향후 통신에 사용되는 UsbDevice 개체입니다.
UsbDevice 개체 사용을 완료한 후에는 해제해야 합니다. 개체를 해제하면 보류 중인 모든 데이터 전송이 취소됩니다. 이러한 작업에 대한 완료 콜백 루틴은 여전히 취소된 오류 또는 작업이 완료된 상태로 호출됩니다.
C++ 앱은 삭제 키워드(keyword) 사용하여 참조를 해제해야 합니다. C#/VB 앱 은 UsbDevice.Dispose 메서드를 호출해야 합니다. JavaScript 앱 은 UsbDevice.Close를 호출해야 합니다.
디바이스가 사용 중이거나 찾을 수 없는 경우 FromIdAsync 가 실패합니다.