IE 模式之後改用 WebView2 就好嗎 ── ActiveX 無法運作的限制與現實的遷移設計
· 小村 豪 · WebView2, Windows, .NET, WPF, Windows Forms, IE 模式, ActiveX, 舊系統遷移, 內部系統, 技術諮詢
在之前的文章〈如何延續並脫離依賴 IE 模式的內部 Web 系統〉中,我提到 IE 模式終究只是有期限的延命措施,應該同時設計脫離的出口。而在接受「出口」相關諮詢時,經常出現的選項就是 WebView2。「想在專用應用程式中顯示內部 Web 系統」「想只用 Web 技術做桌面應用程式中的部分畫面」「聽說 Electron 很重,有沒有替代方案」──這些場合都會讓 WebView2 成為候選方案。
另一方面,WebView2 在導入之前也有一些必須先了解的特性:執行環境要怎麼配布、使用者資料資料夾要放在哪裡、原生端和 Web 端要怎麼互相溝通。而最重要的是,原本在 IE 模式下運作的 ActiveX,在 WebView2 中無法執行,這是關係到遷移計畫根本的限制。本文將整理 WebView2 的基本結構、配布方式、設計、安全性,一路談到與脫離 IE 模式現實結合的方式。
1. 先下結論
- WebView2 是把以 Chromium 為基礎的 Microsoft Edge 內嵌到 Windows 應用程式中的控制項。可以從 WinForms / WPF / WinUI / Win32 C++ 呼叫,適合用在既有桌面應用程式中「只加入部分 Web UI」的場景。1
- 執行環境原則上使用 Evergreen(自動更新的共用執行環境)。雖然 Windows 11 已標準內建,但不應假設「一定已經安裝」,官方建議在安裝程式中內建存在檢查與啟動安裝(bootstrap)流程。2
- 針對離線環境或希望固定已驗證組態的工廠、生產線,可以使用 Fixed Version(隨應用程式一併發布),但隨附檔案會超過 250MB,並且必須自行負責發布安全性更新。請不要輕易選用。3
- 最先容易踩到的是使用者資料資料夾(UDF)的問題。UDF 預設會建立在 exe 旁邊,因此安裝在 Program Files 底下的應用程式會啟動失敗。請把明確指定
%LOCALAPPDATA%底下的資料夾當作固定做法。4 - 原生端與 Web 端的連結,基本上以
PostWebMessageAsJson/WebMessageReceived的訊息交換為主,AddHostObjectToScript(公開 COM 物件)則應限定於可信任的內容。1 - WebView2 中無法執行 ActiveX。 含有 ActiveX 的 IE 模式依賴頁面,不能只靠「換成 WebView2」了事,必須把原本由 ActiveX 負責的處理移到原生端重新設計。這正是脫離 IE 模式計畫的核心所在。5
2. WebView2 的基本結構
WebView2 由「SDK(內嵌到應用程式中的 API)」與「執行環境(安裝在客戶端的 Edge 基礎執行環境)」兩部分組成。這與 Visual C++ 執行環境或 .NET 執行環境的架構相同:應用程式參考 NuGet 套件 Microsoft.Web.WebView2 進行組建,執行時則使用客戶端上的執行環境來運作。3
支援的平台相當廣泛,可以在 .NET Framework 4.6.2 以上/.NET Core 3.1 以上的 WinForms、WPF、WinUI、Win32 C++ 中使用。像是只把既有 WinForms 業務應用程式的其中一個畫面換成 WebView2 這種階段式用法,正是相對於整體換掉框架(例如 Electron)的一大優勢。UI 框架本身的選型,也請參考〈WinForms / WPF / WinUI 該如何選擇 - 判斷表〉。
最小的內嵌方式大致如下面的程式碼(WPF/WinForms 共通的想法)。
var env = await CoreWebView2Environment.CreateAsync(
browserExecutableFolder: null, // 使用 Evergreen 執行環境
userDataFolder: Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"KomuraSoft", "MyApp", "WebView2"));
await webView.EnsureCoreWebView2Async(env);
webView.CoreWebView2.Navigate("https://internal.example.co.jp/app/");
重點在於不依賴預設值,而是自行建立 CoreWebView2Environment。理由會在接下來的兩章中說明。
導入步驟本身很直觀,WinForms / WPF 的話大致是下面的流程。
- 透過 NuGet 把
Microsoft.Web.WebView2加入專案(設計工具的工具箱中也會出現 WebView2 控制項) - 在表單/視窗中放置控制項
- 如上面的程式碼一樣,先用
EnsureCoreWebView2Async初始化,再呼叫Navigate
這裡有一個一開始就務必掌握的 API 注意事項:webView.CoreWebView2 在初始化完成之前是 null。在表單建構函式中嘗試訂閱事件,像是 CoreWebView2.WebMessageReceived += ...,結果變成 NullReferenceException,是常見的踩坑,初始化相關的處理應統一放在「EnsureCoreWebView2Async 的 await 之後」,這是基本做法。對 Source 屬性賦值也會隱含地啟動初始化,但如果想指定環境(例如 UDF 的位置)的應用程式,統一先明確呼叫 EnsureCoreWebView2Async(env) 會更不容易出錯。
另外,WebView2 的事件全都是在 UI 執行緒上觸發的。如果在 WebMessageReceived 中直接寫入繁重的處理(例如裝置存取或檔案 I/O),連帶 Web 端的操作感也會一起卡住,因此原生端的處理應該用 async/await 讓出執行緒。這方面的原則,可以直接套用〈WPF/WinForms 的 UI 執行緒與 async/await〉一文中寫的內容。
3. 執行環境配布 ── Evergreen 與 Fixed Version
3.1 Evergreen(建議使用)
Evergreen 是所有 WebView2 應用程式共用安裝在客戶端上的執行環境,並且該執行環境會自動更新的方式。因為安全性修補會自動套用、磁碟佔用也較小,官方明確建議使用這種方式。6
實務上要注意的重點有 3 個。
- 實作存在檢查。 雖然 Windows 11 已標準內建,Windows 10 也已廣泛配布,但仍然存在「沒有安裝」的終端裝置。在 .NET 中可以用
CoreWebView2Environment.GetAvailableBrowserVersionString()確認,但在尚未安裝執行環境的環境中,這個呼叫本身就會以例外(WebView2RuntimeNotFoundException)失敗,因此要用 try/catch 包起來,把「發生例外=尚未安裝」當作判斷依據,並在安裝流程中接續執行啟動安裝程式(bootstrapper,一個小型的線上安裝程式)或獨立安裝程式。2 - 設計對執行環境更新的追蹤。 即使執行環境已更新,正在執行中的應用程式仍會繼續使用舊版本。建議的做法是攔截
NewBrowserVersionAvailable事件,建立「重新啟動後套用更新」的引導流程。2 - 與內部的更新管理政策保持一致。 Edge 瀏覽器與 WebView2 執行環境的更新政策是各自獨立的。在透過群組原則停止執行環境更新的環境中,Evergreen 的前提(永遠是最新版本)會不成立,因此若要使用較新的 API,應加入功能偵測。6
3.2 Fixed Version(限定用途)
Fixed Version 是把特定版本的執行環境隨應用程式一併發布的方式。因為可以凍結已完成驗證的組態,所以在離線的生產設備,或變更管理極為嚴格的環境中,會是合理的選擇。不過,
- 隨附的二進位檔案會超過 250MB,發布物也會因此變大2
- 由於執行環境不會自動更新,因此必須自行負責透過自己的發布版本,發送瀏覽器引擎的漏洞修補
- 一旦疏於更新,公司內部就會持續留下「搭載舊版 Chromium 的業務應用程式」
這些都是相當沉重的代價。只有在顯示的內容完全封閉、由自家管理,並且發布週期中已納入執行環境更新的體制時,才應該選用 Fixed Version。
4. 最先容易踩到的陷阱 ── 使用者資料資料夾
WebView2 會把 Cookie、快取、權限等內容儲存在使用者資料資料夾(UDF)中。如果不指定 UDF 的位置,預設會嘗試在預設位置(多數組態下會是 exe 旁邊)建立,因此安裝在 Program Files 底下的應用程式會寫入失敗,發生初始化錯誤。這是一種典型的「發布之後才發現」的問題:在開發機(偵錯執行、可寫入的資料夾)上正常運作,一旦安裝就無法啟動。4
對策很單純,就是像前面的程式碼範例一樣,永遠明確指定 %LOCALAPPDATA% 底下的應用程式專用資料夾。同時也要在設計中納入以下幾點。
- UDF 依使用者、依應用程式分開(不要在多個應用程式間共用)
- 不要放在網路磁碟機上(會造成速度下降、損毀、資料遺失)4
- 事先決定在解除安裝或「清除登入資訊」功能中刪除 UDF 的步驟(如果維運人員不知道 Cookie 或網站資料存放的位置,在整理離職員工的終端裝置等場合就容易遺漏)
可以把這件事想成前一篇文章〈業務用 Windows 應用程式的本機資料儲存〉中提到「不要寫入 exe 旁邊」原則的 WebView2 版本。
5. 原生 ⇔ Web 的連結設計
要讓 WebView2 不只是一個「單純的瀏覽器畫框」,關鍵就在於原生程式碼與 Web 內容之間的相互連結。手段主要有兩種。1
5.1 Web 訊息(基本形式)
原生端用 PostWebMessageAsJson 傳送 JSON,Web 端則用 window.chrome.webview.addEventListener("message", ...) 接收;反方向則是 window.chrome.webview.postMessage(...) 與 WebMessageReceived 事件。因為是鬆散耦合,而且可以在單一處檢查對外公開的操作,所以應先把這個方式當作預設的連結手段。
// 原生 → Web
webView.CoreWebView2.PostWebMessageAsJson(
JsonSerializer.Serialize(new { type = "deviceStatus", connected = true }));
// Web → 原生
webView.CoreWebView2.WebMessageReceived += (s, e) =>
{
// 不處理非預期來源(例如頁面已跳轉到外部網站後)的訊息
if (!e.Source.StartsWith("https://internal.example.co.jp/", StringComparison.Ordinal))
return;
AppMessage? msg;
try { msg = JsonSerializer.Deserialize<AppMessage>(e.WebMessageAsJson); }
catch (JsonException) { msg = null; }
if (msg?.Type is null)
return; // 格式不正確的在這裡捨棄(需要的話記錄日誌)
// 依 type 只執行允許的操作
};
Web 端(JavaScript)就這樣接收。不需要特別的函式庫,只要使用 WebView2 注入的 window.chrome.webview 物件即可。
// 接收來自原生端的訊息
window.chrome.webview.addEventListener("message", (e) => {
if (e.data.type === "deviceStatus") {
updateStatusBadge(e.data.connected);
}
});
// 向原生端發送請求
document.getElementById("print-label").addEventListener("click", () => {
window.chrome.webview.postMessage({ type: "printLabel", copies: 2 });
});
接收端應如上面的程式碼一樣,先檢查 e.Source(發送訊息的頁面 URI),然後徹底執行「用白名單檢查訊息的 type,非預期的情況一律忽略並記錄日誌」。由於 Web 端只要一個連結、一次重新導向就可能跳轉到外部網站,因此請不要因為「現在顯示的應該是自己的頁面」這種假設而省略來源檢查。反過來說,在 Web 端也可以加入 window.chrome.webview 不存在時(例如用一般瀏覽器開啟時)的備用邏輯,這樣就能單獨用瀏覽器偵錯 Web UI 部分,提升開發效率。
5.2 公開主機物件(功能強大但應限定使用)
使用 AddHostObjectToScript,就能讓 .NET/COM 物件直接被 JavaScript 呼叫。內部機制其實是 COM,本公司長年經手的 COM 技術在這種地方依然活躍,是相當有趣的一點,但讓 Web 內容直接握有原生物件,也意味著一旦頁面遭入侵,影響範圍也會同樣大。公開的對象應限定於自家管理的內容,公開的方法也應縮到必要的最小限度。原則是:可能顯示不受信任頁面的 WebView,不應註冊主機物件。
5.3 讀取本機內容
如果要把 HTML/JS 隨應用程式一併發布並顯示,固定做法不是直接讀取 file://,而是用 SetVirtualHostNameToFolderMapping 把資料夾對應到虛擬主機名稱。這樣一來,內容就會擁有類似 https://appassets.example/ 的來源(origin),因此像 localStorage 這類以來源為前提的 Web API 就能正常使用,也能指定跨來源存取的允許等級。主機名稱應使用實際上不可能存在的保留網域(例如 .example),存取類型則從必要的最小限度(先設定為 DenyCors)開始。7
6. 脫離 IE 模式與 WebView2 ── ActiveX 無法運作
這是本文最重要的一節。IE 模式之所以能夠延命,是因為 Edge 內部運作著真正的 IE11(Trident 引擎),ActiveX 與瀏覽器協助程式物件(BHO)能夠照常運作。5 另一方面,WebView2 是 Chromium,沒有承載 ActiveX 的機制。也就是說,
「把在 IE 模式下運作的內部系統,換成用 WebView2 製作的外殼」,只有在不依賴 ActiveX 的畫面上才能成立。
必須在這樣的限制之下規劃遷移計畫。現實可行的遷移順序如下。
- 盤點現況:把依賴 IE 模式的頁面分類成「使用 ActiveX 等 IE 專屬技術的畫面」與「單純只是老舊架構的畫面」(可以直接沿用〈IE 模式文章〉中的網站清單盤點方法)。
- 非 IE 專屬的畫面:改修為支援現代瀏覽器,直接用 Edge 顯示;若想整合進業務終端裝置的應用程式,則改用 WebView2 外殼承載。
- 依賴 ActiveX 的畫面:把原本由 ActiveX 負責的功能(序列通訊、檔案存取、專用裝置控制等)移到原生端(WebView2 的主機應用程式),重新設計成透過 Web 訊息呼叫的形式。可以想像成把「瀏覽器裡的 ActiveX」翻轉成「應用程式裡的 Web UI +原生處理」。
- 至於 ActiveX 本身要保留、包裝,還是替換,可以直接套用〈ActiveX/OCX 該維持、包裝,還是替換 - 判斷表〉的判斷標準。
第 3 點的重新設計正是導入 WebView2 的實質工作量所在,在規劃階段就必須先調整好期望值:這並不是「導入 WebView2 就能脫離 IE 模式」這麼單純的事。反過來說,只要完成把 ActiveX 功能移到主機應用程式的設計,UI 就能改用 Web 技術自行開發、維護,而發布方式又能以桌面應用程式的形式統一管理,可以兩者兼得。
7. 內部系統一定會被問到的實作課題
在檢討是否採用 WebView2 時,業務端一定會提出幾個問題。這裡先整理起來。
7.1 列印與報表
「用 IE 的時候,按下列印按鈕就會印出報表」這樣的需求,在 WebView2 中可以用兩種方式滿足。
- 直接列印畫面:用
CoreWebView2.ShowPrintUI()顯示列印對話框,或是用PrintAsync進行無人值守列印。因為效果等同於瀏覽器的列印功能,CSS 的列印設定(@media print)可以直接生效。 - 輸出為 PDF:用
PrintToPdfAsync可以把目前顯示的頁面轉存成 PDF 檔案。對於「報表輸出成 PDF 後存到共用資料夾」這類業務流程,因為原生端能統一管理檔案名稱與儲存位置,比較適合採用這個方式。1
像是需要像素等級對齊的複寫式單據這類報表,與其用 Web 列印硬是調整到位,也應該考慮改用原生端的報表輸出方式(也就是〈Excel 報表製作方法〉一文中整理的方式)。
7.2 檔案的下載與上傳
下載功能即使不做任何設定,預設也會像瀏覽器一樣運作,但在業務應用程式中,固定做法是透過 DownloadStarting 事件介入處理。可以做到固定儲存位置、依副檔名判斷允許或拒絕、把預設的下載 UI 換成應用程式自己的通知等控管。1 上傳(<input type="file">)則不需要特別實作,會直接開啟 OS 的檔案選擇對話框。
7.3 認證與 SSO
如果內部 Web 系統採用 Windows 整合驗證(NTLM/Kerberos),在 WebView2 上大致也能像瀏覽器一樣通過。對於使用 Basic 驗證的舊系統,可以透過 BasicAuthenticationRequested 事件提供憑證,甚至可以做到不顯示登入畫面──不過這個憑證要儲存在哪裡,正是〈DPAPI 文章〉中提到的話題。如果想讓 Microsoft Entra ID(舊稱 Azure AD)的 SSO 透過 OS 的登入資訊通過驗證,可以考慮啟用環境選項 AllowSingleSignOnUsingOSPrimaryAccount。
由於 Cookie 是儲存在 UDF 中,即使重新啟動應用程式,登入狀態也會維持。如果希望「透過登出功能確實清除工作階段」,請加入用 CookieManager 明確刪除 Cookie 的實作。
7.4 開發時的偵錯
因為 WebView2 內部就是 Chromium,開發時可以直接使用 F12 的 DevTools(CoreWebView2Settings.AreDevToolsEnabled 預設為啟用)。此外,如前面所述,只要把 Web UI 端設計成「單獨用瀏覽器也能運作」,就能把 UI 的開發、偵錯當成普通的 Web 開發來進行,只在 WebView2 上確認原生連結部分,做到分工。也就是說,即使把 Web 資產封裝進應用程式裡,開發體驗依然能維持 Web 開發的樣貌。
8. 安全性設計的要點
由於 WebView2 應用程式是「內建瀏覽器的應用程式」,因此應以相當於瀏覽器的威脅模型來思考。
- 限定顯示的內容:在
NavigationStarting中用內部網域的白名單檢查跳轉目標,非預期的 URL 就轉交給預設瀏覽器開啟(NewWindowRequested也做同樣的處理)。 - 縮小跨越信任邊界的功能:主機物件的公開範圍、Web 訊息允許的操作都應縮到最小限度。把可能顯示外部網站的 WebView 與具有原生連結的 WebView 分開,也是有效的做法。
- 依環境調整提供給使用者的功能:透過
CoreWebView2Settings,可以只保留必要程度的「瀏覽器特性」。在資訊站終端或現場終端上先收緊設定,能減少意外發生。 - 若使用 Fixed Version,須自行負責更新計畫:如前所述,漏洞修補的發布會變成應用程式端的責任。6
以下列出 CoreWebView2Settings 中經常調整的項目。建議把「正式版組建要怎麼設定」納入發布前的檢查清單中。
| 設定 | 預設值 | 現場終端・正式環境的典型做法 |
|---|---|---|
AreDevToolsEnabled(F12 開發人員工具) |
啟用 | 正式環境中停用 |
AreDefaultContextMenusEnabled(右鍵選單) |
啟用 | 不想讓使用者使用「上一頁」「重新載入」的畫面中停用 |
AreBrowserAcceleratorKeysEnabled(Ctrl+F5 等快速鍵) |
啟用 | 資訊站用途中停用 |
IsStatusBarEnabled(顯示連結目標) |
啟用 | 依喜好決定 |
IsZoomControlEnabled(Ctrl+滾輪縮放) |
啟用 | 版面會跑掉的業務畫面中停用 |
AreHostObjectsAllowed(主機物件) |
啟用 | 不使用的話就停用 |
與其說這些是「停用就安全」,不如說它們是用來「關閉應用程式預期操作以外的入口」的工具。若要全面提升 Windows 應用程式的安全性,也請一併參考〈Windows 應用程式安全性最低檢查清單〉。
9. 採用判斷整理
| 架構 | 適合的場景 | 注意事項 |
|---|---|---|
| 用 Edge(瀏覽器)顯示 | 一般的內部 Web 系統 | 無法整合應用程式、無法進行原生連結 |
| 既有應用程式+WebView2 承載部分 Web UI | 以畫面為單位進行現代化改造、重複利用 Web 資產 | UDF、執行環境配布、連結設計(本文) |
| WebView2 外殼+原生功能移植 | 依賴 ActiveX 的 IE 模式資產的出口 | 重新實作 ActiveX 功能是核心工作 |
| Electron 等 | 必須跨平台的情況 | 若只用於 Windows 會偏重,發布物與記憶體用量增加 |
| 用純原生(WPF 等)重新製作 | 沒有 Web 資產、以離線為前提 | 需要與開發成本權衡 |
如果是「僅限 Windows 使用的內部應用程式,想使用 Web 技術製作 UI」,那麼 WebView2 會比 Electron 更適合作為預設選項。因為可以與 OS 端共用執行環境,所以發布負擔較輕,與既有 .NET 資產的整合也更直觀。
10. 總結
WebView2 是一項可以把以 Chromium 為基礎的 Web UI,當作零件內嵌到 Windows 應用程式中的技術,與內部系統的現代化改造相當契合。導入時的實務要點有三個:Evergreen 執行環境的存在檢查與更新追蹤、明確指定使用者資料資料夾,以及以 Web 訊息為基礎的連結設計。而在計畫面,則要正視 ActiveX 無法運作的限制,把將 ActiveX 功能移到原生端的重新設計,放在工作量的核心位置。
如果一邊留意著 IE 模式的期限,一邊在想「差不多該找出口了」,那麼從盤點目標系統、拆解依賴 ActiveX 部分的功能開始,會是最踏實的做法。這方面的推進方式,有不少地方需要看實際的系統架構才容易判斷,如果猶豫不決,歡迎與我們洽詢。
相關文章
- 如何延續並脫離依賴 IE 模式的內部 Web 系統
- ActiveX/OCX 該維持、包裝,還是替換 - 判斷表
- COM・ActiveX・OCX 是什麼
- WinForms / WPF / WinUI 該如何選擇 - 判斷表
相關的諮詢領域
合同會社小村軟體承接依賴 IE 模式、ActiveX 的內部系統出口設計、運用 WebView2 進行階段式現代化改造,以及將 Web UI 整合到既有 Windows 應用程式的相關諮詢。
參考連結
-
Microsoft Learn, Overview of WebView2 APIs。關於導覽管理、本機內容讀取、主機⇔Web 間通訊(Web 訊息、主機物件)等 WebView2 功能的整體概觀。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Distribute your app and the WebView2 Runtime。關於透過啟動安裝程式/獨立安裝程式進行配布、偵測是否已安裝、用 NewBrowserVersionAvailable 追蹤更新,以及 Fixed Version 的隨附步驟(超過 250MB)。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Evergreen vs. fixed version of the WebView2 Runtime。關於執行環境兩種配布模式的差異、Windows 11 的標準內建,以及 Fixed Version 的優缺點。 ↩ ↩2
-
Microsoft Learn, Manage user data folders。關於使用者資料資料夾的角色、自訂 UDF 所需的讀寫權限,以及放在網路磁碟機上會造成速度下降、當機、資料遺失的原因。 ↩ ↩2 ↩3
-
Microsoft Learn, What is Internet Explorer (IE) mode?。關於 IE 模式以 Trident (MSHTML) 引擎運作,並支援 ActiveX 控制項與瀏覽器協助程式物件(也就是以 Chromium 為基礎的 WebView2 並不具備這項支援)。 ↩ ↩2
-
Microsoft Learn, Development best practices for WebView2 apps。關於建議使用 Evergreen、執行環境更新的處理方式、功能偵測,以及使用 Fixed Version 時定期更新的必要性。 ↩ ↩2 ↩3
-
Microsoft Learn, Using local content in WebView2 apps。關於透過虛擬主機名稱對應讀取本機內容、賦予來源(origin)帶來的優點,以及存取類型(DenyCors 等)的指定方式。 ↩
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
在 WinForms/WPF 應用程式中導入 Entra ID 驗證 ── MSAL.NET 與 WAM 代理的實務架構
從實務角度整理在 WinForms/WPF 桌面應用程式中導入 Entra ID(原 Azure AD)驗證的做法。內容涵蓋公用客戶端的概念、ROPC 廢除現況、應用程式註冊、MSAL.NET 的 AcquireTokenSilent 模式、WAM 代理、權杖快取持久化,以...
WPF 高 DPI 對應──「不是應該對 DPI 很強嗎」卻仍模糊、暈邊的原因與對策
WPF 以 DIP(1/96 英吋)進行版面配置,一開始就是 System DPI Aware,但移到 DPI 不同的螢幕時整體會暈邊,點陣圖與細線也會模糊。本文從實務角度整理原因判斷、.NET Framework 4.6.2/.NET 上的 Per-Monitor DPI...
委外・委託開發 Windows 應用程式前該整理的事項
在委外・委託開發 Windows 應用程式之前,整理既有軟體改版、設備整合、COM/ActiveX、發布與更新、維護等應留意的重點。
Windows 業務應用程式的列印與 PDF 輸出 ── System.Drawing.Printing / WPF / 報表函式庫的取捨
本文以要件別判斷表整理 PrintDocument 的 WinForms 列印、WPF 的 FlowDocument/FixedDocument 列印,以及 PDF 輸出的各種選項。並從實務角度說明分頁控制、DPI 落差等實作陷阱,以及從 Windows 服務列印、依賴預設...
如何理解 Windows 的工作階段隔離 ── Session 0・RDP・多使用者同時執行
整理 Windows 應用程式開發者容易混淆的「工作階段」概念。說明服務無法顯示 UI 的 Session 0 隔離原因、RDP 連線時工作階段的行為、具名物件的工作階段隔離,以及共用 PC・RDS 環境常見的設計失誤,從實務角度解說。
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
ActiveX 遷移
整理保留、包裝或替換 COM / ActiveX / OCX 資產的階段性判斷的主題頁面。
UI 執行緒 & 計時器
整理 WPF / WinForms UI 執行緒、非同步流程、Dispatcher 使用、計時器判斷的主題頁面。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
Windows 應用程式開發
支援包含常駐處理、設備連動、運作日誌與可維護結構的 Windows 桌面應用程式。
技術諮詢 & 設計審查
協助釐清設計方向、架構邊界、生命週期責任,以及既有 Windows 資產的處理方式。
常見問題
整理諮詢這個主題時常見的問題。
- WebView2 可以執行 ActiveX 嗎?
- 不行。IE 模式是在 Edge 內部執行真正的 IE11(Trident 引擎),因此 ActiveX 可以照常運作;但 WebView2 是以 Chromium 為基礎,沒有承載 ActiveX 的機制。因此,依賴 ActiveX 的畫面無法只靠「換成 WebView2」就解決,必須把原本由 ActiveX 負責的序列通訊、檔案存取、專用裝置控制等功能移到原生端(主機應用程式),改成透過 Web 訊息呼叫的架構重新設計。這個重新設計正是導入 WebView2 的實質工作量所在。
- WebView2 的執行環境該選 Evergreen 還是 Fixed Version?
- 原則上應選擇 Evergreen(自動更新的共用執行環境),因為安全性修補會自動套用、磁碟佔用也較小,官方也明確建議使用。雖然 Windows 11 已標準內建,但仍有部分尚未安裝的終端裝置,因此需要在安裝程式中內建存在檢查與啟動安裝(bootstrap)流程。Fixed Version(應用程式隨附)的隨附檔案會超過 250MB,而且需要自行負責發布瀏覽器引擎的漏洞修補,因此只應在離線的製造裝置或變更管理極為嚴格的環境等有限場景下選用。
- 為什麼 WebView2 應用程式安裝後無法啟動?
- 最典型的入門陷阱就是使用者資料資料夾(UDF)的問題。WebView2 會把 Cookie、快取、權限存放在 UDF 中,如果不指定位置,預設會嘗試在 exe 旁邊建立,導致安裝在 Program Files 底下的應用程式寫入失敗而發生初始化錯誤。這是一種典型的「開發機上正常運作,一旦安裝就無法啟動」的問題。對策是在建立 `CoreWebView2Environment` 時,永遠明確指定 `%LOCALAPPDATA%` 底下的應用程式專用資料夾。放在網路磁碟機上也會造成速度下降、資料損毀的問題,應避免。
- WebView2 中原生程式碼與 Web 頁面要怎麼連結?
- 基本方式是透過 Web 訊息進行鬆散耦合的連結。原生端使用 `PostWebMessageAsJson` 傳送 JSON,Web 端則透過 `window.chrome.webview` 的 message 事件接收;反方向則是 `postMessage` 與 `WebMessageReceived` 事件。接收端應以 `e.Source` 檢查訊息來源的 URI,並以白名單檢查訊息的 type,這一點非常重要。另外也可以用 `AddHostObjectToScript` 直接公開 .NET/COM 物件,但一旦頁面遭入侵,影響範圍會相當大,因此應限定於自家管理的內容,並將公開的方法縮到最小限度。
作者檔案
本文作者的個人檔案頁面。
Go Komura
小村軟體有限公司 代表
以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。