다음을 통해 공유


드라이버 저장소에서 실행

'드라이버 저장소에서 실행'을 사용하는 INF는 INF가 DIRID 13을 사용하여 설치 시 드라이버 패키지 파일의 위치를 지정한다는 것을 의미합니다.

INF에 의해 페이로드된 '드라이버 저장소에서 실행' 파일의 경우 INF의 파일에 대한 SourceDisksFiles 항목에 나열된 하위 디렉터리가 INF의 파일에 대한 DestinationDirs 항목에 나열된 하위 디렉터리와 일치해야 합니다.

또한 CopyFiles 지시문을 사용하여 드라이버 저장소에서 실행되는 파일의 이름을 바꿀 수 없습니다. 디바이스에 INF를 설치해도 드라이버 저장소 디렉터리에 새 파일이 생성되지 않도록 이러한 제한 사항이 필요합니다.

SourceDisksFiles 항목에는 동일한 파일 이름을 가진 여러 항목이 있을 수 없으며 CopyFiles를 사용하여 파일 이름을 바꿀 수 없으므로 INF 참조에 고유한 파일 이름이 있어야 하는 모든 '드라이버 저장소에서 실행' 파일입니다.

드라이버 패키지는 Windows 10 1709부터 '드라이버 스토어에서 실행'을 일반적으로 지원합니다. 그러나 특정 디바이스 스택은 해당 스택에 해당 플러그를 제공해야 하는 파일에 추가 제한을 적용할 수 있습니다. Windows 10 1803까지 '드라이버 스토어에서 실행'을 지원하지 않는 디바이스 스택이 몇 가지 예입니다.

  • UMDF 드라이버 이진 파일: 자세한 내용은 UMDF 드라이버 의 로딩 위치 제한 참조

  • UEFI 펌웨어 업데이트: 자세한 내용은 업데이트 드라이버 패키지 작성을 참조하세요.

특정 디바이스 스택에 연결하는 이진 파일을 제공하는 경우 이진 파일에 대한 전체 파일 경로 제공을 지원하고 전체 파일 경로에 제한이 있는 경우 검사 연결하려는 특정 디바이스 스택에 대한 설명서를 참조하세요. 해당 경로에 대한 제한 없이 이진 파일에 대한 전체 파일 경로 제공을 지원하는 경우 '드라이버 저장소에서 실행'되는 파일을 지원해야 합니다.

드라이버 저장소에서 동적으로 파일 찾기 및 로드

경우에 따라 구성 요소가 '드라이버 스토어에서 실행'을 사용하는 드라이버 패키지의 일부인 파일을 로드해야 합니다. 이러한 드라이버 패키지 파일의 경로는 서로 다른 버전의 드라이버 패키지, 다른 OS 버전, 다른 OS 버전 간에 다를 수 있으므로 하드 코딩해서는 안 됩니다. 드라이버 패키지 파일을 로드해야 하는 경우 아래에 설명된 몇 가지 패러다임을 사용하여 이러한 드라이버 패키지 파일을 검색하고 동적으로 로드해야 합니다.

동일한 드라이버 패키지에서 파일 찾기 및 로드

드라이버 패키지의 파일이 동일한 드라이버 패키지에서 다른 파일을 로드해야 하는 경우 해당 파일을 동적으로 검색하는 한 가지 잠재적인 옵션은 이 파일이 실행 중인 디렉터리를 확인하고 해당 디렉터리를 기준으로 다른 파일을 로드하는 것입니다.

드라이버 패키지에서 다른 파일에 액세스해야 하는 Windows 10 버전 1803 이상의 드라이버 저장소에서 실행되는 WDM 또는 KMDF 드라이버는 드라이버가 로드된 디렉터리 경로를 가져오기 위해 디렉터리 유형으로 DriverDirectoryImage를 사용하여 IoGetDriverDirectory를 호출해야 합니다. 또는 Windows 10 버전 1803 이전 OS 버전을 지원해야 하는 드라이버의 경우 IoQueryFullDriverPath를 사용하여 드라이버의 경로를 찾고, 로드된 디렉터리 경로를 가져와서 해당 경로에 상대적인 파일을 찾습니다. 커널 모드 드라이버가 KMDF 드라이버인 경우 WdfDriverWdmGetDriverObject를 사용하여 IoQueryFullDriverPath에 전달할 WDM 드라이버 개체를 검색할 수 있습니다.

사용자 모드 이진 파일은 GetModuleHandleExW GetModuleFileNameW를 사용하여 이진 파일이 로드된 위치를 확인할 수 있습니다. 예를 들어 UMDF 드라이버 이진 파일은 다음과 같은 작업을 수행할 수 있습니다.

bRet = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
                         (PCWSTR)&DriverEntry,
                         &handleModule);
if (bRet) {
    charsWritten = GetModuleFileNameW(handleModule,
                                      path,
                                      pathLength);
    …

드라이버 패키지에서 파일 찾기 및 로드

일부 시나리오에서는 드라이버 패키지에 다른 드라이버 패키지의 이진 파일 또는 사용자 모드 구성 요소에 의해 로드될 파일이 포함될 수 있습니다. 이 메서드는 동일한 드라이버 패키지에서 파일을 로드하기 위해 위에서 설명한 방법보다 선호하는 경우 동일한 드라이버 패키지의 파일에도 사용할 수 있습니다.

다음은 드라이버 패키지에서 파일을 로드하는 시나리오의 몇 가지 예입니다.

이러한 경우 드라이버 패키지는 로드될 것으로 예상되는 파일의 경로를 나타내는 디바이스 또는 디바이스 인터페이스에서 일부 상태를 설정해야 합니다.

드라이버 패키지는 일반적으로 HKR AddReg 를 사용하여 이 상태를 설정합니다. 이 예제에서는 드라이버 패키지ExampleFile.dll하위 디렉터가 없는 SourceDisksFiles 항목이 있다고 가정해야 합니다. 그러면 파일이 드라이버 패키지 디렉터리의 루트에 있습니다. CopyFiles 지시문의 DestinationDirs가 dirid 13을 지정한다고 가정해야 합니다.

디바이스 상태로 설정하기 위한 INF 예제는 다음과 같습니다.

[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg

[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

이를 디바이스 인터페이스 상태로 설정하는 INF 예제는 다음과 같습니다.

[ExampleDDInstall.Interfaces]
AddInterface = {<fill in an interface class GUID for an interface exposed by the device>},,Example_Add_Interface_Section

[Example_Add_Interface_Section]
AddReg = Example_Add_Interface_Section.AddReg

[Example_Add_Interface_Section.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

이전 예제에서는 빈 플래그 값을 사용하여 레지스트리 값을 REG_SZ. 이로 인해 %13%가 정규화된 사용자 모드 파일 경로로 전환됩니다. 대부분의 경우 경로가 환경 변수를 기준으로 하는 것이 좋습니다. 0x20000 플래그 값을 사용하는 경우 레지스트리 값은 REG_EXPAND_SZ 형식이고 %13%는 적절한 환경 변수가 있는 경로로 변환하여 경로의 위치를 추상화합니다. 이 레지스트리 값을 검색할 때 ExpandEnvironmentStrings를 호출하여 경로의 환경 변수를 확인합니다.

커널 모드 구성 요소에서 값을 읽어야 하는 경우 값은 REG_SZ 값이어야 합니다. 커널 모드 구성 요소가 해당 값을 읽는 경우 ZwOpenFile과 같은 API에 전달하기 전에 앞에 와 \??\ 야 합니다.

디바이스 상태의 일부일 때 이 설정에 액세스하려면 먼저 애플리케이션에서 디바이스의 ID를 찾아야 합니다. 사용자 모드 코드는 CM_Get_Device_ID_List_SizeCM_Get_Device_ID_List 사용하여 필요에 따라 필터링된 디바이스 목록을 가져올 수 있습니다. 해당 디바이스 목록에는 여러 디바이스가 포함될 수 있으므로 디바이스에서 상태를 읽기 전에 적절한 디바이스를 검색합니다. 예를 들어 CM_Get_DevNode_Property 호출하여 특정 조건과 일치하는 디바이스를 검색할 때 디바이스에서 속성을 검색합니다.

올바른 디바이스가 발견되면 CM_Open_DevNode_Key 호출하여 디바이스 상태가 저장된 레지스트리 위치에 대한 핸들을 가져옵니다.

커널 모드 코드는 상태를 사용하여 디바이스에 대한 PDO(물리적 디바이스 개체)를 검색하고 IoOpenDeviceRegistryKey를 호출해야 합니다. 커널 모드 코드가 디바이스의 PDO를 검색하는 한 가지 가능한 방법은 디바이스에서 노출하는 활성화된 인터페이스를 검색하고 IoGetDeviceObjectPointer를 사용하여 디바이스 개체를 검색하는 것입니다.

디바이스 인터페이스 상태일 때 이 설정에 액세스하기 위해 사용자 모드 코드는 CM_Get_Device_Interface_List_Size 호출하고 CM_Get_Device_Interface_List 수 있습니다.

또한 CM_Register_Notification 사용하여 디바이스 인터페이스의 도착 및 제거에 대한 알림을 받을 수 있으므로 인터페이스를 사용하도록 설정한 후 상태를 검색할 때 코드에 알림을 받을 수 있습니다. 위의 API에서 사용되는 디바이스 인터페이스 클래스에 여러 디바이스 인터페이스가 있을 수 있습니다. 이러한 인터페이스를 검사하여 읽을 설정에 대한 올바른 인터페이스를 확인합니다.

올바른 디바이스 인터페이스가 발견되면 CM_Open_Device_Interface_Key 호출합니다.

커널 모드 코드는 상태를 가져올 디바이스 인터페이스에 대한 기호 링크 이름을 검색할 수 있습니다. 이렇게 하려면 IoRegisterPlugPlayNotification을 호출하여 적절한 디바이스 인터페이스 클래스에 디바이스 인터페이스 알림을 등록합니다. 또는 IoGetDeviceInterfaces를 호출하여 시스템의 현재 디바이스 인터페이스 목록을 가져옵니다. 위의 API에서 사용되는 디바이스 인터페이스 클래스에 여러 디바이스 인터페이스가 있을 수 있습니다. 이러한 인터페이스를 검사하여 읽을 설정이 있어야 하는 올바른 인터페이스를 확인합니다.

적절한 기호 링크 이름이 발견되면 IoOpenDeviceInterfaceRegistryKey를 호출하여 디바이스 인터페이스 상태가 저장된 레지스트리 위치에 대한 핸들을 검색합니다.

참고 항목

CM_Get_Device_ID_List_Size CM_Get_Device_ID_List CM_GETIDLIST_FILTER_PRESENT 플래그를 사용하거나 CM_Get_Device_Interface_List_Size CM_Get_Device_Interface_List CM_GET_DEVICE_INTERFACE_LIST_PRESENT 플래그를 사용합니다. 이렇게 하면 파일 경로가 포함된 상태와 관련된 하드웨어가 존재하고 통신할 준비가 됩니다.

드라이버 패키지 제거

기본적으로 드라이버 패키지는 디바이스에 여전히 설치되어 있는 경우 시스템에서 제거할 수 없습니다. 그러나 시스템에서 드라이버 패키지를 제거하는 일부 옵션을 사용하면 '강제' 제거를 시도할 수 있습니다. 이렇게 하면 해당 드라이버 패키지가 시스템의 일부 디바이스에 여전히 설치되어 있더라도 드라이버 패키지를 제거하려고 합니다. '드라이버 스토어에서 실행'되는 파일이 있는 드라이버 패키지에는 강제 제거가 허용되지 않습니다. 드라이버 패키지가 시스템에서 제거되면 드라이버 저장소 콘텐츠가 제거됩니다. 해당 드라이버 패키지와 함께 설치된 디바이스가 있는 경우 해당 드라이버 패키지의 모든 '드라이버 저장소에서 실행' 파일이 사라지고 누락된 파일로 인해 해당 디바이스가 오작동할 수 있습니다. 디바이스가 잘못된 상태로 전환되는 것을 방지하기 위해 '드라이버 스토어에서 실행' 파일이 포함된 드라이버 패키지를 강제로 제거할 수 없습니다. 디바이스에 더 이상 설치되지 않은 경우에만 제거할 수 있습니다. 이러한 드라이버 패키지 의 제거를 지원하기 위해 DiUninstallDriver 또는 pnputil /delete-driver <oem#.inf> /uninstall 을 사용할 수 있습니다. 이러한 제거 방법은 먼저 제거되는 드라이버 패키지를 사용하여 디바이스를 업데이트하여 드라이버 패키지를 제거하기 전에 해당 드라이버 패키지와 함께 더 이상 설치되지 않도록 합니다.

드라이버 패키지 개발

프라이빗 이진 파일 테스트

드라이버 패키지를 개발할 때 시스템에서 드라이버 패키지를 완전히 다시 빌드하고 교체하는 대신 드라이버 패키지의 특정 실행 파일을 프라이빗 버전으로 바꿔야 하는 경우 커널 디버거를 .kdfiles 명령과 함께 사용하는 것이 좋습니다. 드라이버 저장소의 파일에 대한 전체 경로를 하드 코딩하면 안 되므로 .kdfiles 매핑 에서 OldDriver 파일 이름은 이전 경로 정보가 없는 파일의 직접 이름일 뿐입니다. 이를 용이하게 하기 위해(및 기타 시나리오) 드라이버 패키지의 파일 이름은 시스템의 관련 없는 드라이버 패키지의 파일 이름과 일치하지 않도록 가능한 한 고유해야 합니다.

드라이버 저장소에서 실행을 사용하도록 INF 포팅

드라이버 저장소에서 실행을 사용하지 않고 드라이버 저장소에서 실행을 사용하도록 포팅하는 INF가 있는 기존 드라이버 패키지가 있는 경우 다음 예제에서는 INF의 일반적인 파일 사용량과 DriverStore에서 실행할 파일을 업데이트하는 패턴을 보여 줍니다.

대상 디렉터리 업데이트에 대한 빠른 참조

다음 표에서는 드라이버 패키지 INF가 파일에 대해 지정하는 현재 대상 디렉터리 DIRID 를 기반으로 적절한 지침을 찾기 위한 빠른 참조를 제공합니다.

DIRID 하위 디렉터리 세부 정보
13 파일이 이미 '드라이버 스토어에서 실행'을 사용하고 있습니다. 더 이상 작업이 필요하지 않습니다.
1 DIRID 1을 사용하면 안 됩니다. 파일에 대한 참조를 확인해야 하는 경우 원본 디렉터리를 사용할 수 있다는 보장은 없습니다. 대신 드라이버 패키지의 구성 요소가 특정 파일에 의존하는 경우 드라이버 패키지에 해당 파일을 포함하고 드라이버 저장소에서 실행합니다.
10 펌웨어 DIRID 13을 펌웨어 업데이트 드라이버 패키지와 함께 사용하여 '드라이버 스토어에서 실행'을 사용하는 방법에 대한 자세한 내용은 업데이트 드라이버 패키지 작성을 참조하세요.
10 다른 파일을 참조하세요.
11 다른 파일을 참조하세요.
12 Umdf UMDF 드라이버 이진을 참조하세요.
12 DIRID 12의 대상이 있는 대부분의 파일은 드라이버 서비스 이진 파일을 나타냅니다. 서비스 이진을 참조하세요.
16422, 16426, 16427, 16428 이러한 DIRID의 대상이 있는 대부분의 파일은 애플리케이션 설치를 나타냅니다. 대신 UWP(유니버설 Windows 플랫폼) 애플리케이션을 제공하고 드라이버 패키지 INF의 DDInstall.Software 섹션에서 AddSoftware 지시문을 사용하여 설치합니다. 자세한 내용은 UWP(유니버설 Windows 플랫폼) 앱과 드라이버 페어링을 참조하세요.

서비스 이진

INF에서 서비스를 추가하고 이진 파일이 드라이버 저장소에서 실행되지 않는 경우 INF는 다음과 같습니다.

[DestinationDirs]
 ; Copy the file to %windir%\system32\drivers
 Example_CopyFiles = 12

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the file in %windir%\system32\drivers
ServiceBinary = %12%\ExampleBinary.sys

드라이버 저장소에서 실행되도록 이 파일을 이동하려면 파일이 복사되는 위치의 DestinationDirs 항목을 업데이트하고 이 파일의 위치를 참조하는 ServiceBinary 지시문을 업데이트해야 합니다.

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleBinary.sys

UMDF 드라이버 이진

INF에서 UMDF 드라이버를 추가하고 이진 파일이 드라이버 저장소에서 실행되지 않는 경우 INF는 다음과 같이 표시할 수 있습니다.

[DestinationDirs]
; Copy the file to %windir%\system32\drivers\UMDF
Example_CopyFiles = 12, UMDF

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the file in %windir%\system32\drivers\UMDF
ServiceBinary = %12%\UMDF\ExampleUmdfDriver.dll
...

드라이버 저장소에서 실행되도록 이 파일을 이동하려면 파일이 복사되는 위치의 DestinationDirs 항목을 업데이트하고 이 파일의 위치를 참조하는 ServiceBinary 지시문을 업데이트해야 합니다.

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleUmdfDriver.dll
...

기타 파일

INF가 다른 구성 요소에 의해 로드될 수 있고 드라이버 스토어에서 실행되지 않는 파일을 추가하는 경우 INF는 다음과 같을 수 있습니다. 이 예제에서는 파일 이름만 디바이스의 레지스트리 상태에 기록됩니다. 로드할 %windir%\system32 파일을 결정하기 위해 이 레지스트리 값을 읽거나 파일을 찾을 수 있는 LoadLibrary의 검색 순서에 따라 로드할 파일을 결정하는 구성 요소입니다.

[DestinationDirs]
; Copy the file to %windir%\system32
Example_CopyFiles = 11

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
HKR,,FileLocation,,"ExampleFile.dll"

드라이버 저장소에서 실행되도록 이 파일을 이동하려면 파일이 복사될 위치에 대한 DestinationDirs 항목을 업데이트하고 디바이스의 상태에 저장된 위치를 업데이트해야 합니다. 이렇게 하려면 레지스트리 값을 읽는 구성 요소가 해당 레지스트리 값을 상대적인 파일이 아닌 파일의 전체 경로로 처리할 수 있어야 합니다 %windir%\system32.

[DestinationDirs]
Example_CopyFiles = 13 ; update the destination to DIRID 13

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
; Point at the run from Driver Store file using DIRID 13
HKR,,FileLocation,,"%13%\ExampleFile.dll"