- 前言
C#寫好一個應用程序,總想分享給自己的朋友或者上架,然而被困在打包之外,這次為大家帶來近期我的經驗,經過幾天的摸索,發現網上的教程並不全面,會給初學者帶來很多疑問,這里將做些問題描述與解答。
/*
開發工具:Visual Studio 2017
系統版本:win10 x64
要求:已經有一個已完成的項目
*/
- 獲取打包工具,使用微軟自帶工具,獲取步驟如下,若已安裝請忽略此步。
打開工具->擴展和更新->搜索(2017 installer)->點擊安裝:
這里安裝擴展的具體步驟就不再贅述。
2. 安裝完擴展以后,新建一個Setup project項目。
界面如下
“應用程序文件夾”即”Application Folder”表示要安裝的應用程序需要添加的文件;
“用戶的‘程序’菜單”即”User’s Programs
Menu”表示:應用程序安裝完,用戶的“開始菜單”中的顯示的內容,一般在這個文件夾中,需要再創建一個文件用來存放:應用程序.exe和卸載程序.exe;
“用戶桌面”即”User’s Desktop”表示:這個應用程序安裝完,用戶的桌面上的創建的.exe快捷方式。
3. 解決方案->添加->新建項目->類庫,命名為ClassLibrary,在項目ClassLibrary下面,刪除Class1.cs,添加->新建項目->安裝程序類(名稱為InstallerDemo.cs),打開Installer,這個class Installer繼承自System.Configuration.Install.Installer,里面就一個構造函數。現在安裝程序不能完成的功能,都可以在這個類寫代碼來自己實現。
4. 重寫安裝函數BeforeInstall,AfterInstall,AfterRollback,AfterUninstall,BeforeRollback,BeforeUninstall等復制以下代碼實現自定義操作:
ps:這里的OnAfterInstall操作是寫入注冊表,自啟動
protected override void OnAfterInstall(IDictionary savedState) { LogWrite("OnAfterInstall!"); string path = this.Context.Parameters["targetdir"];//獲取用戶設定的安裝目標路徑, 注意,需要在Setup項目里面自定義操作的屬性欄里面的CustomActionData添加上/targetdir="[TARGETDIR]\" LogWrite(path); //開機啟動 RegistryKey hklm = Registry.LocalMachine; RegistryKey run = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",true); try {//64位系統在計算機\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run LogWrite("設置注冊表!"); LogWrite(path.Substring(0, path.Length - 1) + @"BingPic\BingPic.exe"); run.CreateSubKey("Bing",true); run.SetValue("Bing", path.Substring(0,path.Length-1) + @"BingPic\BingPic.exe"); hklm.Close(); LogWrite("設置結束!"); } catch (Exception my) { my.ToString(); LogWrite(my.ToString()); } base.OnAfterInstall(savedState); } public override void Install(IDictionary stateSaver) { LogWrite("Install!"); base.Install(stateSaver); } protected override void OnBeforeInstall(IDictionary savedState) { LogWrite("OnBeforeInstall!"); base.OnBeforeInstall(savedState); } public override void Uninstall(IDictionary savedState) { LogWrite("Uninstall!"); base.Uninstall(savedState); } public override void Rollback(IDictionary savedState) { LogWrite("Rollback"); base.Rollback(savedState); } public void LogWrite(string str) { string LogPath = @"c:\log\"; using (System.IO.StreamWriter sw = new System.IO.StreamWriter(LogPath + @"SetUpLog.txt", true)) { sw.WriteLine(DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss] ") + str + "\n"); } }
實現以上還不能應用到你的程序中,接下來添加主程序入口。
5. 添加主程序入口:“application folder 應用程序文件夾”–右側空白處右鍵–“添加”–“項目輸出”
**
項目Setup1 ->添加->項目輸出->選擇ClassLibrary后確定,你會發現,在項目Setup1 下面多了一項“主輸出來自ClassLibrary(活動)”的字樣。
6. 添加自定義操作: 可以看到四個子項:安裝,提交,回滾,卸載。在安裝上面點擊右鍵->添加自定義操作->選擇“主輸出來自ClassLibrary(活動)”。這樣,重新生成后,安裝之后就會執行 OnAfterInstall代碼了。
ps:獲取用戶設定的安裝目標路徑, 注意,需要在Setup項目里面自定義操作->install->輸出的屬性欄里面的CustomActionData添加上/targetdir=”[TARGETDIR]\”這樣代碼里就可以獲取到安裝路徑了
7. 添加卸載程序:c:\windows\system32\msiexec.exe
獲取資源管理器”:點擊項目setup1,屬性>-“ProductCode” ,將它的值復制,后面需要使用,很重要。
8. 添加你的已存在項目文件:debug目錄下的文件添加到應用程序文件夾里。
9. 創建應用程序快捷方式,卸載快捷方式.並重命名為你希望的,剪切並黏貼到桌面文件夾和用戶程序文件夾
並在卸載快捷方式的屬性中添加之前復制的
最后生成應用程序即可。
至此你的第一個應用程序就打包好了。現在去測試吧!
這個例子中在寫入注冊表時遇到了不少難題,其中一個很迷惑人的就是: System.UnauthorizedAccessException: 無法寫入到注冊表項。
在 System.ThrowHelper.ThrowUnauthorizedAccessException(ExceptionResource resource)
在 Microsoft.Win32.RegistryKey.EnsureWriteable()
在 Microsoft.Win32.RegistryKey.SetValue(String name, Object value, RegistryValueKind valueKind)
在 Microsoft.Win32.RegistryKey.SetValue(String name, Object value)
在 MyInstall.InstallerBing.OnAfterInstall(IDictionary savedState)
后來找資料說是未將RegistryKey run = hklm.OpenSubKey(@”SOFTWARE\Microsoft\Windows\CurrentVersion\Run”,true);設為true,之后解決。
操作注冊表時還有一個問題就是寫入成功,找不到的問題,
在32位機上自啟動路徑位:計算機\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
64位:計算機\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run
最后設置的CustomActionData添加上/targetdir=”[TARGETDIR]\”,一定要寫對 /targetdir=”[TARGETDIR]\”
歡迎大家指出問題。