了解封裝的桌面應用程式在 Windows 上執行的方式
本主題描述您可以建立 Windows 應用程式套件的桌面應用程式類型,以及一些作業系統 (OS) 行為和其他重要事項,這些行為很重要。 我們將深入探討下列專案的詳細數據(如我們所見,特定行為取決於您的應用程式類型):
傳統型應用程式類型
您可以建立和封裝兩種類型的傳統型應用程式。 您可以使用 Application 元素的 uap10:RuntimeBehavior 屬性,在其應用程式套件指令清單中宣告應用程式的類型:
- 其中一種類型包括 WinUI 3 應用程式(使用 Windows 應用程式 SDK)和 傳統型橋接器 應用程式(Centennial)。 使用
uap10:RuntimeBehavior="packagedClassicApp"
宣告。 - 另一種類型代表其他類型的 Win32 應用程式,包括以外部位置封裝的應用程式。 使用
uap10:RuntimeBehavior="win32App"
宣告。
通用 Windows 平台 (UWP) 應用程式 (uap10:RuntimeBehavior="windowsApp"
) 也已封裝;但本主題不是關於它們。
然後 uap10:TrustLevel 屬性(相同 Application 元素的)會決定封裝應用程式的進程是否在應用程式容器內執行。
- 完全信任的應用程式。 使用
uap10:TrustLevel="mediumIL"
宣告。 - appContainer 應用程式。 使用
uap10:TrustLevel="appContainer"
宣告。 在輕量型應用程式容器中執行 (因此會使用檔案系統和登錄虛擬化隔離)。 如需詳細資訊,請參閱 MSIX appContainer 應用程式。
重要
如需詳細數據、相依性和功能需求,請參閱應用程式中這兩個屬性的檔。 另請參閱 在 Windows 10 版本 2004 中引進 uap10 (10.0;組建 19041)。
封裝和應用程式容器的目的
封裝應用程式的目的是在運行時間授與其 套件身分 識別。 某些 Windows 功能需要套件身分識別(請參閱 需要套件身分識別的功能)。 您可以封裝 上述應用程式類型的所有 組合(藉此受益於 套件身分識別)。
但 appContainer 應用程式的主要目標是盡可能將應用程式狀態與系統狀態分開,同時維持與其他應用程式的相容性。 Windows 可藉由偵測並重新導向它在運行時間對文件系統和登錄所做的特定變更來達成此目的(稱為 虛擬化)。 當區段僅適用於虛擬化應用程式時,我們將會指出。
安裝
應用程式套件會以每個用戶為基礎安裝,而不是全系統安裝。 新計算機上新套件的預設位置位於 底下 C:\Program Files\WindowsApps\<package_full_name>
,可執行檔名為 app_name.exe。 但套件可以安裝在其他地方;例如,Visual Studio 的 Start 命令會使用專案的 $(OutDir)
。
部署之後,套件檔案會標示為只讀,並受到操作系統 (OS) 嚴重鎖定。 如果這些檔案遭到竄改,Windows 會防止應用程式啟動。
位置 C:\Program Files\WindowsApps
是所謂的 PackageVolume。 該位置是 Windows 隨附的預設 PackageVolume;但是您可以在任何磁碟驅動器和任何路徑上建立 PackageVolume。 此外,並非所有套件都安裝在 PackageVolume 中(請參閱上述 Visual Studio 範例)。
檔案系統
OS 支援封裝傳統型應用程式的不同檔案系統作業層級,視資料夾位置而定。
已針對您的裝置優化
為了避免檔案重複(為了優化磁碟空間,並減少下載檔案時所需的頻寬),OS 會利用單一記憶體和檔案的硬式連結。 當使用者下載 MSIX 套件時, AppxManifest.xml
會用來判斷隨附套件的數據是否已經存在於先前套件安裝的磁碟上。 如果相同的檔案存在於多個 MSIX 套件中,則 OS 只會將共用檔案儲存在磁碟上一次,並且從這兩個套件建立共用檔案的硬式連結。 由於檔案會以 64Kb 區塊下載,因此即使下載的檔案百分比存在於磁碟上,也只會下載不同檔案的增量。 這可減少用於下載的頻寬。
Windows 10 版本 1903 和更新版本上的 AppData 作業
本節僅適用於虛擬化應用程式。
使用者資料夾中所有新建立的 AppData
檔案和資料夾 (例如, C:\Users\<user_name>\AppData
) 都會寫入私人每個使用者、個別應用程式位置,但在運行時間合併以出現在實際 AppData
位置。 這允許只供應用程式本身使用的成品進行某種程度的狀態區隔;可讓系統在卸載應用程式時清除這些檔案。
允許使用者修改使用者 AppData
資料夾下的現有檔案,以提供應用程式與OS之間的更高程度的相容性和互動性。 這可減少系統「腐爛」,因為 OS 知道應用程式所做的每個檔案或目錄變更。 狀態區隔也可讓已封裝的桌面應用程式在相同應用程式的未封裝版本離開的地方進行挑選。 請注意,OS 不支援使用者資料夾的 AppData
虛擬檔案系統 (VFS) 資料夾。
早於 Windows 10 版本 1903 的 OS 上的 AppData 作業
本節僅適用於虛擬化應用程式。
所有寫入使用者 AppData
的資料夾(例如 C:\Users\<user_name>\AppData
,)包括建立、刪除和更新,都會在寫入至個別使用者、個別應用程式位置的私人寫入時複製。 這會建立已封裝應用程式在實際修改私人複本時正在編輯真實 AppData
時的錯覺。 透過重新導向寫入的方式,系統可以追蹤應用程式所做的所有檔案修改。 這可讓系統在卸載應用程式時清除這些檔案,進而減少系統「腐爛」,併為使用者提供更好的應用程式移除體驗。
工作目錄和應用程式檔
本節僅適用於虛擬化應用程式。
除了重新導向 AppData
之外,Windows 的已知資料夾 (System32
、 Program Files (x86)
等等) 也會動態地與應用程式套件中的對應目錄合併。 每個套件都包含位於其根目錄的資料夾 VFS
。 目錄中的任何目錄或檔案 VFS
讀取,會在運行時間與各自的原生對應項目合併。 例如,應用程式可以包含 C:\Program Files\WindowsApps\<package_full_name>\VFS\SystemX86\vc10.dll
做為應用程式套件的一部分,但檔案似乎安裝在 C:\Windows\System32\vc10.dll
。 這可維持與預期檔案位於非套件位置之傳統型應用程式的相容性。
不允許寫入應用程式套件中的檔案/資料夾。 操作系統會忽略不屬於套件一部分的檔案和資料夾,只要使用者具有許可權,就允許寫入。
一般檔案系統作業
這個簡短的參考資料表,說明了常見的檔案系統作業及作業系統處理這些作業的方式。
作業 | 結果 | 範例 |
---|---|---|
讀取或列舉已知的 Windows 檔案或資料夾 | 的 C:\Program Files\<package_full_name>\VFS\<well_known_folder> 動態合併與本機系統對應專案。 |
讀取 C:\Windows\System32 會傳回 的內容 C:\Windows\System32 加上 的內容 C:\Program Files\WindowsApps\<package_full_name>\VFS\SystemX86 。 |
寫入底下 AppData |
Windows 10 版本 1903 和更新版本:下列目錄下建立的新檔案和資料夾會重新導向至每個使用者、每個套件的私人位置:
AppData 位置開啟檔案。 如果檔案是從實際 AppData 位置開啟,則不會發生該檔案的虛擬化。 如果使用者具有許可權,則允許在 底下 AppData 刪除檔案。早於 Windows 10 版本 1903:寫入時複製到每個使用者、每個應用程式位置。 |
AppData 通常是 C:\Users\<user_name>\AppData 。 |
在套件內寫入 | 不允許。 套件是唯讀的。 | 不允許在下 C:\Program Files\WindowsApps\<package_full_name> 寫入。 |
在套件外部寫入 | 如果使用者具有許可權,則允許。 | 如果套件不包含 C:\Program Files\WindowsApps\<package_full_name>\VFS\SystemX86\foo.dll ,且使用者具有權限,則允許寫入 C:\Windows\System32\foo.dll 。 |
封裝的 VFS 位置
本節僅適用於虛擬化應用程式。
下表顯示檔案在應用程式的系統上會覆寫作為套件一部分的運送位置。 當這些檔案實際上是在 內部 C:\Program Files\WindowsApps\<package_full_name>\VFS
的重新導向位置時,您的應用程式會察覺這些檔案會位於列出的系統位置中。 FOLDERID 位置來自 KNOWNFOLDERID 常數。
系統位置 | 重新導向的位置 (在 [<package_root>]\VFS 下) | 在架構上有效 |
---|---|---|
FOLDERID_SystemX86 | SystemX86 |
x86、amd64 |
FOLDERID_System | SystemX64 |
amd64 |
FOLDERID_ProgramFilesX86 | ProgramFilesX86 |
x86、amd6 |
FOLDERID_ProgramFilesX64 | ProgramFilesX64 |
amd64 |
FOLDERID_ProgramFilesCommonX86 | ProgramFilesCommonX86 |
x86、amd64 |
FOLDERID_ProgramFilesCommonX64 | ProgramFilesCommonX64 |
amd64 |
FOLDERID_Windows | Windows |
x86、amd64 |
FOLDERID_ProgramData | 常見 AppData |
x86、amd64 |
FOLDERID_System\catroot | AppVSystem32Catroot |
x86、amd64 |
FOLDERID_System\catroot2 | AppVSystem32Catroot2 |
x86、amd64 |
FOLDERID_System\drivers\etc | AppVSystem32DriversEtc |
x86、amd64 |
FOLDERID_System\driverstore | AppVSystem32Driverstore |
x86、amd64 |
FOLDERID_System\logfiles | AppVSystem32Logfiles |
x86、amd64 |
FOLDERID_System\spool | AppVSystem32Spool |
x86、amd64 |
登錄
本節(及其子區段)僅適用於虛擬化應用程式。
應用程式套件包含檔案registry.dat
,其可作為實際登錄中 HKLM\Software 的邏輯(虛擬)對等專案。 在運行時間,虛擬登錄會將該 Hive 的內容合併至原生系統 Hive,以提供兩者的單一檢視。 例如,如果registry.dat
包含單一密鑰 Foo,則運行時間的 HKLM\Software 讀取也會顯示包含 Foo (除了所有原生系統密鑰外)。
雖然 MSIX 套件包含 HKLM 和 HKCU 金鑰,但會以不同的方式處理它們。 只有 HKLM\Software 下的金鑰是套件的一部分;HKCU 下的機碼或登錄的其他部分則不是。 不允許寫入封裝中的索引鍵或值。 只要使用者具有權限,就會允許寫入不屬於套件的機碼或值。
HKCU 下的所有寫入都會在寫入至個別使用者、個別應用程式位置的私人時複製。 傳統上,卸載程式無法清除 HKEY_CURRENT_USER ,因為註銷使用者的登錄數據已卸除且無法使用。
所有寫入都會在套件升級期間保留,而且只有在完全移除應用程式時才會刪除。
常見的登錄作業
本節大部分僅適用於虛擬化應用程式。
這個簡短的參考資料表說明了常見的登錄作業及作業系統處理這些作業的方式。
作業 | 結果 | 範例 |
---|---|---|
讀取或列舉 HKLM\Software | 封裝Hive與本機系統對應專案的動態合併。 | 如果registry.dat 包含單一密鑰 Foo,則在運行時間讀取 HKLM\Software 會顯示 HKLM\Software 和 HKLM\Software\Foo 的內容。 |
HKCU 下的 寫入 | 在寫入時複製到每個使用者、每個應用程式的私人位置。 | 與 AppData 檔案相同。 |
寫入封裝內部。 | 不允許。 套件是唯讀的。 | 如果套件 Hive 中有對應的索引鍵/值存在,則不允許在 HKLM\Software 下寫入。 |
寫入套件外部 | 作業系統會略過。 如果使用者具有許可權,則允許。 | 只要套件 Hive 中沒有對應的索引鍵/值,而且使用者具有正確的訪問許可權,就會允許在 HKLM\Software 下寫入。 |
解除安裝
本節僅適用於虛擬化應用程式。
當使用者卸載套件時,會移除位於 下 C:\Program Files\WindowsApps\<package_full_name>
的所有檔案和資料夾,以及封裝程式期間所擷取的任何 AppData
重新導向寫入或登錄。