套件支援架構是一個開放原始碼套件,可協助您將修正程式套用至現有的傳統型應用程式(而不修改程式代碼),以便在 MSIX 容器中執行。 套件支援架構有助於讓應用程式遵循最新執行階段環境的最佳做法。
本文深入探討套件支援架構的每個元件,並提供使用它的詳盡逐步指南。
瞭解套件支持架構內的內容
套件支援架構包含可執行檔、運行時間管理員 DLL 和一組運行時間修正。
以下是程式:
- 建立組態檔,指定您要套用至應用程式的修正程式。
- 修改套件以指向套件支援架構 (PSF) 啟動器可執行檔。
當使用者啟動您的應用程式時,套件支援架構啟動器是執行的第一個可執行檔。 它會讀取您的組態檔,並將運行時間修正程式和運行時間管理員 DLL 插入應用程式進程。 當應用程式需要在 MSIX 容器內執行時,運行時間管理員會套用修正程式。
步驟 1:識別封裝的應用程式相容性問題
首先,為您的應用程式建立套件。 然後,安裝它、執行它,並觀察其行為。 您可能會收到錯誤訊息,可協助您識別相容性問題。 您也可以使用 行程監視器 來識別問題。 常見問題與有關工作目錄和程式路徑許可權的應用程式假設有關。
使用行程監視器來識別問題
進程監視器 是觀察應用程式檔案和登錄作業及其結果的強大公用程式。 這可協助您瞭解應用程式相容性問題。 開啟行程監視器之後,新增篩選條件 [篩選 > ...],只包含來自應用程式可執行檔的事件。
隨即會出現事件清單。 對於其中許多事件, SUCCESS 一詞會出現在 [結果 ] 數據行中。
您可以選擇性地篩選事件,只顯示失敗。
如果您懷疑文件系統存取失敗,請搜尋 System32/SysWOW64 或套件檔案路徑下失敗的事件。 使用篩選功能也能在這裡提供幫助。 從此清單底部開始,向上捲動。 最近發生的失敗會出現在此清單的底部。 應集中注意力於包含像「拒絕存取」和「找不到路徑/名稱」這類字串的錯誤,並忽略那些似乎不具可疑性的內容。 PSFSample 有兩個問題。 您可以在下列影像中顯示的清單中看到這些問題。
在此影像中顯示的第一個問題中,應用程式無法從位於 「C:\Windows\SysWOW64」 路徑的 「Config.txt」 檔案讀取。 應用程式不太可能嘗試直接參考該路徑。 最有可能的是,它嘗試使用相對路徑從該檔案讀取,且根據預設,“System32/SysWOW64” 是應用程式的工作目錄。 這表示應用程式預期其目前的工作目錄設定為封裝中的某個位置。 在 appx 內部查看,我們可以看到檔案存在於與可執行檔相同的目錄中。
第二個問題會出現在下圖中。
在此問題中,應用程式無法將.log檔案寫入其套件路徑。 這表示檔案重新導向的修正可能會有所幫助。
步驟 2:尋找運行時間修正
PSF 包含您現在可以使用的執行時修正,例如檔案重定向修正。
檔案重新導向修正
您可以使用 檔案重新導向修正 ,將嘗試在應用程式於 MSIX 容器中執行時無法存取的目錄中進行的寫入或讀取作業進行重新導向。
例如,如果您的應用程式寫入與應用程式可執行檔位於相同目錄中的記錄檔,您可以使用 [檔案重新導向修正] 在另一個位置建立該記錄檔,例如本機應用程式數據存放區。
來自社群的運行時間修正
請務必檢閱社群對 GitHub 頁面的貢獻。 其他開發人員可能已解決了與您類似的問題,並分享了執行時修正。
步驟 3:套用運行時間修正
您可以使用 Windows SDK 中的一些簡單工具套用現有的運行時間修正,並遵循下列步驟。
- 建立套件配置資料夾
- 取得套件支援架構檔案
- 將它們新增至您的套件
- 修改套件指令清單
- 建立組態檔
讓我們逐一查看每個任務。
建立套件配置資料夾
如果您已經有 .msix (或 .appx) 檔案,您可以將其內容解壓縮到配置資料夾,做為套件的預備區域。 您可以使用 MakeAppx 工具從命令提示字元執行此動作,根據 SDK 的安裝路徑,您可以在 Windows 10 計算機上找到 makeappx.exe 工具:x86:C:\Program Files (x86)\Windows Kits\10\bin\x86\makeappx.exe x64:C:\Program Files (x86)\Windows Kits\10\bin\x64\makeappx.exe
makeappx unpack /p PSFSamplePackage_1.0.60.0_AnyCPU_Debug.msix /d PackageContents
這會為您提供如下所示的內容。
如果您一開始沒有 .msix (或 .appx) 檔案,您可以從頭開始建立套件資料夾和檔案。
取得套件支援架構檔案
您可以使用獨立 Nuget 命令行工具,或透過 Visual Studio 取得 PSF Nuget 套件。
使用命令行工具取得套件
從這個位置安裝 Nuget 命令行工具: https://www.nuget.org/downloads。 然後,從 Nuget 命令行執行此命令:
nuget install Microsoft.PackageSupportFramework
或者,您可以將套件延伸模組重新命名為 .zip,並將其解壓縮。 您需要的所有檔案都會位在 /bin 資料夾底下。
使用 Visual Studio 取得套件
在 Visual Studio 中,以滑鼠右鍵按兩下您的方案或項目節點,然後挑選其中一個 [管理 Nuget 套件] 命令。 搜尋 Microsoft.PackageSupportFramework 或 PSF 以尋找 Nuget.org 上的套件。然後,安裝它。
將套件支援架構檔案新增至您的套件
將所需的 32 位和 64 位 PSF DLL 和可執行檔新增至套件目錄。 使用下表做為指南。 您也會想要包含您在運行時需要的任何修復。 在我們的範例中,我們需要檔案重新導向運行時間修正。
| 應用程式可執行檔為 x64 | 應用程式可執行檔為 x86 |
|---|---|
| PSFLauncher64.exe | PSFLauncher32.exe |
| PSFRuntime64.dll | PSFRuntime32.dll |
| PSFRunDll64.exe | PSFRunDll32.exe |
您的套件內容現在看起來應該像這樣。
修改套件指令清單
在文本編輯器中開啟套件清單,然後將 Executable 元素的 Application 屬性設定為 PSF 啟動器可執行檔的名稱。 如果您知道目標應用程式的架構,請選擇適當的版本、PSFLauncher32.exe 或 PSFLauncher64.exe。 如果沒有,PSFLauncher32.exe 在所有情況中都可以運作。 以下是範例。
<Package ...>
...
<Applications>
<Application Id="PSFSample"
Executable="PSFLauncher32.exe"
EntryPoint="Windows.FullTrustApplication">
...
</Application>
</Applications>
</Package>
建立組態檔
建立檔名 config.json,並將該檔案儲存至套件的根資料夾。 修改 config.json 檔案的宣告應用程式識別碼,以指向您剛才取代的可執行檔。 使用從行程監視器取得的知識,您也可以設定工作目錄,以及使用檔案重新導向修正,將讀取/寫入重新導向至套件相對 “PSFSampleApp” 目錄下的.log檔案。
{
"applications": [
{
"id": "PSFSample",
"executable": "PSFSampleApp/PSFSample.exe",
"workingDirectory": "PSFSampleApp/"
}
],
"processes": [
{
"executable": "PSFSample",
"fixups": [
{
"dll": "FileRedirectionFixup.dll",
"config": {
"redirectedPaths": {
"packageRelative": [
{
"base": "PSFSampleApp/",
"patterns": [
".*\\.log"
]
}
]
}
}
}
]
}
]
}
以下是 config.json 架構指南:
| 陣列 | 鑰匙 | 價值觀 |
|---|---|---|
| 應用程式 | 識別碼 | 使用封裝指令檔中Id元素的Application屬性值。 |
| 應用程式 | 可執行檔 | 您要啟動之可執行檔的套件相對路徑。 在大部分情況下,您可以在修改套件指令清單檔案之前,先從套件指令清單檔案取得此值。 它是 Executable 元素的 Application 屬性值。 |
| 應用程式 | workingDirectory | (選擇性)封裝相對路徑,用來作為啟動之應用程式的工作目錄。 如果您未設定此值,作業系統會使用System32目錄作為應用程式的工作目錄。 |
| 流程 | 可執行檔 | 在大部分情況下,這會是先前設定的 executable 的名稱,並移除其路徑和檔案擴展名。 |
| 修正 | dll | 要載入之修正的套件相對路徑 .msix/.appx。 |
| 修正 | 設定 | (選擇性)控制修正 dll 的運作方式。 此值的確切格式會依修正依修正而有所不同,因為每個修正程式都可以將這個「Blob」解譯為想要。 |
applications、 processes和 fixups 索引鍵是陣列。 這表示您可以使用 config.json 檔案來指定多個應用程式、進程和修正 DLL。
封裝及測試應用程式
接下來,建立套件。
makeappx pack /d PackageContents /p PSFSamplePackageFixup.msix
然後,簽署它。
signtool sign /a /v /fd sha256 /f ExportedSigningCertificate.pfx PSFSamplePackageFixup.msix
如需詳細資訊,請參閱 如何建立套件簽署憑證 ,以及如何 使用 signtool 簽署套件
使用 PowerShell 安裝套件。
備註
請記得先卸載套件。
powershell Add-AppPackage .\PSFSamplePackageFixup.msix
執行應用程式,並觀察套用運行時間修正的行為。 視需要重複診斷和封裝步驟。
檢查套件支持架構是否正在執行
您可以檢查執行時間補丁是否運作中。 若要這樣做,請開啟 [任務管理器 ],然後按兩下 [ 更多詳細數據]。 尋找已套用套件支援架構的應用程式,並展開應用程式詳細數據以提供更多詳細數據。 您應該能夠看到套件支援架構正在運行。
使用追蹤修正工具
診斷已封裝應用程式相容性問題的一種替代技術是使用 Trace Fixup。 此 DLL 隨附於 PSF,並提供應用程式行為的詳細診斷檢視,類似於進程監視器。 它專為顯示應用程式相容性問題而設計。 若要使用 Trace Fixup,請將 DLL 新增至套件,將下列片段新增至您的 config.json,然後將應用程式封裝並安裝。
{
"dll": "TraceFixup.dll",
"config": {
"traceLevels": {
"filesystem": "allFailures"
}
}
}
根據預設,追蹤修正功能會篩選出那些可能被認為是「可預期」的失敗。 例如,應用程式可能會嘗試無條件刪除檔案,而不檢查檔案是否已經存在,而忽略結果。 這有一些非預期失敗可能會篩選掉的不幸結果,因此在上述範例中,我們選擇從文件系統函式接收所有失敗。 我們這樣做是因為我們根據先前的經驗知道,嘗試讀取 Config.txt 檔案時會出現「找不到檔案」的錯誤訊息。 這是經常觀察到的失敗,通常不會假設為非預期。 實際上,可能最好先篩選非預期的失敗,然後如果仍有問題無法識別,再回退到包括所有失敗的篩選。
根據預設,追蹤修正程序的輸出會傳送至附加的調試程式。 在此範例中,我們不會附加調試程式,而是會改用來自SysInternals的 DebugView 程式來檢視其輸出。 執行應用程式後,我們可以看到與之前相同的錯誤,這將指引我們去解決相同的執行時問題。
偵錯、擴充或建立執行時修補
您可以使用 Visual Studio 對運行時間修正進行偵錯、擴充運行時間修正,或從頭開始建立一個。 您必須執行這些動作才能成功。
- 新增封裝專案
- 新增執行階段修正的專案
- 新增一個專案以啟動 PSF 啟動器執行檔
- 設定封裝專案
完成時,您的解決方案看起來會像這樣。
讓我們看看此範例中的每個專案。
| 專案 | 目標 |
|---|---|
| 桌面應用程式套件 | 此專案是以 Windows 應用程式封裝項目 為基礎,它會輸出 MSIX 套件。 |
| Runtimefix | 這是C++ Dynamic-Linked 程式庫專案,其中包含一或多個替代函式,用作執行時期的修正。 |
| PSFLauncher | 這是一個空的C++專案。 此專案是收集套件支援框架執行階段可分發檔案的平台。 它會輸出可執行檔。 該可執行檔是您啟動方案時所執行的第一件事。 |
| WinFormsDesktopApplication | 此專案包含桌面應用程式的原始程式碼。 |
若要查看包含所有這些類型專案的完整範例,請參閱 PSFSample。
讓我們逐步解說在解決方案中建立和設定每個這些專案的步驟。
建立套件解決方案
如果您還沒有桌面應用程式的解決方案,請在 Visual Studio 中建立新的 空白解決方案。
您也可以新增您擁有的任何應用程式專案。
新增封裝專案
如果您還沒有 Windows 應用程式封裝專案,請建立一個專案,並將其新增至您的解決方案。
如需 Windows 應用程式封裝專案的詳細資訊,請參閱 使用 Visual Studio 封裝您的應用程式。
在 [方案總管] 中,以滑鼠右鍵按兩下封裝專案,選取 [ 編輯],然後將它新增至項目檔底部:
<Target Name="PSFRemoveSourceProject" AfterTargets="ExpandProjectReferences" BeforeTargets="_ConvertItems">
<ItemGroup>
<FilteredNonWapProjProjectOutput Include="@(_FilteredNonWapProjProjectOutput)">
<SourceProject Condition="'%(_FilteredNonWapProjProjectOutput.SourceProject)'=='<your runtime fix project name goes here>'" />
</FilteredNonWapProjProjectOutput>
<_FilteredNonWapProjProjectOutput Remove="@(_FilteredNonWapProjProjectOutput)" />
<_FilteredNonWapProjProjectOutput Include="@(FilteredNonWapProjProjectOutput)" />
</ItemGroup>
</Target>
新增執行階段修正的專案
將C++ Dynamic-Link 連結庫 (DLL) 專案新增至方案。
以滑鼠右鍵按兩下該專案,然後選擇 [ 屬性]。
在屬性頁中,尋找 [C++語言標準 ] 欄位,然後在該欄位旁邊的下拉式清單中,選取 [ISO C++17 Standard (/std:c++17) 選項。
以滑鼠右鍵按下該專案,然後在作功能表中,選擇 [ 管理 Nuget 套件] 選項。 確定 [ 封裝來源] 選項設定為 [全部 ] 或 [nuget.org]。
按兩下該欄位旁的設定圖示。
搜尋 PSF* Nuget 套件,然後為此專案安裝該套件。
如果您想要偵錯或擴充現有的運行時間修正,請使用本指南的 尋找運行時間修正 一節中所述的指引,新增您取得的運行時間修正檔案。
如果您打算提出全新的修正,暫勿將任何內容新增至此。 我們稍後將協助您在本指南中將正確的檔案新增至此專案。 目前,我們會繼續設定您的解決方案。
新增一個專案以啟動 PSF 啟動器執行檔
將C++ 空白專案 專案新增至方案。
使用上一節所述的相同指引,將 PSF Nuget 套件新增至此專案。
開啟項目的屬性頁,然後在 [ 一般 設定] 頁面中,將 [目標名稱 ] 屬性設定為 PSFLauncher32 ,或 PSFLauncher64 視應用程式的架構而定。
將專案參考新增至方案中的執行階段修正專案。
以滑鼠右鍵按兩下參考,然後在 [ 屬性] 視窗中套用這些值。
| 財產 | 價值觀 |
|---|---|
| 複製本地 | 對 |
| 複製本機衛星組件 | 對 |
| 參考組件輸出 | 對 |
| 連結庫相依性 | 否 |
| 連結庫依賴項輸入 | 否 |
設定封裝專案
在封裝專案中,以滑鼠右鍵按兩下 [ 應用程式] 資料夾,然後選擇 [ 新增參考]。
選擇 PSF 啟動器專案和傳統型應用程式專案,然後選擇 [ 確定] 按鈕。
備註
如果您沒有應用程式的原始程式碼,只要選擇 PSF 啟動器專案即可。 我們將示範如何在建立組態檔時參考可執行檔。
在 [ 應用程式] 節點中,以滑鼠右鍵按下 PSF 啟動器應用程式,然後選擇 [ 設定為進入點]。
將名為 config.json 的檔案新增至封裝專案,然後將下列 json 文字複製並貼到檔案中。 將 [封裝動作] 屬性設定為 [內容]。
{
"applications": [
{
"id": "",
"executable": "",
"workingDirectory": ""
}
],
"processes": [
{
"executable": "",
"fixups": [
{
"dll": "",
"config": {
}
}
]
}
]
}
為每個鍵值提供相應的值。 請使用下表作為指南。
| 陣列 | 鑰匙 | 價值觀 |
|---|---|---|
| 應用程式 | 識別碼 | 使用封裝指令檔中Id元素的Application屬性值。 |
| 應用程式 | 可執行檔 | 您要啟動之可執行檔的套件相對路徑。 在大部分情況下,您可以在修改套件指令清單檔案之前,先從套件指令清單檔案取得此值。 它是 Executable 元素的 Application 屬性值。 |
| 應用程式 | workingDirectory | (選擇性)封裝相對路徑,用來作為啟動之應用程式的工作目錄。 如果您未設定此值,作業系統會使用System32目錄作為應用程式的工作目錄。 |
| 流程 | 可執行檔 | 在大部分情況下,這會是先前設定的 executable 的名稱,並移除其路徑和檔案擴展名。 |
| 修正 | dll | 要載入之修正 DLL 的套件相對路徑。 |
| 修正 | 設定 | (選擇性)控制修正 DLL 的運作方式。 此值的確切格式會依修正依修正而有所不同,因為每個修正程式都可以將這個「Blob」解譯為想要。 |
完成時,您的 config.json 檔案看起來會像這樣。
{
"applications": [
{
"id": "DesktopApplication",
"executable": "DesktopApplication/WinFormsDesktopApplication.exe",
"workingDirectory": "WinFormsDesktopApplication"
}
],
"processes": [
{
"executable": ".*App.*",
"fixups": [ { "dll": "RuntimeFix.dll" } ]
}
]
}
備註
applications、 processes和 fixups 索引鍵是陣列。 這表示您可以使用 config.json 檔案來指定多個應用程式、進程和修正 DLL。
修正執行期錯誤
在 Visual Studio 中,按 F5 以啟動調試程式。 首先,啟動的是 PSF 啟動器應用程式,接著會啟動您的目標桌面應用程式。 若要偵錯目標桌面應用程式,您必須手動附加至桌面應用程式程序,方法是選擇 [偵錯 ->附加至程序],然後選取應用程式程序。 若要啟用針對具有原生執行階段修正 DLL 的 .NET 應用程式進行偵錯,請選取受控與原生程式碼類型(混合模式偵錯)。
設定好之後,您可以在桌面應用程式的程式碼和執行時修正專案的程式碼行旁設置斷點。 如果您沒有應用程式的原始程式碼,您就只能在運行時間修正專案中的程式代碼行旁設定斷點。
由於 F5 偵錯會從套件設定資料夾路徑部署鬆散檔案,而不是從 .msix/.appx 套件安裝,因此配置資料夾通常沒有與已安裝套件資料夾相同的安全性限制。 因此,在套用運行時間修正之前,可能無法重現套件路徑存取拒絕錯誤。
若要解決此問題,請使用 .msix / .appx套件部署,而不是 F5 鬆散檔案部署。 若要建立 .msix / .appx套件檔案,請使用來自 Windows SDK 的 MakeAppx 公用程式,如上所述。 或者,從 Visual Studio 中,以滑鼠右鍵按兩下您的應用程式項目節點,然後選取 [ 市集 -> 建立應用程式套件]。
Visual Studio 的另一個問題是,它沒有內建支援附加至由偵錯工具啟動的任何子程序。 這使得在目標應用程式的啟動路徑中難以偵錯邏輯,Visual Studio 必須在啟動之後手動附加該邏輯。
若要解決此問題,請使用支持子進程附加的調試程式。 請注意,通常不可能將 Just-In-Time (JIT) 調試程式附加至目標應用程式。 這是因為大部分的 JIT 技術都牽涉到透過 ImageFileExecutionOptions 登錄機碼啟動調試程式來取代目標應用程式。 這會破壞 PSFLauncher.exe 利用的將 FixupRuntime.dll 插入目標應用程式的迂迴機制。 WinDbg 包含在 適用於 Windows 的偵錯工具中,並從 Windows SDK 取得,可支援子進程附加。 它現在也支援直接 啟動和偵錯 UWP 應用程式。
若要以子進程方式偵錯目標應用程式啟動,請啟動 WinDbg。
windbg.exe -plmPackage PSFSampleWithFixup_1.0.59.0_x86__7s220nvg1hg3m -plmApp PSFSample
在提示字元中 WinDbg ,啟用子偵錯並設定適當的斷點。
.childdbg 1
g
(執行直到目標應用程式啟動並進入除錯器)
sxe ld fixup.dll
g
(執行直到載入修復 DLL)
bp ...
支援
有問題嗎? 請在 MSIX 技術社群網站上的 套件支援架構 對話空間上詢問我們。