您可能遇到過下面的一種或多種情況:
• 您的應用程序寫入Program Files ,Windows目錄,或者系統根(一般是C盤)文件夾,但是您在這些地方並沒有找到您的文件
• 您的應用程序寫入Windows注冊表,特別是HKLM/Software中,但是您沒有看 到注冊表進行了更新
• 您切換到了另一個帳戶,並且您的應用程序沒有辦法找 到已寫入Program Files,Windows目錄,或者系統根(一般是C盤)文件夾的文件,或者找到 了這些文件的老版本
• 在啟用或禁用用戶帳戶控制(UAC)後,您的應用程序都 沒有辦法找到Program Files或Windows目錄中的文件
如果這些出現在了您的應用程序 中,都是由於UAC虛擬化的原因。下面所提供的信息為您介紹了所有關於發現這個應用程序兼 容性問題,解決方案,以及特殊兼容性問題的一些附加信息。
真正的問題:UAC 虛擬 化
在Windows Vista中,一般由管理員來運行應用程序。這樣,應用程序可以自由的 讀寫系統文件和注冊表的值。如果標准用戶可以運行這些應用程序,那他們可能會由於沒有 足夠的權限而導致失敗。Windows Vista通過重定向寫入(以及後續文件或者注冊表操作)對 應用戶的配置文件(profile)位置,來對標准用戶運行應用程序的能力進行了提升。
例如,如果一個應用程序試圖寫入C:\Program Files\Contoso\Settings.ini,並且用戶 沒有權限來對該文件夾進行寫入操作,寫入操作將會被重定向到C:\Users \Username\AppData\Local\VirtualStore\Program Files\Contoso\settings.ini。如果應用 程序試圖在注冊表中寫入HKEY_LOCAL_MACHINE\Software \Contoso\,這將會被自動重定向到 HKEY_CURRENT_USER\Software\Classes\VirtualStore \MACHINE\Software\Contoso或 HKEY_USERS\UserSID_Classes\VirtualStore \Machine\Software\Contoso。
下圖顯示了Windows 虛擬化進程的兩個組件:文件虛擬化和注冊表虛擬化
重要注意
當為Windows Vista開發應用程序時,請確定在對應的requestedExecutionLevel元素 中嵌入應用程序清單文件。這將會關閉文件和注冊表虛擬化,減少虛擬化的文件和注冊表值 的復雜性。
更多關於UAC虛擬化和新UAC技術,請參閱“Windows Vista中的新 UAC技術”http://msdn.microsoft.com/en-us/library/bb756960.aspx .
解決 方案
虛擬化是為了幫助現存的應用程序解決兼容性問題而出現的。為Windows 7而設 計的新的應用程序不應該對敏感的系統區域進行寫入操作,不應該依靠虛擬化來對不正確的 應用程序行為進行修正。開發應用程序的時候,應該始終考慮使其運行在標准用戶的權限下 ,而不是在管理員權限下運行。測試您的應用程序時,也要用標准用戶權限而不是管理員權 限。
如果您正在使用UAC虛擬化來為Windows 7開發應用程序,那麼請將您的應用程序重新設計 為將文件寫入合適位置。當更新現有的代碼以在Windows 7上運行的時候,您應該:
• 確定在運行時,應用程序存儲數據只是在對應用戶的位置或者在對訪問控制 列表(ACL)進行了設置的%alluserprofile%系統位置。更多關於ACLs的信息,請參閱訪問控 制列表.
• 使用已知的文件夾來寫入數據文件。所有用戶可以使用的一般數據應 該被寫入一個對所有人共享的公共位置。所有其他的數據都應該被寫入對應用戶的位置。
o 一般數據文件可以包含,但不限制,日志文件,配置文件(INI/XML),狀態存儲應 用程序例如保存的游戲等等。
o 用戶文件則不同;它們應該被保存到Documents文 件夾(或者用戶指定的位置)
• 確保您沒有在代碼中指定你覺得合適的路徑。 建議您使用下面的模型和APIs來獲取特定已知的Windows的正確路徑:
o C/C++ native 應用程序: 使用SHGetKnownFolderPath方法來獲取已知文件夾的整個路徑,它們可以 用文件夾的KNOWNFOLDERID來識別。它是一個標識您想要獲取的已知位置的GUID參數:
FOLDERID_ProgramData – 向所有人共享項目數據的目錄
FOLDERID_LocalAppData – 對應用戶項目數據的目錄(不可移動的)
FOLDERID_RoamingAppData –對應用戶項目數據的目錄(可移動的)
o 托 管代碼: 使用System.Environment.GetFolderPath方法。GetFolderPath包含一個標識您想要 獲取的已知位置的參數:
Environment.SpecialFolder.CommonApplicationData –向所有人共享項目數據的目錄
Environment.SpecialFolder.LocalApplicationData –對應用戶項目數據的目 錄(不可移動的)
Environment.SpecialFolder.ApplicationData –對應用戶 項目數據的目錄(可移動的)
• 如果上面提到的方法都不起作用,則請您使用 環境變量:
o %ALLUSERSPROFILE% –向所有人共享項目數據的目錄
o %LOCALAPPDATA% –對應用戶項目數據的目錄(不可移動的) - Windows Vista 或更高版本
o %APPDATA% –對應用戶項目數據的目錄(可移動的) - Windows Vista或更高版本
選定最適合的解決方案的步驟
到目前為止,我們向 您展示了與UAC虛擬化相關的情況,解釋了為什麼會發生重定向,並給出了建議的解決方案。 這部分包含了一些測試和操作,使您可以一點點的來定位問題並使用相應的方法來解決它。
測試 #1:
• 使用標准用戶權限運行應用程序
• 運行寫入受 保護的文件夾(例如Program Files或者系統根(C:\)目錄)的操作場景
• 期 待的結果: 應用程序“成功”將文件寫入受保護的文件夾;但是,您無法在您所 希望的位置找到。
• 結論: 這說明UAC數據虛擬化把文件重定向到了另一個地方 。
測試 #2:
• 使用Windows Explorer,在VirtualStore文件夾中搜索您 的文件
o VirtualStore文件夾是在您配置文件(profile)下的用來存儲重定向的 文件的
o VirtualStore文件夾的名字和位置會在Windows以後的版本中改變
• 首先,請在%localappdata%\VirtualStore下查找
• 如果您在那 裡沒有找到,那麼請您試著使用命令:dir %userprofile%\yourfile.dat /s /a
• 期待的結果: 您應該可以在VirtualStore文件夾中找到您的文件
• 結論: 這可以證明UAC虛擬化確實發生了。
測試 #3:
• 以管理員的身份進行登錄並以管理員身份運行您的應用程序。
o 要想以管理員身份 運行應用程序,請右鍵點擊可執行文件並選擇Run as Administrator
o 當應用程序以管理員身份運行時,虛擬化處於禁用狀態,且應用程序現在有權限向受 保護的文件夾中進行寫入操作。
• 不要始終使您的應用程序獲取管理員權限來 繞過虛擬化,這樣會使系統留下很多容易被攻擊的地方,也會使應用程序不能使用受限或是 標准用戶權限運行,並且匿名用戶在使用時也無需彈出UAC窗口。
• 期待的結果 : 應用程序成功向受保護的文件夾中進行了寫入操作,並且您可以在您所期望的位置找到該 文件。
• 結論: 使用管理員身份運行應用程序會禁用虛擬化並具有可以向受保 護的系統位置進行寫入的權限。
測試 #4
• 運行Process Monitor (ProcMon)
o 更多關於Process Monitor的信息,請訪問Microsoft TechNet上的 Windows Sysinternals Process Monitor Web site
o 在動手實驗中,我們將一步 一步地教您使用Process Monitor
• 配置過濾,使得只顯示文件操作和執行這些 操作的進程
o 當您運行Process Monitor的時候,會彈出Process Monitor Filter 對話框
• 將下面的條目添加到過濾器中: "Column=Process Name, Relation=is, Value=YourApp.exe, Action=Include"
• 再一次調用Process Monitor Filter對話框,點擊這個工具欄按鈕:
• 然後點擊OK,通過啟用下面的工具條按鈕來配置Process Monitor 只記錄文件事 件:
• 按 CTRL-X來清除日志;按CTRL-E來開啟或關閉logging
• 期待的結果: 您將看 到結果為REPARSE的文件操作;下面一行(結果是SUCCESS)通常是重定向操作:
• 雙擊顯示REPARSE結果的行並點擊Stack選項卡來查看操作時所調用的堆棧:
• 左側顯示的粉色的K和藍色的U,表示stack frame是在內核模式(K)還是在用戶模式(U); 在這種情況下,我們只關注在用戶模式下的stack frame
• 在本例中,在 BrokenAppNative.exe中的SaveFile方法(frame 21)就將進行重定向操作。
• 您應該為更有意義的界面進行標志配置,更多關於標志配置的信息,請參閱 Debugging Tools for Windows Web site
• 總結: 這個測試證明了UAC虛擬化確實發生了, 還顯示了您的應用程序哪裡需要修改
測試 #5
• 為您的包含UAC指令的應 用程序添加一個清單文件
o 這將把您的應用程序標記為支持UAC的應用程序並且將會關閉UAC虛擬化
o 清單文件時一個程序嵌入DLL或.exe文件中的作為資源的XML文檔,但它可以使一個獨立的名 為YourApp.exe.manifest或YourDLL.dll.manifest的文件。
o 清單文件可以包含很 多的通常是關於應用程序兼容性的信息,例如Visual C++運行時的確切版本,公用控件庫的 版本,以及UAC配置
o 更多關於清單文件中UAC配置的信息,請參閱Windows Vista Developer Story: Create and Embed an Application Manifest (UAC)
• 期待 的結果: 該應用程序現在無法向受保護的文件夾中進行寫入操作,並返回了“拒絕訪問 ”錯誤
o 這是一個很好的結果,因為UAC數據虛擬化並沒有發揮作用
o 作為開發者,您應該認識到這一點(因為您在清單文件中把應用程序標記為了支持UAC) 並且避免對受保護的地方進行寫入操作。
• 結論: Windows開啟虛擬化是因為應 用程序沒有被標記為支持UAC。使您的應用程序支持UAC以關閉虛擬化。
工具
為了檢測UAC虛擬化我們可以使用下面的工具:
• Process Monitor,一個免費 且高級的Microsoft工具,它可以監控並記錄文件系統,注冊表,網絡,以及進程的活動。
o 更多關於Process Monitor的信息,請參看Windows Sysinternals網站上的 Process Monitor page
o 在Microsoft TechNet上下載Process Monitor
• Standard User Analyzer,Microsoft應用程序兼容性工具包的一部 分,是一個監控應用程序資源(文件,注冊表及其他)的使用並對由於是標准用戶原因引起 的問題進行匯報。
o 更多關於Standard User Analyzer請在Microsoft TechNet上 查看“Standard User Analyzer”
o 要獲得Standard User Analyzer, 請訪問download the Microsoft Application Compatibility Toolkit