實驗概覽
本實驗針對原生 C++ (Win32) 應用程式,展示相同的 UAC 檔案虛擬化行為與解決方案。您將學會:
- 疑難排解檔案重導向問題
- 使用 Process Monitor 找出問題根因
系統需求
- Microsoft Visual Studio 2008
- Microsoft Windows 7
- Windows 7 SDK
- Process Monitor (Sysinternals)
練習:體驗使用者帳戶控制虛擬化
任務 1:無資訊清單檔執行應用程式 (模擬舊版應用程式)
- 確認 UAC 已啟用 (同 .NET 版步驟)。
- 開啟
DataRedirection 解決方案,將 BrokenAppNative 設為啟動專案。
- 確認 Visual Studio 未以管理員身分執行。
- 設定建置目標為 x86 (Debug 或 Release) —— 原因:x64 應用程式不論有無資訊清單,虛擬化永遠關閉。
- 專案屬性 > 連結器 > 資訊清單檔 > 啟用使用者帳戶控制 設為 No (關閉預設資訊清單)。
- 檢視
BrokenAppNative.cpp 中 SaveFile/LoadFile 及 MakeDataFilePath:資料檔路徑透過 SHGetKnownFolderPath(FOLDERID_ProgramFiles) 取得,並在 Program Files\BrokenApp 下建立 SomeFile.txt。
- 建置並執行 (非管理員)。工作管理員確認 UAC 虛擬化為「已啟用」。
- 輸入文字並按「儲存」——成功無錯誤。
- 嘗試前往實際 Program Files 路徑——找不到檔案,已重導向至
VirtualStore。


任務 2:使用 Process Monitor 找出問題
- 啟動 Process Monitor 並開始擷取。
- 啟動
BrokenAppNative,輸入文字並按「儲存」。
- 停止擷取,開啟程序樹選取
BrokenAppNative.exe。
- 篩選該程序事件,觀察 REPARSE (原始嘗試寫入 Program Files) 與 SUCCESS (重導向至 VirtualStore 實際寫入)。




任務 3:加入 UAC 資訊清單 (宣告支援 UAC)
- 專案屬性 > 連結器 > 資訊清單檔 > 啟用使用者帳戶控制 設為 Yes。
- UAC 執行層級 設為 asInvoker (或 requireAdministrator/highestAvailable)。
- 資訊清單工具 > 輸入和輸出 > 內嵌資訊清單 設為 Yes。
- 重新建置並執行——工作管理員顯示虛擬化「已停用」。
- 嘗試儲存——出現「拒絕存取」錯誤。



任務 4:修正「拒絕存取」錯誤 (變更儲存路徑至 ProgramData)
- 編輯
BrokenAppNative.cpp 中的 MakeDataFilePath 方法。
- 註解掉使用
FOLDERID_ProgramFiles 的程式碼。
- 取消註解使用
FOLDERID_ProgramData 的程式碼 (對應 C:\ProgramData,所有使用者可存取)。
- 重新建置並執行——資料檔正確儲存於
C:\ProgramData\BrokenApp,操作成功。

補充:關閉 UAC 虛擬化設定 (僅供教學)
- C# 專案: 專案屬性 > 應用程式 > 資源 > 選擇「不含資訊清單建立應用程式」。
- C++ 專案: 專案屬性 > 連結器 > 資訊清單檔 > 啟用使用者帳戶控制 = No。
注意: 正式發布的執行檔必須包含 UAC 節點資訊清單。否則 Windows 視為舊版應用程式啟用虛擬化,導致資料分散、安全性風險與相容性問題。
總結
本實驗驗證了原生 C++ 應用程式同樣受 UAC 檔案虛擬化影響。解決路徑完全一致:
- 加入資訊清單宣告
requestedExecutionLevel 關閉虛擬化。
- 使用
SHGetKnownFolderPath 搭配 FOLDERID_ProgramData、FOLDERID_LocalAppData、FOLDERID_RoamingAppData 取得正確資料儲存路徑。
- 避免硬式編碼路徑,確保標準使用者權限下應用程式正常運作。