實驗概覽
本實驗將引導您體驗 UAC (User Account Control) 虛擬化機制,並逐步解決因檔案重導向造成的相容性問題。您將學會如何:
- 疑難排解檔案重導向問題
- 使用 Process Monitor 找出問題根因
系統需求
- Microsoft Visual Studio 2008
- Microsoft Windows 7
- Process Monitor (Sysinternals) - 下載連結
練習:體驗使用者帳戶控制虛擬化
本練習診斷一個不支援 UAC 虛擬化的受控應用程式,特別是檔案重導向至 VirtualStore 資料夾的行為。
任務 1:無資訊清單檔情況下執行應用程式 (模擬舊版應用程式)
- 確認 UAC 已啟用: 控制台 > 使用者帳戶 > 變更使用者帳戶控制設定,滑桿保持預設位置。
- 開啟
DataRedirection 解決方案,將 BrokenAppManaged 設為啟動專案。
- 確認 Visual Studio 未 以系統管理員身分執行 (標題列不應顯示 Administrator)。
- 專案屬性 > 應用程式 > 資訊清單:選擇 不含資訊清單建立應用程式。
- 檢視
FileIO.cs 中 Save/Load 方法與靜態建構函式,觀察資料檔路徑指向 Program Files\BrokenApp。
- 建置並執行 (非管理員)。開啟工作管理員 > 程序分頁 > 檢視 > 選取欄位 > 勾選 UAC 虛擬化,確認該程序為「已啟用」。
- 在編輯框輸入文字並按「儲存」——操作應成功無錯誤。
- 嘗試前往實際路徑 (
C:\Program Files (x86)\BrokenApp 或 C:\Program Files\BrokenApp)——找不到資料夾,因寫入已被重導向至 VirtualStore。

任務 2:使用 Process Monitor 找出問題根因
- 下載並啟動 Process Monitor (ProcMon)。
- 啟動
BrokenAppManaged 應用程式。
- 確認 ProcMon 正在擷取 (工具列第三個按鈕或 Ctrl+E)。
- 在應用程式輸入文字並按「儲存」。
- 停止擷取 (Ctrl+E)。
- 工具 > 程序樹,找到
BrokenAppManaged.exe 雙擊選取。
- 在 ProcMon 主視窗右鍵點擊程序名 > 「包含 'BrokenAppManaged'」進行篩選。
- 觀察結果:REPARSE 為原始寫入嘗試,SUCCESS 為重導向後的實際寫入 (至
VirtualStore)。







任務 3:加入 UAC 資訊清單檔 (宣告支援 UAC)
- 專案屬性 > 應用程式 > 資訊清單:選擇 內嵌預設設定的資訊清單 (預設包含 UAC 節點,
requestedExecutionLevel 為 asInvoker)。
- 重新建置並執行。
- 工作管理員確認 UAC 虛擬化現為「已停用」。
- 再次嘗試儲存——出現「拒絕存取」錯誤,因虛擬化關閉,直接寫入受保護的 Program Files 失敗。



任務 4:修正「拒絕存取」錯誤 (將資料檔移至正確位置)
- 回到
FileIO.cs 的靜態建構函式。
- 註解掉使用
Environment.SpecialFolder.ProgramFiles 的程式碼。
- 取消註解使用
Environment.SpecialFolder.CommonApplicationData (對應 C:\ProgramData) 的程式碼——此資料夾所有使用者皆可存取。
- 重新建置並執行,確認資料檔儲存於
C:\ProgramData\BrokenApp,操作成功無重導向。
補充:如何在 Visual Studio 2008 中關閉 UAC (僅供教學示範)
- C# 專案: 專案 > 屬性 > 應用程式 > 資源 > 圖示與資訊清單 > 選擇「不含資訊清單建立應用程式」。
- C++ 專案: 專案 > 屬性 > 連結器 > 資訊清單檔 > 啟用使用者帳戶控制 設為 No。
重要: 所有正式發布的執行檔都應在資訊清單中包含 UAC 節點。若含 UAC 節點,Windows 不會視為舊版應用程式,不會啟用重導向;直接寫入 Program Files 將導致「拒絕存取」。
總結
本實驗完整展示了:
- 舊版應用程式無資訊清單時,UAC 虛擬化會透明地將受保護區域寫入重導向至
VirtualStore。
- 使用 Process Monitor 可精準追蹤重導向行為 (REPARSE → SUCCESS)。
- 加入資訊清單宣告支援 UAC 後,虛擬化關閉,寫入受保護區域直接失敗。
- 正確做法:使用已知資料夾 API (
Environment.GetFolderPath、SHGetKnownFolderPath) 將資料檔存放於 ProgramData (共用) 或 LocalAppData/RoamingAppData (使用者專屬),確保標準使用者權限下正常運作。