在項目的釋出頁籤中可以為應用程式選擇兩種ClickOnce部署模式:
- 該應用程式隻能聯機使用
- 該應用程式也可以脫機使用(可以從“開始”菜單啟動)
在這裡,我們姑且分别稱它們為聯機模式和脫機模式。聯機模式要求運作應用程式的機器必須與部署應用程式的伺服器保持聯機才能使用,因為每次運作應用程式都要從伺服器的應用程式釋出頁面(通常是publish.htm)或者由自己建立的快捷方式啟動(鍊向釋出頁面的setup.exe)。它會聯機到伺服器驗證應用程式并自動下載下傳最新版本到本機的應用程式緩存區(以後簡稱緩存區),然後啟動緩存區中的應用程式。在這個過程中它不會建立解除安裝程式,也不會自動建立啟動應用程式的任何快捷方式。感覺就是在應用程式釋出頁面上點選“運作”啟動了應用程式,關閉之後就不存在了,但是它仍然存放在緩存區。是以在釋出聯機應用程式時是不需要設定更新的(每次運作的一定是最新的版本),“更新”選項是不可用的。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5iNwEWOjVGOhRjZ0MjNlVGOzQGNhJjYmJ2Lc1WZ0l2LcNWaw9CXi9mYn5Wan5Wa39CXt92YuUHZpFmYuM3b09GawlGavw1LcpDc0RHaiojIsJye.jpg)
那麼我們自然而然的意識到,部署為聯機模式的應用程式,是不存在解除安裝這一說的。我們能做的隻是清空緩沖區的檔案。這個緩沖區在類似C:/Documents and Settings/Administrator/Local Settings/Apps/2.0/(2000,XP,2003系統是"%USERPROFILE%/Local Settings/apps/2.0";Vista系統是"%USERPROFILE%/AppData/Local/Apps/2.0" 和"%USERPROFILE%/AppData/Roaming")的目錄中建立随機名稱的檔案夾,用于存放應用程式緩存檔案;還存在一個Data檔案夾,其中存放的也是随機名稱的檔案夾,用于存放應用程式的資料緩存檔案。我們可以通過Windows SDK6中的mage.exe -cc指令将這裡的聯機緩存檔案清空(參見:《清單生成和編輯工具 (Mage.exe)》 )。
mage.exe所在目錄:
C:/Program Files/Microsoft SDKs/Windows/v6.0A/bin/mage.exe
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
e:/Program Files/Microsoft Visual Studio 9.0/VC>mage -?
指令
-New <檔案類型> -n
-Update <檔案名> -u
-Sign <檔案名> -s
-ClearApplicationCache -cc
-Help [verbose] -h -?
Options
-AppCodeBase <路徑> -appc
-AppManifest <路徑> -appm
-CertFile <檔案名> -cf
-CertHash <哈希> -ch
-FromDirectory <路徑> -fd
-IconFile <檔案路徑> -if
-IncludeProviderURL -ip
-Install -i
-Name <名稱> -n
-Password <密碼> -pwd
-Processor <處理器> -p
-ProviderURL -pu
-Publisher <發行者名稱> -pub
-MinVersion <版本号|none> -mv
-SupportURL <支援 url> -s
-TimeStampUri -ti
-ToFile <檔案名> -t
-TrustLevel <級别> -tr
-UseManifestForTrust -um
-Version <版本> -v
-WPFBrowserApp -wpf
使用 "mage -help verbose" 了解更詳細的幫助
e:/Program Files/Microsoft Visual Studio 9.0/VC>mage -cc
已清除應用程式緩存。
脫機模式将應用程式通過釋出頁面安裝,或者其他存儲媒體安裝,安裝過程中可能需要聯機到釋出伺服器,而應用程式會被“安裝”到前面說過的本地應用程式緩存區(注意它不會被mage.exe -cc指令清除)。它還會在開始菜單和桌面建立快捷方式,在系統資料庫中目前使用者的解除安裝鍵中留下應用程式的相關資訊(友善從控制台的“添加删除程式”删除它)。我們還可以設定詳細的更新選項,甚至可以通過ApplicationDeployment類編寫自己風格的更新代碼(見《ClickOnce部署——手動檢查更新》 )。
其實我們更關心的是部署為脫機模式的應用程式的解除安裝問題。通過上圖可以看到,系統資料庫中留下了關于應用程式許多有趣的解除安裝資訊。先是由讨厭的16位16進制數值序列組成的鍵(圖中左側紅線的68f29660d055f6eb),然後是圖示、名稱、釋出版本、發行商、快捷方式辨別、快捷方式檔案名、快捷方式檔案夾、聯機支援快捷方式名稱、解除安裝指令(圖中右側紅線的UninstallString)以及更新位址。這些資訊會顯示在開始菜單和桌面的快捷方式上,以及“添加删除程式”的解除安裝資訊中。
于是我們可以直接在指令行中粘貼解除安裝指令(UninstallString項的值),調出應用程式的解除安裝界面。
rundll32.exe dfshim.dll,ShArpMaintain ClickOnce.application, Culture=neutral, PublicKeyToken=0000000000000000, processorArchitecture=msil
一切并不是那麼美好,作為軟體的開發者或者應用程式的布置者,我們往往會選擇一種“安靜地”方式解除安裝掉過時的應用程式,遺憾的是目前版本的ClickOnce(.NET Framework 3.5 SP1)并不提供安裝器的安靜模式——這與流行的應用程式安裝器相悖。或者說dfshim.dll并沒有提供安靜模式的入口函數給我們調用(參考《How to uninstall a ClickOnce application silently?》 )。
我更喜歡《How to uninstall a ClickOnce application silently?》 提問中spencery 的答複,他主張由程式調用并找到解除安裝視窗後發送模拟鍵盤指令實作自動應答的方法。那麼我可以發送SHIFT+TAB和ENTER或者ALT+O(%{O})來确認解除安裝。
- using Microsoft.Win32;
- ///
- /// The sole purpose of this class is so we an send SHIFT-TAB and ENTER to the ClickOnce removal dialog.
- ///
- /// If the click once removal dialog is not yet open, this class will do nothing.
- public partial class AutomateKeystrokes : Form
- {
- [DllImport("user32.dll")]
- private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
- [DllImport("user32.dll")]
- private static extern bool SetForegroundWindow(IntPtr hWnd);
- public AutomateKeystrokes()
- {
- this.Load += new System.EventHandler(this.AutomateKeystrokes_OnLoad);
- }
- private void AutomateKeystrokes_OnLoad(object sender, EventArgs e)
- {
- RespondToClickOnceRemovalDialog();
- Application.Exit();
- }
- ///
- /// Use automated keystrokes to answer "OK" to the ClickOnce removal dialog.
- ///
- /// Timing is very critical here. Even Debug.Writeline lines can cause this to fail.
- private void RespondToClickOnceRemovalDialog()
- {
- IntPtr myWindowHandle = IntPtr.Zero;
- for (int i = 0; i < 60 && myWindowHandle == IntPtr.Zero; i++)
- {
- Thread.Sleep(500);
- myWindowHandle = FindWindow(null, _MAGIC_LENS_APPLICATION + " Maintenance");
- }
- if (myWindowHandle != IntPtr.Zero)
- {
- SetForegroundWindow(myWindowHandle);
- SendKeys.Send("+{TAB}"); // SHIFT-TAB
- SendKeys.Send("{ENTER}");
- SendKeys.Flush();
- }
- }
- }
事實上在某種情況下,mage.exe -cc指令同樣對脫機模式的應用程式有效。假設我們在應用程式運作期間,執行了應用程式的解除安裝程式。按照正常安裝器的管理方式,要麼要求關閉應用程式後執行解除安裝操作,要麼依舊執行解除安裝操作,而将當時無法删除的檔案注冊給Windows,讓系統重新啟動時删除這些檔案,完成軟體的解除安裝。ClickOnce采取的方式與它們都不同,如果處于這種情況,解除安裝程式會依舊被執行,但是并不把當時無法删除的檔案注冊給Windows,即使重新啟動作業系統,那些上次沒法删除的檔案卻仍然保留在緩存區裡,此時就是執行mage.exe -cc指令最好的時機,它會把這些成為“垃圾”的檔案清除掉。
順便說一下,上面代碼第33行FindWindow方法。它的第一個參數指類名(是指API的視窗類名,而不是OOP中的類,每個視窗都應該有自己的類名),第二個參數是指視窗标題名稱。對于本例,我們要找到标題為“ClickOnce 維護”的視窗,是以修改此行代碼的" Maintenance"為" 維護",并在窗體類代碼中聲明這樣的字段:
- readonly string _MAGIC_LENS_APPLICATION = "ClickOnce";
原帖:http://hi.baidu.com/wingingbob/blog/item/2091f951728d53868c5430ad.html