디바이스와 상호 작용하는 Win32 서비스

동기 부여:

디바이스와 상호 작용하는 INF AddService 를 통해 설치된 이상적인 Win32 서비스는 드라이버디바이스와 상호 작용하는 방식과 유사하게 작동합니다. 디바이스의 존재에 따라 드라이버가 로드되고 언로드되며, 디바이스와 상호 작용하는 Win32 서비스는 디바이스의 존재에 따라 이와 동일한 시작중지 패턴을 따라야 합니다.

서비스는 연결된 디바이스가 더 이상 존재하지 않을 때 디바이스 인터페이스가 상호 작용하고 중지된 경우에만 시작해야 합니다. 이 디자인 패턴은 원치 않는 동작과 정의되지 않은 동작을 최소화하는 강력한 서비스를 보장합니다. 이 패턴을 따르도록 서비스를 디자인하는 방법을 살펴보겠습니다.

서비스 설치

서비스를 설치하려면 INF AddService 지시문을 사용합니다. 이렇게 하면 서비스를 만들고 시작할 수 있습니다.

서비스 요청 시작을 만드는 플래그를 추가합니다. 이 작업은 서비스 트리거를 시작하는 StartType=0x3 설정하여 수행할 수 있습니다.

이 섹션의 마지막 단계는 AddTrigger 지시문을 사용하여 디바이스 인터페이스가 도착할 때 서비스를 시작하도록 하는 것입니다(AddTrigger에 대한 자세한 내용은 AddService 참조). 다음은 AddTrigger를 사용하는 방법의 예입니다.

[UserSvc_AddTrigger]
TriggerType = 1                                   ; SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL
Action      = 1                                   ; SERVICE_TRIGGER_ACTION_SERVICE_START
SubType     = %GUID_DEVINTERFACE_OSRFX2%          ; Interface class GUID
DataItem    = 2, "USB\VID_0547&PID_1002"          ; SERVICE_TRIGGER_DATA_TYPE_STRING

[UserSvc_Install]
ServiceType   = 0x10 ; SERVICE_WIN32_OWN_PROCESS
StartType     = 3   ; SERVICE_DEMAND_START
ErrorControl  = 0   ; SERVICE_ERROR_IGNORE
ServiceBinary = %13%\oemsvc.exe
AddTrigger    = UserSvc_AddTrigger

DataItem에 지정된 HardwareId는 선택 사항이며 일반적으로 트리거 범위를 보다 구체적인 디바이스로 지정하기 위해 제네릭 클래스 인터페이스를 사용하는 경우에만 필요합니다.

서비스 런타임

런타임 관점에서 서비스의 첫 번째 단계는 디바이스 인터페이스 알림을 등록하는 것입니다. 이 작업을 수행하는 방법에 대한 규범적인 지침은 디바이스 인터페이스 도착 및 디바이스 제거 알림 등록 페이지에서 찾을 수 있습니다.

특히 CM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE 플래그와 함께 CM_Register_Notification 사용하여 디바이스 인터페이스 알림의 적절한 등록을 수행해야 합니다.

참고

서비스가 시작되면 도착 알림이 이미 통과되었을 수 있으므로 디바이스 인터페이스 알림을 받게 된다는 사실에 의존할 수 없습니다. 대신, 이미 인터페이스가 있는지 확인하기 위해 디바이스 인터페이스 목록을 가져와야 합니다.

알림을 등록한 후에는 다음 두 단계에서 원하는 디바이스 인터페이스를 찾을 수 있습니다.

  1. 알림 콜백에서 인터페이스 검색
  2. 기존 디바이스 인터페이스 목록을 쿼리하고 CM_Get_Device_Interface_List 사용하여 원하는 인터페이스를 찾습니다.

참고

알림 등록과 원하는 디바이스 인터페이스 찾기 사이에 인터페이스가 도착할 가능성이 있습니다. 이 경우 인터페이스는 알림 콜백과 인터페이스 목록 모두에 나열됩니다.

원하는 디바이스 인터페이스를 찾았으면 CreateFile을 통해 인터페이스에 대한 핸들을 엽니다.

다음 단계는 디바이스를 작동하고 관리하기 위해 보조 인터페이스별 알림을 등록하는 것입니다. 이 작업은 CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE 플래그와 함께 CM_Register_Notification 사용하여 수행할 수 있습니다. 이렇게 하면 디바이스가 사라지면 핸들을 적절하게 해제할 수 있습니다.

마지막 디바이스 인터페이스를 제거하면 서비스를 중지할 수 있도록 디바이스 인터페이스 도착 및 제거를 추적해야 합니다. 마지막 인터페이스가 제거되면 서비스를 중지합니다(자세한 내용은 이 페이지에서 찾을 수 있습니다). 이 작업은 다음 단계를 수행하여 수행할 수 있습니다.

  1. SCM에 SERVICE_STOP_PENDING 상태를 게시하여 서비스가 중단되고 있음을 나타냅니다.
  2. 서비스에서 사용하던 모든 항목을 유니티리얼화/정리
  3. SCM에 SERVICE_STOP 상태를 게시하여 중지 작업을 완료합니다.

서비스가 중지되는 경우 기존에 열려 있는 모든 핸들을 확인하고 디바이스 인터페이스(없음이 있을 수 있음)로 이동하여 정리해야 합니다.

디바이스 인터페이스는 디바이스 설치, 디바이스 사용/사용 안 함, 디바이스 다시 열거, 시스템 다시 부팅 중 또는 나열되지 않은 다른 시나리오 중에 다시 돌아올 수 있습니다. 디바이스 인터페이스가 다시 돌아오면 트리거 시작 등록에 따라 서비스가 트리거가 시작됩니다.

이 흐름은 서비스가 디바이스 인터페이스 도착 시 시작되고 마지막 디바이스 인터페이스가 더 이상 존재하지 않을 때 중지되도록 합니다.

GitHub 대한 샘플은 서비스에서 이러한 이벤트 흐름을 활용하는 방법을 안내합니다. 샘플은 Win32 서비스 샘플에서 찾을 수 있습니다.

또한 AddService 페이지에서 AddTrigger와 관련된 유용한 설명서를 찾을 수 있습니다.