Share via


從驅動程式存放區執行

使用「從驅動程式存放區執行」的 INF 表示 INF 會使用 DIRID 13 來指定安裝時驅動程式套件檔案的位置

針對由 INF 裝載的「從驅動程式存放區執行」檔案,INF 中檔案的 SourceDisksFiles 專案中列出的子文件必須符合 INF 中檔案的 DestinationDirs 專案中列出的子檔。

此外, CopyFiles 指示詞無法用來重新命名從驅動程式存放區執行的檔案。 這些限制是必要的,如此一來,裝置上的 INF 安裝就不會導致在驅動程式存放區目錄中建立新的檔案。

由於 SourceDisksFiles 專案不能有多個具有相同檔名的專案,而且 CopyFiles 無法用來重新命名檔案,因此 INF 參考的每個「從驅動程式存放區執行」檔案都必須有唯一的檔名。

從 Windows 10 1709 開始,驅動程式套件具有「從驅動程式市集執行」的一般支援。 不過,某些裝置堆疊可能會對您需要提供該外掛程式到該堆疊的檔案進行額外限制。 例如,這些裝置堆疊在 Windows 10 1803 之前不支援「從驅動程式市集執行」:

如果提供插入特定裝置堆疊的二進位檔,請參閱您要插入的特定裝置堆疊檔,以檢查它是否支援提供完整檔案路徑給二進位檔,以及該完整檔案路徑是否有任何限制。 如果支援提供完整檔案路徑給二進位檔,但該路徑沒有任何限制,則它應該支援「從驅動程式存放區執行」的檔案。

從驅動程式存放區動態尋找和載入檔案

有時候,元件需要載入使用「從驅動程式存放區執行」之驅動程式套件的檔案。 這些驅動程式套件檔案的路徑不應該硬式編碼,因為它們在不同版本的驅動程式套件、不同的OS版本、不同的OS版本等之間可能不同。當這類需要載入驅動程式套件檔案時,應該使用以下所述的一些範例,以動態方式探索和載入這些驅動程式套件檔案。

尋找並載入相同驅動程式套件中的檔案

當驅動程式套件中的檔案需要從相同的驅動程式套件載入另一個檔案時,動態探索該檔案的其中一個可能選項是判斷此檔案執行所在的目錄,以及載入相對於該目錄的其他檔案。

從 Windows 10 版本 1803 和更新版本上從驅動程式存放區執行的 WDM 或 KMDF 驅動程式,需要從其驅動程式套件存取其他檔案,應呼叫具有 DriverDirectoryImage 的 IoGetDriverDirectory 作為目錄類型,以取得驅動程式從中載入的目錄路徑。 或者,對於需要支援 Windows 10 版本 1803 之前作業系統版本的驅動程式,請使用 IoQueryFullDriverPath 尋找驅動程式的路徑、取得載入的目錄路徑,以及尋找相對於該路徑的檔案。 如果核心模式驅動程式是 KMDF 驅動程式,則可以使用 WdfDriverWdmGetDriverObject 來擷取要傳遞至 IoQueryFullDriverPath 的 WDM 驅動程序物件。

使用者模式二進位檔可以使用 GetModuleHandleExWGetModuleFileNameW 來判斷從何處載入二進位檔。 例如,UMDF 驅動程式二進位檔可能會執行類似下列動作:

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

尋找並載入任何驅動程式套件中的檔案

在某些情況下,驅動程式套件可能包含要由另一個驅動程式套件或使用者模式元件中的二進位檔載入的檔案。 如果這是慣用於上述方法,以從相同驅動程式套件載入檔案,這個方法也可以用於來自相同驅動程式套件的檔案。

以下是幾個可能涉及從驅動程式套件載入檔案的案例範例:

  • 驅動程式套件中的使用者模式 DLL 提供與驅動程式套件中驅動程式通訊的介面。

  • 擴充驅動程式套件包含驅動程式在基底驅動程式套件中載入的組態檔。

在這些情況下,驅動程式套件應該在裝置或裝置介面上設定一些狀態,指出預期要載入的檔案路徑。

驅動程式套件通常會使用 HKR AddReg 來設定此狀態。 在此範例中,應該假設針對 ExampleFile.dll,驅動程式套件具有不含 subdir 的 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值。 當核心模式元件讀取該值時,應該先加上\??\它,再將它傳遞給 ZwOpenFileAPI。

若要在裝置屬於裝置狀態的一部分時存取此設定,首先應用程式必須尋找裝置的身分識別。 使用者模式程式代碼可以使用 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_SizeCM_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 旗標。 這可確保與包含檔案路徑的狀態相關的硬體已存在,且已準備好進行通訊。

拿掉驅動程式套件

根據預設,如果驅動程式套件仍安裝在任何裝置上,就無法從系統中移除。 不過,從系統移除驅動程式套件的一些選項允許嘗試移除驅動程式套件。 即使該驅動程式套件仍安裝在系統上的某些裝置上,這仍會嘗試移除驅動程式套件。 對於具有「從驅動程式存放區執行」的任何檔案的驅動程式套件,不允許強制移除。 從系統移除驅動程式套件時,會移除其驅動程式存放區內容。 如果有任何裝置仍與該驅動程式套件一起安裝,該驅動程式套件中的任何「從驅動程式存放區執行」檔案現在都會消失,而遺失的檔案可能會導致該裝置故障。 為了避免將裝置置於這類狀況不佳的狀態,無法強制移除包含任何「從驅動程式存放區執行」檔案的驅動程式套件。 它們只能在任何裝置上不再安裝之後移除。 為了協助移除這類驅動程式套件,可以使用 DiUninstallDriverpnputil /delete-driver <oem#.inf> /uninstall 這些移除方法會先使用移除的驅動程式套件來更新任何裝置,以在嘗試移除驅動程式套件之前,不再與該驅動程式套件一起安裝。

驅動程式套件開發

測試私人二進位檔

開發驅動程式套件時,如果需要將驅動程式套件中的特定可執行檔取代為私人版本,而不是完全重建和取代系統上的驅動程式套件,則建議使用核心調試程式搭配 .kdfiles 命令。 由於驅動程式存放區中檔案的完整路徑不應該硬式編碼,因此建議在 .kdfiles 對應中, OldDriver 檔名只是檔案的直接名稱,沒有先前的路徑資訊。 為了方便進行此動作(和其他案例),驅動程式套件中的檔名應該盡可能是唯一的,因此它不符合系統上不相關的驅動程式套件的檔名。

移植 INF 以使用從驅動程式存放區執行

如果您有現有的驅動程式套件,且 INF 不使用從驅動程式存放區執行,並將它移植到從驅動程式存放區執行,下列範例會顯示 INFs 中的一些常見檔案使用方式,以及更新要從 DriverStore 執行之檔案的模式。

目的地目錄更新的快速參考

下表提供快速參考,根據驅動程式套件 INF 為檔案指定的目前目的地目錄 DIRID 來尋找適當的指引。

DIRID 目錄 詳細資料
13 檔案已經使用「從驅動程式存放區執行」。 不需要進一步的工作。
1 不應該使用 DIRID 1。 當需要解析檔案的參考時,不保證來源目錄可供使用。 相反地,如果驅動程式套件中的元件相依於特定檔案,請在驅動程式套件中包含這些檔案,並從驅動程式存放區執行這些檔案。
10 韌體 如需如何使用 DIRID 13 搭配韌體更新驅動程式套件,使其使用「從驅動程式存放區執行」的資訊,請參閱 撰寫更新驅動程式套件
10 請參閱 其他檔案
11 請參閱 其他檔案
12 UMDF 請參閱 UMDF 驅動程式二進位檔
12 具有 DIRID 12 目的地的大部分檔案都代表驅動程式服務二進位檔。 請參閱 服務二進位檔
16422, 16426, 16427, 16428 具有這些 DIRID 目的地的大多數檔案都代表安裝應用程式。 相反地,請提供 通用 Windows 平台 (UWP) 應用程式,並使用驅動程式套件 INF 之 DDInstall.Software 區段的 AddSoftware 指示詞進行安裝。 如需詳細資訊,請參閱將驅動程式與 通用 Windows 平台 (UWP) 應用程式配對。

服務二進位檔

如果您的 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"