Windows 應用程式相容的運作機制 ── 以相容模式、Shim 與 Compatibility Administrator 延續舊應用程式

· · Windows, 相容模式, Shim, 應用程式相容性, Compatibility Administrator, 既有資產活用, Windows 開發, 既有系統

更新紀錄(僅初版,2026年08月20日 發布)
初次發布
引用本文(DOI(已登錄存檔): 10.5281/zenodo.22176321)

以下 DOI 指向先前登錄的存檔,內容可能與目前正文不同。引用目前正文時,請使用本頁網址。

Go Komura(2026)。〈Windows 應用程式相容的運作機制 ── 以相容模式、Shim 與 Compatibility Administrator 延續舊應用程式〉。小村軟體有限公司。 https://comcomponent.com/zh-TW/blog/windows-appcompat-shims-compatibility-mode/

DOI(已登錄存檔)
10.5281/zenodo.22176321
DOI(上次登錄版本)
10.5281/zenodo.22176322

「一套十年前的業務應用程式,原始碼已經不在,在新的 Windows 11 電腦上無法啟動。可是在相容性索引標籤選了『Windows XP』,它就跑起來了。這樣繼續用下去可以嗎。」在照顧舊業務應用程式的現場,常會接到這類諮詢。

相容模式並不是把整個作業系統退回舊版 Windows 的功能,而是只針對那一支應用程式,補上它所假設的舊版 Windows 行為的機制。核心是插在應用程式與 Windows API 之間的一小段相容性修正,也就是 Shim。1

本文面向中小企業的資訊人員與 Windows 應用程式開發者,依能修好什麼 → 為什麼跑得動 → 如何套用與部署 → 延續使用或遷移該怎麼判斷的順序整理。依據 Microsoft Learn 的第一手資料,確認勾選核取方塊之後究竟發生了什麼。

1. 先講結論 ── 相容模式可以用,但要當成延續使用的手段來管理

靠相容模式維持眼前的業務運轉,本身是在使用 Windows 正式提供的機制,屬於合理的選擇。 Windows 自己也會對已知的應用程式套用相容性修正。1 但這並不等於修好了應用程式。正途是最終把它改成不靠 Shim 也能執行的形態。

要不要用,依下面的順序判斷就能理清。

判斷順序 要確認的事 閱讀章節
1. 判定適用範圍 問題是不是出在應用程式這一側的 API 用法。會不會是驅動程式、16 位元、專用硬體的問題 第 2~3 章
2. 選出需要的修正 版本判斷、路徑、權限要求等,補上什麼才跑得動 第 4~5 章。現成設定見第 6 章,RunAsInvoker 見第 7 章,個別 Shim 的部署見第 8 章
3. 決定跑起來之後的維運 能不能記錄設定,並在 Windows 更新時驗證。要延續使用到什麼時候 第 9 章

尤其要注意,「對是否為系統管理員的檢查回傳成功」和「授予系統管理員權限」是兩回事。Shim 受到與應用程式相同的安全性約束,不會繞過作業系統的保護。12 RunAsInvoker 同樣只是抑制提高權限的要求、讓應用程式以與呼叫端相同的權限啟動,並不是增加權限的功能。3

只要理解機制,就能把「不知道為什麼跑得動,所以不敢碰」的延續使用,換成能說清楚可依賴範圍、失效條件與重寫時機的延續使用。

理解機制會改變延續使用的品質不了解機制就使用相容模式,會變成不敢碰的不穩定延續使用;理解機制之後,就能有依據地判斷能依賴到什麼程度、發生什麼會失效、何時應該重寫不了解機制就使用不敢碰的不穩定延續使用理解機制之後再使用有依據的判斷能依賴到什麼程度發生什麼會失效何時應該重寫

圖 1:同樣是延續使用,不了解機制時的不安,與基於理解的判斷,品質並不相同。

圖中實線表示始終成立的關係,虛線表示附帶條件的關係(成立條件寫在詳細頁面中各關係的說明中)。關係的完整清單(共 16 條,附依據與可信度)以及主要概念的定義,彙整在知識地圖詳細頁面(日文)。資料:JSON-LD / Turtle

2. 第一步的釐清 ── 這是不是 Shim 修得好的問題

2.1. 修得好的只有使用者模式下應用程式這一側的問題

Shim 做得到的事,都落在改應用程式程式碼同樣做得到的範圍內。它是在沒有原始碼、廠商支援已結束、現在無法立刻修改等情況下的替代手段,並不比修改程式碼更強大。1

例如:看了作業系統版本就拒絕啟動、假設寫入位置還是舊路徑、要求實際上並不需要的系統管理員權限,這類問題都可以列入檢討。具體有哪些 Shim,第 5 章再確認。

2.2. 一直調設定也解決不了的情況

下列問題需要相容模式以外的對策。

問題 Shim 無法解決的原因
核心模式的不相容 Shim 在使用者模式的處理程序內執行,因此修不了裝置驅動程式。舊量測儀器、USB 保護鎖、印表機的不支援驅動程式,以及部分在核心中執行的防毒軟體也一樣
64 位元 Windows 上的 16 位元應用程式 作業系統不支援執行 16 位元應用程式,連啟動本身都會失敗
直接存取硬體 從使用者模式直接碰 I/O 連接埠或實體記憶體的前提,超出 Shim 能偽裝的範圍
繞過安全性機制 Shim 無法把應用程式未獲許可的操作,變成獲得許可的操作

核心模式的問題與安全性的限制,都是 Shim 執行位置本身帶來的界限。1 ForceAdminAccess 與 WRPMitigation 只是偽裝檢查或寫入成功、讓應用程式往下走,並沒有真的改寫受保護的資源。2

在 16 位元的問題上,不只要確認應用程式本體,也要確認安裝程式。就算本體是 32 位元,只要舊安裝套件的啟動部分(stub)是 16 位元,就會變成「應用程式跑得動,卻裝不起來」。64 位元 Windows 上控制代碼帶有 32 位元的有效位元,無法截短成 16 位元傳遞,基於這類原因並不支援 16 位元應用程式,啟動會以 ERROR_BAD_EXE_FORMAT 失敗。4

Shim 不生效的情況Shim 在使用者模式的處理程序內執行,因此對核心模式的驅動程式問題、16 位元應用程式、直接存取硬體、繞過安全性機制都不生效不生效不生效不生效不生效Shim(在使用者模式執行)核心驅動程式16 位元應用程式直接存取硬體繞過安全性機制在 64 位元上連啟動都會失敗只是偽裝成功讓它往下走

圖 2:Shim 僅限使用者模式,碰不到核心、16 位元、直接存取硬體與繞過安全性。

另外,舊的防拷保護或竄改偵測這類具有自我完整性檢查的應用程式,可能會把 API 攔截本身視為異常。並不是使用者模式的應用程式就一定救得回來。

3. 區分相似的機制 ── Shim、UAC 虛擬化、WOW64、DPI 虛擬化

「舊應用程式跑起來了」的時候,在背後運作的未必只有 Shim。先把 Windows 具備的向下相容層分開來看。實際上,也可能是多個機制組合在一起。

層 做什麼 主要對象
Shim(相容模式) 攔截 API 呼叫,偽裝出與舊版 Windows 相同的回應 以舊作業系統為前提寫成的應用程式
UAC 虛擬化(檔案/登錄檔) 把沒有權限的 HKLM\Software 或 Program Files 寫入轉送到每位使用者的 VirtualStore 以系統管理員權限為前提寫成的 32 位元應用程式
WOW64 讓 32 位元應用程式直接在 64 位元 Windows 上執行(提供登錄檔與檔案的 32 位元檢視) 32 位元應用程式
DPI 虛擬化 讓未支援 DPI 的應用程式以 96 DPI 繪製,再以點陣圖放大顯示 高 DPI 顯示器上的舊應用程式

3.1. UAC 虛擬化:把寫入位置依使用者分流

UAC 虛擬化是針對沒有資訊清單的 32 位元互動式處理程序而生效的過渡措施。Microsoft 自己把它定位成打算從未來 Windows 移除的暫時技術。5 執行 32 位元應用程式的 WOW64,和把寫入位置依使用者轉送的 UAC 虛擬化是不同的機制。

關於轉送到 Wow6432Node 以及 VirtualStore 造成的實際損害與對策,登錄檔的 32bit/64bit 重新導向與虛擬化的陷阱一文有討論。本文只寫到與 Shim 區分所必需的程度。

UAC 虛擬化的定位UAC 虛擬化是針對沒有資訊清單的 32 位元互動式處理程序而生效的過渡措施,會把寫入轉送到每位使用者的 VirtualStore,但 Microsoft 自己明言它是打算從未來 Windows 移除的暫時技術沒有資訊清單的 32 位元互動式處理程序UAC 虛擬化生效轉送到每位使用者的 VirtualStore有意在未來移除的暫時技術

圖 3:UAC 虛擬化是給沒有資訊清單的 32 位元處理程序的過渡措施,不能長期依賴。

3.2. DPI 虛擬化:把舊的繪製拉伸開

沒有宣告支援 DPI 的應用程式,會被當成以 96 DPI(100%)繪製。Windows 會把那張點陣圖拉伸,因此在高 DPI 螢幕上顯示會變模糊。相容性索引標籤的「覆寫高 DPI 設定」,就是切換這項虛擬化行為的開關。6

DPI 虛擬化的機制沒有宣告支援 DPI 的應用程式會被當成以 96 DPI 繪製,Windows 拉伸點陣圖顯示因而看起來模糊,相容性索引標籤的覆寫高 DPI 設定則切換這項虛擬化的行為切換虛擬化的行為沒有宣告支援 DPI 的應用程式視為以 96 DPI 繪製拉伸點陣圖顯示在高 DPI 螢幕上變模糊覆寫高 DPI 設定

圖 4:未支援 DPI 的應用程式被當成 96 DPI 拉伸,相容性索引標籤的覆寫就是這項虛擬化的開關。

4. 為什麼相容模式能讓它跑起來 ── Shim 與啟動時的套用

4.1. 替換 API 呼叫的去向

Windows 的可執行檔(PE 格式)呼叫外部 DLL 的 API 時,途中會經過匯入位址表(IAT)。例如呼叫 GetVersionEx 時,控制權會轉到 IAT 裡所寫的位址。

Shim 會在應用程式載入時,把這個 IAT 項目改寫成 Shim 程式碼的位址。這就是 API 攔截(hook)。以 GetProcAddress 動態取得的 API,則靠攔截 GetProcAddress 本身來處理。1

攔截下來的 Shim 會回傳舊的作業系統版本、或把檔案存取位置改掉,必要時再呼叫真正的 API。對應用程式呈現「它所期待的 Windows 行為」,對作業系統送出符合現行機制的呼叫,可說是一名口譯。

Shim 攔截 API 呼叫的路徑應用程式的 API 呼叫會經過 IAT,載入時把 IAT 項目改寫成指向 Shim,Shim 就能攔截下來,先偽裝出與舊版 Windows 相同的回應,必要時再呼叫真正的 APIAPI 呼叫載入時改寫成指向 Shim必要時以攔截處理應用程式IAT 項目Shim(口譯)真正的 Windows API偽裝出與舊版 Windows 相同的回應經由 GetProcAddress 的呼叫

圖 5:Shim 插在應用程式與 Windows API 之間。被改寫的是應用程式這一側的 IAT,作業系統本身沒有變。

改變的是應用程式這一側的呼叫路徑,不是作業系統本身。 Shim 在與應用程式相同的安全性約束下執行,因此為了使用它也不需要放寬作業系統的安全性設定。1

4.2. .sdb 決定「對哪個 EXE 套用什麼」

Shim 資料庫是副檔名為 .sdb 的二進位檔案。它以檔名、大小、總和檢查碼、版本這類比對屬性識別可執行檔,並在處理程序啟動時進行比對。這裡用到的術語可以分成以下幾個。7

術語 作用
Appfix(Shim) 套用 API 攔截等相容性修正
Apphelp 顯示「這個應用程式有相容性問題」之類的訊息
相容層(相容模式) 把多個 Shim 與旗標綁成一組來套用

被比對的不只是使用者設定過相容模式的應用程式。每一次處理程序啟動,都會與作業系統標準的資料庫比對。 Windows 隨附了數千個已知應用程式的修正,實體位於 %WINDIR%\AppPatch 底下。Microsoft 提供的相容性修正會作為 Windows 的一部分出貨,並經由 Windows Update 更新。1

處理程序啟動時的 Shim 資料庫比對每一次處理程序啟動都會與 Shim 資料庫比對,只要有符合比對屬性的登錄,就會由 Appfix 注入 Shim 或由 Apphelp 顯示訊息,沒有登錄就照常啟動有有沒有多個 Shim 與旗標的組合處理程序啟動與 Shim 資料庫(.sdb)比對以檔名、大小等比對有登錄嗎?Appfix(注入 Shim)Apphelp(顯示訊息)照常啟動相容層(相容模式)

圖 6:比對不只針對設定過相容模式的應用程式,而是在每一次處理程序啟動時都在進行。

相容層裡不只有 API 攔截,也包含啟動時的旗標。第 7 章的 RunAsInvoker 並不攔截 API,而是以載入器旗標作用在啟動時執行等級上的相容性修正。3

4.3. 也可能是 PCA 發現問題後自行套用

就算系統管理員沒有手動設定,PCA(Program Compatibility Assistant)也可能套用相容性設定。PCA 會監視應用程式的執行,一旦偵測到已知問題的徵兆,就會建議套用修正,在部分情況下則會自動套用。8

例如,對於呼叫已釋放 DLL 內的程式碼而當掉的應用程式會用 PINDLL,對於寫入受保護的 Windows 檔案失敗的應用程式則會用 WRPMITIGATION 這類相容模式。8

PCA 自動套用相容性設定的流程PCA 監視應用程式的執行,一旦偵測到已知相容性問題的徵兆,就會向使用者建議套用修正,在部分情況下則自動套用相容性設定有以建議處理部分情況沒有應用程式執行PCA 監視有已知問題的徵兆嗎?屬於哪種情況?建議套用修正自動套用相容性設定照常執行例:PINDLL 或 WRPMITIGATION

圖 7:PCA 監視應用程式的執行,偵測到已知問題的徵兆就建議修正或自動套用。

「我沒印象設定過,相容模式的勾卻打上了」這種現象,多半就是這條路徑。未必是故障或誤操作,也可能是 Windows 針對問題做出處置的結果。

5. 從症狀選出修正 ── 代表性的 Shim 與版本判斷

5.1. 現成 Shim 能補上什麼

在 Microsoft 公開的現成 Shim 中,挑出延續業務應用程式時常用的幾個。2

Shim 能做什麼(摘要)
WinXPSP3VersionLie 等 VersionLie 系列 對作業系統版本查詢回傳指定的舊版本(版本偽裝)
CorrectFilePaths 把對無法寫入或不存在的檔案路徑的存取,改接到其他位置
VirtualRegistry 重新導向或偽裝登錄檔的讀寫(含版本偽裝與模擬不存在的機碼)
ForceAdminAccess 對「是否屬於系統管理員群組」的檢查暫時回傳 True
RunAsAdmin / RunAsHighest / RunAsInvoker 從外部賦予相當於資訊清單 requireAdministrator / highestAvailable / asInvoker 的執行等級
WRPMitigation 對受保護的作業系統檔案與登錄檔的寫入偽裝成功,讓應用程式往下走
EmulateGetDiskFreeSpace 把磁碟可用空間回報為最多 2GB(因應在大容量磁碟上位數溢位的應用程式)
GlobalMemoryStatusLie 偽裝記憶體狀態的回報值(因應在啟動時的記憶體檢查就掛掉的應用程式)
LoadLibraryRedirect 讓應用程式載入 Windows 這一側的最新 DLL,而不是隨附的舊系統 DLL

多數 Shim 做的事,就是回傳舊應用程式所期待的答案。「磁碟容量最多 2GB」「作業系統是 XP」「系統管理員檢查通過」——把應用程式誕生那個年代的前提,只在那個處理程序裡重現一次。如同第 2 章所見,偽裝答案與實際變更權限、資源是兩回事。

5.2. 就算不選相容模式,GetVersionEx 的值也會變

版本偽裝並不只發生在手動選了相容模式的時候。從 Windows 8.1 起,GetVersionEx 回傳的值取決於應用程式的資訊清單。若 <compatibility> 內沒有 <supportedOS> 宣告,即使實際跑在較新的 Windows 上,也會回傳相當於 Windows 8 的 6.2。有宣告的話,就回傳所宣告之中最高的作業系統為止的值。例如宣告到 Windows 8.1 GUID 的應用程式,在 Windows 11 上也是 6.3。910

在這個基礎上,如果又套用了 VersionLie 系列的 Shim,就會回報相容模式所選作業系統的版本。必須依序看資訊清單決定的預設回應,以及 Shim 對回應的置換。9

應用程式看到的作業系統版本是怎麼決定的GetVersionEx 回傳的值取決於資訊清單有沒有 supportedOS 宣告,沒有宣告就回傳相當於 Windows 8 的 6.2,有宣告則回傳所宣告之中最高的作業系統為止的值,若套用了 VersionLie 系列的 Shim 就會被所選作業系統的版本覆寫沒有有有沒有GetVersionEx 的查詢有 supportedOS 宣告嗎?回傳相當於 Windows 8 的 6.2所宣告之中最高的作業系統為止的值有套用 VersionLie 系列的 Shim 嗎?相容模式所選作業系統的值回傳原本的值

圖 8:應用程式看到的 Windows 版本,是由資訊清單與 Shim 多段決定的。

因此,要確認的地方也會隨症狀而分。如果是自家應用程式把 Windows 11 判定成 Windows 8 而造成困擾,就先確認 supportedOS 宣告。反過來,如果是舊應用程式只憑版本檢查就拒絕啟動,那 VersionLie 值得一試。這類應用程式實際上在新作業系統上多半沒問題,靠 Shim 解除啟動拒絕的可能性很高。

版本造成的兩種症狀與處理自家應用程式明明在 Windows 11 上卻被判定成 8,就要懷疑資訊清單的 supportedOS 宣告;只憑版本檢查就拒絕啟動的舊應用程式,用 VersionLie 有很高機率可以突破明明是 Windows 11 卻被判定成 8懷疑 supportedOS 宣告因版本檢查而拒絕啟動試著用 VersionLie 突破實際行為在新作業系統上多半沒問題

圖 9:判定變舊的症狀懷疑資訊清單,拒絕啟動的症狀懷疑 VersionLie。

6. 先在一台機器上確認 ── 相容性索引標籤與 Layers 機碼

6.1. 看核取方塊存到哪裡

在內容的相容性索引標籤儲存的設定,會寫進登錄檔的 AppCompatFlags\Layers 機碼。這也是 DXGI 的應用程式相容設定所使用的相容層指定位置。11

reg query "HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"

對設定了「Windows XP (Service Pack 3)」「以系統管理員身分執行此程式」「覆寫高 DPI 設定」的 EXE,看到的值例如會像下面這樣。

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
    C:\LegacyApp\Gyomu.exe    REG_SZ    ~ WINXPSP3 RUNASADMIN HIGHDPIAWARE

各項目與值的代表性對應如下。這是 Windows 11 的例子,項目名稱與值可能隨作業系統版本而變。

相容性索引標籤的項目 寫入的值(例) 本體
相容模式:Windows XP (Service Pack 3) WINXPSP3 把版本偽裝等多個 Shim 綁成一組的相容層
使用 256 色(8 位元色彩) 256COLOR 舊色彩模式的緩解
以 640×480 解析度執行 640X480 以低解析度執行
停用全螢幕最佳化 DISABLEDXMAXIMIZEDWINDOWEDMODE 停用全螢幕時的繪製最佳化
覆寫高 DPI 設定(應用程式) HIGHDPIAWARE 讓 DPI 虛擬化(點陣圖拉伸)停止作用6
以系統管理員身分執行此程式 RUNASADMIN 啟動時要求提高權限

6.2. 分清楚套用給哪些使用者,以及何時套用

HKCU 這一側只是那位使用者的設定。從「變更所有使用者的設定」儲存時,會寫進 HKLM 這一側的同名機碼,套用到所有使用者。在整備電腦時,請確認存在哪一邊。

另外,設定套用到處理程序的時機,是下一次啟動那個 EXE 的時候。載入器會讀取已儲存的值,套用對應的相容層。

相容性索引標籤的設定生效前的流程相容性索引標籤的設定會以 EXE 路徑與值的形式存進 AppCompatFlags 的 Layers 機碼,下次啟動該 EXE 時載入器讀取這個值,把對應的相容層套用到處理程序在相容性索引標籤設定把 EXE 路徑與值存進 Layers 機碼下次啟動 EXE載入器讀取值把相容層套用到處理程序HKCU 只對那位使用者生效HKLM 對所有使用者生效

圖 10:核取方塊的本體是寫入 Layers 機碼,套用則發生在下次啟動時。

6.3. 別把相容模式和提高權限的指定搞混

RUNASADMIN 也和 WINXPSP3 同住在 Layers 機碼裡。看起來像「設了相容模式,連提高權限也跟著來了、或是不見了」時,直接確認值就能把相容層的指定與提高權限的指定分開。

相容性索引標籤是通往代表性現成相容層的入口。要挑選個別 Shim 並加以組合,是第 8 章 Compatibility Administrator 的工作。在那之前,先看看日常維運中出場機會很多的 RunAsInvoker。

7. RunAsInvoker ── 只抑制不必要的提高權限要求

7.1. 區分「要求系統管理員」與「確實需要系統管理員權限」

在舊業務應用程式中,有些會因為資訊清單的 requireAdministrator 指定,或因為 EXE 名稱、內容被誤判為安裝程式,每次啟動都要求 UAC 提高權限。然而,其中也有不少只是沿用 XP 時代的設計而提出要求,實際上根本沒用到系統管理員權限。

RunAsInvoker 會同時覆寫安裝程式偵測與資訊清單處理,讓應用程式以從父處理程序繼承來的權杖直接啟動。呼叫端是標準使用者權限的話,就維持那個權限。3

RunAsInvoker 抑制提高權限要求的機制資訊清單的 requireAdministrator 宣告與被誤判為安裝程式,都是啟動時要求 UAC 提高權限的原因,套用 RunAsInvoker 之後兩者都會被覆寫,應用程式會以從父處理程序繼承來的權杖直接啟動沒有有requireAdministrator 宣告有套用 RunAsInvoker 嗎?被誤判為安裝程式每次啟動都要求 UAC 提高權限以父處理程序的權杖直接啟動必須有系統管理員權限的處理會在應用程式內失敗

圖 11:RunAsInvoker 只是覆寫提高權限要求的原因,權限並不會增加。

7.2. 用環境變數暫時試用

就算不建立 .sdb,也可以用環境變數 __COMPAT_LAYER 暫時套用相同的相容層。以下是套用到從該命令提示字元或 PowerShell 啟動的子處理程序的例子。

:: 對從這個命令提示字元啟動的子處理程序套用 RunAsInvoker
set __COMPAT_LAYER=RunAsInvoker
start "" "C:\LegacyApp\Gyomu.exe"
# PowerShell 的情況
$env:__COMPAT_LAYER = 'RunAsInvoker'
Start-Process 'C:\LegacyApp\Gyomu.exe'

請先以與實際使用者相同的標準權限,確認業務上必要的操作也都能執行,再採用。2 如果是不需要系統管理員權限的應用程式,把命令寫成批次檔、當成捷徑發下去,就能減少發放本機系統管理員權限,也能減少每次 UAC 要輸入密碼就得找資訊人員的情形。這是朝最小權限原則靠攏的相容技巧。

派發 RunAsInvoker 批次檔的效果把設定 RunAsInvoker 的兩行批次檔當成捷徑發下去,就不必把本機系統管理員權限發給一般使用者,也不會因為 UAC 要輸入密碼而叫來資訊人員,維運會朝最小權限原則靠攏派發兩行批次檔不必發放系統管理員權限不會因 UAC 叫來資訊人員符合最小權限原則的維運

圖 12:光是派發批次檔,就能同時減少發放系統管理員權限與為 UAC 出勤。

7.3. 區分生效範圍、永久套用與改寫

RunAsInvoker 並不會讓權限增加。 真正需要系統管理員權限的 HKLM 寫入或 Program Files 底下的更新,會在應用程式內失敗。符合條件時,也可能被 UAC 虛擬化轉送到 VirtualStore。如果設定儲存看起來「失效了」,就要懷疑虛擬化。5

環境變數方式生效的對象,是繼承該環境啟動的子處理程序。要永久套用,就用直接設定 Layers 機碼或部署 .sdb。相容性索引標籤裡並沒有可以選 RUNASINVOKER 的項目。

RunAsInvoker 的暫時套用與永久套用用環境變數 COMPAT_LAYER 套用時只對從那裡啟動的子處理程序生效,要永久套用就得直接設定 Layers 機碼或以 .sdb 部署以環境變數設定只對子處理程序生效暫時性的套用直接設定 Layers 機碼永久套用以 sdb 部署

圖 13:環境變數方式是僅限子處理程序的暫時套用,永久化要靠 Layers 機碼或 .sdb。

如果應用程式能改寫,比起增加相容性設定,把設定檔的儲存位置移到 %APPDATA% 底下、並在資訊清單宣告 asInvoker,才是本來該做的修正。3

8. 部署到整個組織 ── Compatibility Administrator 與 sdbinst

8.1. 讓應用程式與工具的 32 位元/64 位元一致

Compatibility Administrator 包含在 Windows ADK(Windows Assessment and Deployment Kit) 裡。12 32 位元版與 64 位元版都會被安裝,修正 32 位元應用程式要用 32 位元版,修正 64 位元應用程式要用 64 位元版。13

另一個要注意的是,不要以系統管理員身分測試就判定「修好了」。在已提高權限的狀態下,UAC 虛擬化與重新導向不會照原本的方式運作,可能會誤判結果。修正的效果要以與實際使用者相同的帳戶和權限來確認。2

使用 Compatibility Administrator 時的兩項注意修正 32 位元應用程式要用 32 位元版、修正 64 位元應用程式要用 64 位元版,修正的效果不要在已提高權限的狀態下確認,而要以與實際使用者相同的帳戶和權限確認32 位元應用程式用 32 位元版修正64 位元應用程式用 64 位元版修正在已提高權限的狀態下測試可能誤判為已修好以與實際使用者相同的權限測試正確確認效果

圖 14:32 位元版與 64 位元版的分用,以及以實際使用者相同權限確認,是入門時的注意點。

8.2. 先用相容層試,再收斂到必要的 Shim 與目標 EXE

建立自訂相容性資料庫,依下列順序進行。14

  1. 在左窗格的「Custom Databases」建立新資料庫,選擇「Create New」→「Application Fix」。
  2. 輸入應用程式名稱與廠商名稱,指定目標 EXE 檔案。
  3. 選擇「Windows XP 相容」這類相容模式(相容層),先用一組 Shim 試試。
  4. 需要的話再選個別的相容性修正。可以收斂成只有 VersionLie、只有 CorrectFilePaths 這種最小組合。
  5. 確認檔案大小、總和檢查碼、版本等比對條件後儲存。

「選出有效的 Shim」和「只讓正確的 EXE 生效」兩件事都必要。比對通常用預設的基本條件就足夠,但請保留能鎖定應用程式版本的條件。這是為了避免廠商推出修正版之後,還把舊的修正一直套用到新版本上。1415

建立自訂相容性資料庫的步驟在新資料庫建立 Application Fix,指定應用程式名稱與目標 EXE,先用一組相容模式試,必要時再收斂到個別 Shim,確認比對條件後儲存建立新資料庫選擇 Application Fix指定應用程式名稱與目標 EXE用一組相容模式試必要時收斂到個別 Shim確認比對條件後儲存保留能鎖定版本的條件

圖 15:Application Fix 先用一組相容模式試,再收斂成最小組合,並用比對條件限定對象。

把做好的 .sdb 拿到測試機上試,確認行為符合預期之後再進入部署。

8.3. 用 sdbinst 套用與解除,用 GUID 管理更新

要套用到各台電腦,就以系統管理員權限執行 sdbinst.exe。除了安裝之外,也可以用指定檔案或指定資料庫 GUID 的方式解除安裝。15

:: 安裝(-q 是不詢問的無訊息模式)
sdbinst -q "C:\Deploy\MyCorpFixes.sdb"

:: 解除安裝(指定檔案)
sdbinst -q -u "C:\Deploy\MyCorpFixes.sdb"

:: 解除安裝(指定資料庫 GUID)
sdbinst -q -u -g {資料庫的 GUID}

在相容性修正越來越多的組織裡,比起讓每個應用程式的安裝程式各自帶一個 .sdb,更建議在公司層級集中成一個、或依部門集中成自訂資料庫來集中管理。因為比起追蹤大量只有一行的資料庫,更新並重新部署一個集中的資料庫更好管理。15

自訂資料庫有各自的 GUID。安裝相同 GUID 的新版本時,舊版本會自動被取代。 部署則搭上 MSI 套件或啟動指令碼這類已經能以系統管理員權限執行的既有管道。15

自訂 .sdb 從建立到部署的流程用 Compatibility Administrator 建立自訂相容性資料庫並在測試機上測試,再用 sdbinst 套用到各台電腦,更新時安裝相同 GUID 的新版本,舊版本就會自動被取代以 Compatibility Administrator 建立在測試機上測試以 sdbinst 套用到各台電腦安裝相同 GUID 的新版本舊版本自動被取代會登錄到程式和功能

圖 16:自訂 .sdb 以建立、驗證、sdbinst 部署的流程展開,更新則以 GUID 管理。

已安裝的自訂資料庫也會登錄到「程式和功能(已安裝的應用程式)」,可用於盤點與確認移除。哪台電腦裝了哪個 .sdb,也要留在資產管理清冊裡。

9. 跑起來之後才要決定的事 ── 延續使用的維護與遷移的期限

9.1. 區分作業系統提供的修正與自家組織的套用判斷

就算靠 Shim 跑起來了,應用程式本身的問題並沒有被修好。Shim 是配合特定 API 用法的應急措施,作業系統的實作一旦改變,前提就可能崩掉。

Microsoft 提供的 Shim 本身,會作為 Windows 的一部分經由 Windows Update 維護。1 另一方面,用自訂資料庫套了什麼、那個組合能不能撐住業務,是由自家組織來管理的。請把每次功能更新都要驗證這件事,算進延續使用的成本裡。

作為應急措施的 Shim 與維護責任Shim 是配合特定 API 用法的謊言,作業系統的實作一旦改變前提就會崩掉;Microsoft 提供的 Shim 由 Windows Update 維護,但自訂資料庫所套的謊言由自家組織照顧,每次功能更新都要驗證就是延續使用的成本Shim 是應急措施的謊言作業系統實作一變,前提就崩掉Microsoft 提供的 Shim由 Windows Update 維護自訂資料庫的謊言由自家組織照顧每次功能更新的驗證就是延續使用的成本

圖 17:Shim 這個謊言的維護責任,分成 Microsoft 提供的部分與自家組織的自訂部分。

9.2. 依剩餘使用期間、依賴程度與驗證體制判斷

重要的是,不要只憑「相容模式跑得動」這個事實就決定長期使用。能靠 Shim 跑起來,只代表它剛好落進 Windows 準備好的承接範圍。請合併下列幾個軸來判斷。

判斷軸 偏向延續使用(Shim)的條件 偏向遷移、重寫的條件
剩餘使用期間 1~2 年內連同業務一起停用 前提是還要再用 5 年以上
原始碼 沒有(廠商消失、遺失) 有,或是能把資產取回
依賴的深度 只是使用者模式的 API 相容問題 依賴驅動程式、16 位元、專用硬體
替代手段 沒有套裝產品或新版本可用 遷移目標的產品、技術很明確
故障時的影響 停了也能用替代程序讓業務繼續 核心業務會直接受衝擊
驗證體制 每次功能更新都能做行為確認 沒有驗證資源,容易長期擱置

9.3. 決定延續使用,就把記錄、驗證、期限湊成一組

  1. 記錄。 留下對哪個 EXE、套用了哪些 Shim 與相容層、為什麼要套用。Layers 機碼的值與 .sdb 的 GUID 也寫進清冊。不要把「沒人知道為什麼跑得動」的狀態交給下一位負責人——這個想法,與接手了沒有原始碼也沒有規格書的系統所談的保全是一致的。
  2. 驗證。 在 Windows 功能更新時,確認延續使用中的應用程式能否啟動、主要操作是否正常。也與Windows 10 支援結束後的現實解方所談的作業系統汰換計畫連動。
  3. 訂出期限。 像「到下一次核心系統更新為止」「到 2028 年 3 月為止」這樣訂出延續使用的終點,並讓遷移的評估並行。
決定延續使用時的三件套維運把靠哪個 Shim 才跑得動記進清冊,每次功能更新都驗證以 Shim 延續使用中的應用程式的行為,並訂出延續使用的期限讓遷移的評估並行決定延續使用記錄:靠哪個 Shim 跑得動,寫進清冊驗證:每次功能更新都做行為確認期限:訂出延續使用的終點讓遷移的評估並行

圖 18:延續使用要把記錄、驗證、期限三件套,連同並行的遷移評估一起納入維運。

9.4. Shim 是用來為遷移的評估與準備爭取時間

遷移的選項會隨應用程式的技術而變。如果是 VB6 寫的,就以VB6 應用程式還能跑多久整理的全面重寫、自動轉換、分階段遷移三選一為起點。如果依賴 ActiveX/OCX,可以用ActiveX / OCX 現在該如何處理的「保留、包裝、取代」判斷表。

把 Shim 定位成為這類遷移專案安全爭取評估與準備期間的手段,才是健康的做法。

遷移這一側的選項與 Shim 的定位遷移的標準做法隨應用程式的技術而變,VB6 是全面重寫、自動轉換、分階段遷移三選一,依賴 ActiveX 則可用保留、包裝、取代的判斷表,而 Shim 的定位是為遷移專案安全爭取評估與準備期間VB6依賴 ActiveX爭取評估與準備的時間應用程式用的是什麼技術?重寫、自動轉換、分階段遷移保留、包裝、取代以 Shim 延續使用

圖 19:遷移的標準做法由應用程式的技術決定,Shim 的定位是為那段評估期間爭取時間。

10. 總結

相容模式是只為那支應用程式補上舊版 Windows 前提行為的機制。 作為核心的 Shim 以替換 IAT 等方式攔截 API 呼叫,補上版本判斷與存取位置。Windows 自己也透過預設的資料庫與 PCA 在使用它。

處理的順序是:先釐清是不是 Shim 的適用範圍,再用相容性索引標籤或 RunAsInvoker 確認需要的設定,組織部署時則以 Compatibility Administrator 與 sdbinst 管理。32 位元/64 位元的工具選擇、以實際使用者的權限驗證,以及用比對條件與 GUID 管理對象與版本,是實務上的重點。

不過它僅限使用者模式,也不是繞過安全性機制的手段。核心驅動程式、64 位元 Windows 上的 16 位元應用程式、直接存取硬體的問題,都需要其他對策。RunAsInvoker 也只是抑制不必要的提高權限要求,並不會增加權限。

跑起來之後,要記錄設定、每次功能更新都驗證、訂出期限讓遷移並行。 把這些都含進來,才算是決定依賴相容模式。

下次只勾一個選項就讓舊應用程式跑起來時,請這樣重新問一次:「這個應用程式是靠哪一句謊言在跑?那句謊言還能通用到什麼時候?」。答得出來,延續使用就是堂堂正正的策略。

相關文章

相關諮詢領域

小村軟體有限公司承接沒有原始碼的舊業務應用程式的行為調查與延續使用設計(Shim、相容模式的選定,自訂 .sdb 的建立與部署)、隨 Windows 11 遷移而來的既有應用程式相容性驗證,以及與延續使用並行的重寫、遷移計畫規劃。從「用相容模式跑起來了,但就這樣下去可以嗎」這個階段來諮詢也沒問題。

參考連結

  1. Microsoft Learn, Understanding and Using Compatibility Fixes. 相容性修正(Shim)以改寫 IAT(匯入位址表)重新導向 API 呼叫、動態連結靠攔截 GetProcAddress 處理、Shim 受到與應用程式相同的安全性約束因而無法繞過作業系統的安全性機制、僅限使用者模式而修不了驅動程式問題、Shim 能做的修正改程式碼同樣做得到、廠商支援已結束的應用程式等使用情境,以及 Microsoft 提供的相容性修正作為 Windows 的一部分出貨並經由 Windows Update 更新。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  2. Microsoft Learn, Compatibility Fixes for Windows 10, Windows 8, Windows 7, and Windows Vista. CorrectFilePaths、VirtualRegistry、ForceAdminAccess、RunAsAdmin/RunAsHighest/RunAsInvoker、WRPMitigation、EmulateGetDiskFreeSpace、GlobalMemoryStatusLie、LoadLibraryRedirect、VersionLie 系列等已知相容性修正的清單與說明、Compatibility Administrator 的 32 位元/64 位元版本分用,以及在已提高權限的狀態下測試會讓虛擬化與重新導向不如預期運作,因此應以實際使用的帳戶驗證。 ↩ ↩2 ↩3 ↩4 ↩5

  3. Microsoft Learn, Using the RunAsInvoker Fix. RunAsInvoker 相容性修正以從父處理程序繼承的權杖啟動應用程式、同時覆寫安裝程式偵測與資訊清單處理、以載入器旗標的形式套用而不攔截 API,以及能修改程式碼時在資訊清單宣告 asInvoker 才是本來該做的修正。 ↩ ↩2 ↩3 ↩4

  4. Microsoft Learn, Running 32-bit Applications. WOW64 是在 64 位元 Windows 上執行 32 位元應用程式並隔離檔案與登錄檔衝突的模擬層,以及 64 位元 Windows 不支援執行 16 位元應用程式,因控制代碼有效位元數的問題而以 ERROR_BAD_EXE_FORMAT 啟動失敗。 ↩

  5. Microsoft Learn, Registry Virtualization. 登錄檔虛擬化是把對 HKLM\Software 的全域寫入透明重新導向到每位使用者 VirtualStore 的相容技術、對象僅限 32 位元互動式處理程序且對在資訊清單指定 requestedExecutionLevel 的處理程序與 64 位元處理程序停用,以及它被定位成打算從未來 Windows 移除的暫時技術。 ↩ ↩2

  6. Microsoft Learn, High DPI Desktop Application Development on Windows. 未支援 DPI 的應用程式被視為固定以 96 DPI 繪製,在高 DPI 顯示器上 Windows 會拉伸點陣圖顯示因而看起來模糊,以及 DPI 感知模式(Unaware/System/Per-Monitor)的差異。 ↩ ↩2

  7. Microsoft Learn, Application Compatibility Database. 相容性基礎架構以 .sdb 格式的資料庫管理問題與解決方案、依可執行檔屬性進行比對、Apphelp(顯示訊息)與 Appfix(以 Shim 進行 API 攔截),以及把多個 Shim 與旗標綁成一組的相容層(模式)。 ↩

  8. Microsoft Learn, Program Compatibility Assistant scenarios for Windows 8. PCA 監視應用程式執行、偵測已知相容性問題的徵兆並建議套用建議的修正或自動套用(PINDLL、DISABLEUSERCALLBACKEXCEPTION、VIRTUALIZEDELETE、WRPMITIGATION 等),以及從相容性索引標籤與相容性疑難排解員套用修正。 ↩ ↩2

  9. Microsoft Learn, GetVersionExW function. 從 Windows 8.1 起 GetVersionEx 回傳的值取決於資訊清單、未針對 Windows 8.1/10 撰寫資訊清單的應用程式會拿到 Windows 8 的版本值(6.2),以及啟用相容模式時會回報所選作業系統的版本。 ↩ ↩2

  10. Microsoft Learn, Targeting your application for Windows. 在應用程式資訊清單的 compatibility 區段以 supportedOS 元素宣告支援作業系統 GUID 的方法、沒有宣告時的行為,以及不含 trustInfo 的 32 位元 x86 應用程式會成為 UAC 檔案虛擬化(把寫入重新導向到 VirtualStore)的對象。 ↩

  11. Microsoft Learn, DXGI overview. 應用程式相容設定會保存在登錄檔的 HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers 機碼(以 DXGI 的相容設定為例)。 ↩

  12. Microsoft Learn, Download and install the Windows ADK. Windows ADK 包含 Compatibility Administrator 與 Standard User Analyzer、選擇 ADK 版本的思路,以及下載與安裝的方法。 ↩

  13. Microsoft Learn, Compatibility Administrator User’s Guide. Compatibility Administrator 提供套用相容性修正、相容模式與 AppHelp 訊息以及建立自訂資料庫的功能,且會同時安裝 32 位元版與 64 位元版,32 位元應用程式必須用 32 位元版、64 位元應用程式必須用 64 位元版。 ↩

  14. Microsoft Learn, Creating a Custom Compatibility Fix in Compatibility Administrator. 相容性修正(舊稱 Shim)是攔截 API 呼叫的一小段程式碼、在自訂資料庫建立 Application Fix 的步驟(指定應用程式名稱、廠商與目標 EXE、選擇相容模式、選擇額外的 Shim、設定比對條件),以及應在縮小比對資訊的同時保留能正確識別應用程式的條件。 ↩ ↩2

  15. Microsoft Learn, Compatibility Fix Database Management Strategies and Deployment. 自訂相容性資料庫的管理策略建議採用集中管理型資料庫、相容性修正應包含版本檢查(比對條件)以免套用到新版本、以 Sdbinst.exe 進行本機安裝(-q、-u、-g 選項)、安裝資料庫 GUID 相同的新版本會自動解除安裝舊版本,以及以 MSI 或指令碼部署的方法。 ↩ ↩2 ↩3 ↩4

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

勾選相容模式之後就跑得動的應用程式,可以一直這樣用下去嗎?
就維持眼前的業務運轉而言,繼續用沒有問題。相容模式的本體是稱為 Shim 的使用者模式 API 攔截,是作業系統正式提供的一套設定機制。不過 Shim 終究是不修改應用程式就讓它跑起來的應急措施,一旦作業系統更新改變了前提,它仍可能再次失效。請把「靠相容模式才跑得動」這件事記進清冊,並和「要重寫這個應用程式,還是有計畫地延續使用」的判斷放在一起來安排維運。
相容模式的核取方塊具體做了什麼?
在內容的相容性索引標籤儲存設定後,目標 EXE 的路徑以及「WINXPSP3」「HIGHDPIAWARE」這類值會被寫進 HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers 機碼。下次啟動該 EXE 時,Windows 載入器會讀取這個值,把對應的相容層(一組 Shim)套用到處理程序上。例如選擇 Windows XP 相容模式時,會啟用對查詢作業系統版本的 API 回傳舊版本號的版本偽裝等修正。它並沒有改變作業系統本身的行為,只是單獨對那個處理程序擺出「舊版 Windows 的樣子」。
16 位元時代的舊應用程式能在 64 位元 Windows 的相容模式下執行嗎?
不能。64 位元 Windows 用 WOW64 這套機制執行 32 位元應用程式,但不支援執行 16 位元應用程式,嘗試啟動會以 ERROR_BAD_EXE_FORMAT 失敗。這是 Shim 無法繞過的架構限制。只有安裝程式的啟動部分是 16 位元的舊安裝套件,也會因為同樣的原因失敗。如果真的非用不可,就只能考慮相容模式以外的手段,例如使用裝有 32 位元版 Windows 的虛擬機器。
「不以系統管理員身分執行就無法啟動」的應用程式,能用標準使用者權限執行嗎?
值得一試的是 RunAsInvoker。在命令提示字元執行 set __COMPAT_LAYER=RunAsInvoker 之後再啟動應用程式,資訊清單中的 requireAdministrator 指定以及安裝程式偵測所引發的提高權限要求都會被抑制,應用程式會以與呼叫端相同的(標準使用者)權限啟動。如果應用程式只是「要求系統管理員權限,實際上並沒有使用」,光是這一步就能把提高權限從日常維運中拿掉。不過權限並不會因此增加,真正需要系統管理員權限的處理仍會在應用程式內部失敗。請確認行為正常之後再採用。
Compatibility Administrator 可以從哪裡取得?
它包含在 Windows ADK(Windows Assessment and Deployment Kit)裡。從 Microsoft 網站下載 ADK,安裝時選擇 Application Compatibility Tools 這一類功能即可使用。32 位元版與 64 位元版都會被安裝,要注意的是:修正 32 位元應用程式要用 32 位元版,修正 64 位元應用程式要用 64 位元版。做好的自訂相容性資料庫(.sdb)在各台電腦上以 sdbinst 命令套用。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽