之前有一個winfrom項目,想要通過獲取SVN版本號作為程序的內部編譯版本號。網上也有各種方法,但沒有一篇行得通的方法。於是我經過一系列研究,得出了一些經驗,特總結成一篇博客。
方法一:通過SVN命令獲取版本號
類似地,我在項目中添加了一個名為"Version_inf.bat"的用於生成版本號的批處理文件,把他放在啟動項目的目錄中。批處理文件中寫下如下腳本:
1 svn info>bin\Debug\SVN_Version.dll 2 findstr “Revision” bin\Debug\SVN_Version.dll
這段腳本的意思是通過“svn info”命令獲取“Revision”版本信息到Debug的輸出目錄的“SVN_Version.dll”文件中。(前提是電腦上必須安裝了svn軟件才能正常使用此命令。)
在程序的Program主入口中,寫上類似的代碼:
1 string str_PathResult = null; 2 Microsoft.Win32.RegistryKey regKey = null;//表示 Windows 注冊表中的項級節點(注冊表對象?) 3 Microsoft.Win32.RegistryKey regSubKey = null; 4 try 5 { 6 regKey = Microsoft.Win32.Registry.LocalMachine;//讀取HKEY_LOCAL_MACHINE項 7 8 if (regKey != null) 9 { 10 string keyPath = @"SOFTWARE\TortoiseSVN"; 11 regSubKey = regKey.OpenSubKey(keyPath, false); 12 } 13 //得到SVN安裝路徑 14 if (regSubKey != null) 15 { 16 if (regSubKey.GetValue("Directory") != null) 17 { 18 str_PathResult = regSubKey.GetValue("Directory").ToString(); 19 } 20 } 21 22 //如果存在SVN安裝信息,則通過調用批處理獲取版本號 23 if (str_PathResult != null) 24 { 25 string path = System.Environment.CurrentDirectory; 26 ////刪除已經存在的版本信息,避免出現串號 27 //if (File.Exists(path + "\\SVN_Version.dll")) 28 //{ 29 // File.Delete(path + "\\SVN_Version.dll"); 30 //} 31 32 int pathNum = path.LastIndexOf("\\") - 3; 33 ProcessStartInfo psi = new ProcessStartInfo(); 34 35 string pathStr = path.Substring(0, pathNum) + "Version_inf.bat"; 36 //string newPathStr = (pathStr.Substring(0, pathStr.LastIndexOf("."))) + ".bat"; 37 38 psi.FileName = pathStr; 39 //psi.FileName = path.Substring(0, pathNum) + "Version_inf.bat"; 40 psi.UseShellExecute = false; 41 psi.WorkingDirectory = path.Substring(0, pathNum).Substring(0, path.Substring(0, pathNum).Length - 1); 42 psi.CreateNoWindow = true; 43 Process.Start(psi); 44 } 45 } 46 catch (Exception ex) 47 { 48 //MessageBox.Show("檢測SVN信息出錯," + ex.ToString(), "提示信息"); 49 //LogUtil.WriteException(ex, "Program.Main()"); 50 } 51 finally 52 { 53 if (regKey != null) 54 { 55 regKey.Close(); 56 regKey = null; 57 } 58 59 if (regSubKey != null) 60 { 61 regSubKey.Close(); 62 regSubKey = null; 63 } 64 }
這樣每次程序編譯的時候就會生成一個新的“SVN_Version.dll”文件,里面記錄了最后一次更新的記錄版本號。
然后在主窗口讀取“SVN_Version.dll”文件中的版本信息顯示到程序的主界面上,代碼如下:
1 AssemblyName name = Assembly.GetExecutingAssembly().GetName(); 2 String version = name.Version.ToString().Substring(0, name.Version.ToString().LastIndexOf(".")); 3 //SVN版本號文件保存路徑 4 String svnVersionPath = System.AppDomain.CurrentDomain.BaseDirectory + "SVN_Version.dll"; 5 if (File.Exists(svnVersionPath)) 6 { 7 //StreamReader svnSteamReader = new StreamReader(svnVersionPath); 8 string[] lines = File.ReadAllLines(svnVersionPath); 9 if (lines.Length > 0) 10 { 11 for (int i = 0; i < lines.Length; i++) 12 { 13 if (lines[i].Contains("Revision")) 14 { 15 String[] temps = lines[i].Split(':'); 16 if (temps.Length > 1) 17 { 18 version += String.Format(".{0}", temps[1].Trim()); 19 break; 20 } 21 } 22 } 23 tssVersion.Text += version; 24 } 25 else 26 { 27 tssVersion.Text += "獲取出錯"; 28 } 29 } 30 else 31 { 32 tssVersion.Text += "未知的版本"; 33 }
這樣就完成了SVN版本號的獲取和內部編譯號的顯示了。如下圖:
但是這種的方法的問題是:
1)svn命令在程序沒有變化或者沒有獲取最新版本時會無法生成版本號;
2)只是在主界面顯示了版本號,但是並沒有真正改變項目生成文件的版本號;
3)如果電腦中沒有安裝svn程序,則極有可能會出現錯誤;
所以我又研究了方法二。
方法二:通過項目預處理事件獲取SVN版本號
先在項目的Properties目錄下新建一個“AssemblyInfo.template.cs”的模板類文件,並把“AssemblyInfo.cs”文件從SVN版本號中忽略。在模板文件中寫下類似的代碼:
1 using System.Reflection; 2 using System.Runtime.CompilerServices; 3 using System.Runtime.InteropServices; 4 5 // 有關程序集的常規信息通過以下 6 // 特性集控制。更改這些特性值可修改 7 // 與程序集關聯的信息。 8 [assembly: AssemblyTitle("程序名")] 9 [assembly: AssemblyDescription("更新時間:$WCDATE$")] 10 [assembly: AssemblyConfiguration("")] 11 [assembly: AssemblyCompany("")] 12 [assembly: AssemblyProduct("程序名")] 13 [assembly: AssemblyCopyright("Copyright © 2013")] 14 [assembly: AssemblyTrademark("")] 15 [assembly: AssemblyCulture("")] 16 17 // 將 ComVisible 設置為 false 使此程序集中的類型 18 // 對 COM 組件不可見。如果需要從 COM 訪問此程序集中的類型, 19 // 則將該類型上的 ComVisible 特性設置為 true。 20 [assembly: ComVisible(false)] 21 22 // 如果此項目向 COM 公開,則下列 GUID 用於類型庫的 ID 23 [assembly: Guid("18501865-f051-43be-ab03-59a2d9e76fcf")] 24 25 // 程序集的版本信息由下面四個值組成: 26 // 27 // 主版本 28 // 次版本 29 // 內部版本號 30 // 修訂號 31 // 32 // 可以指定所有這些值,也可以使用“內部版本號”和“修訂號”的默認值, 33 // 方法是按如下所示使用“*”: 34 // [assembly: AssemblyVersion("1.0.*")] 35 [assembly: AssemblyVersion("1.1.1.$WCREV$")] 36 [assembly: AssemblyFileVersion("1.1.1.$WCREV$")]
然后在項目屬性的生成事件中編寫如下預先生成事件執行的命令:
1 $(SolutionDir)Lib\SubWCRev.exe $(SolutionDir) $(ProjectDir)Properties\AssemblyInfo.template.cs $(ProjectDir)Properties\AssemblyInfo.cs -f
這段話的意思就是找到SVN的SubWCRev.exe文件,獲取到版本信息后通過模板將數據寫入到“AssemblyInfo.cs”文件中。
這樣每次生成之后版本號就寫入到了項目輸出的文件中。將每個項目都按照如上方法添加模板和預生成事件,那么程序文件就會都帶有版本信息。
實際效果如下圖所示:
程序在顯示的時候,可以通過封裝一個公共屬性讓其他人可以調用到版本號信息:
1 /// <summary> 2 /// 版本號 3 /// </summary> 4 public static string AppVersion 5 { 6 set { AppDomain.CurrentDomain.SetData("AppVersion", value); } 7 get { return AppDomain.CurrentDomain.GetData("AppVersion") == null ? "" : AppDomain.CurrentDomain.GetData("AppVersion").ToString(); } 8 }
這樣就大功告成啦!!!
當然如果想獲取項目生成的文件或者想獲取某個指定文件的版本號屬性,可以使用如下方法:
1 /// <summary> 2 /// 獲取文件的版本號 3 /// </summary> 4 /// <param name="filePath">文件的完整路徑</param> 5 /// <returns>文件的版本號</returns> 6 public static string GetFileVersion(string filePath) 7 { 8 string FileVersions = ""; 9 10 try 11 { 12 System.Diagnostics.FileVersionInfo file1 = System.Diagnostics.FileVersionInfo.GetVersionInfo(filePath); 13 FileVersions = file1.FileVersion; 14 if (FileVersions != "") 15 { 16 string[] strVer = FileVersions.Split('.'); 17 if (strVer.Length == 2) 18 { 19 FileVersions = strVer[0] + ".00.0000"; 20 } 21 22 } 23 } 24 catch (Exception ex) 25 { 26 FileVersions = ""; 27 } 28 return FileVersions; 29 }
特別說明:本文章為本人Healer007 原創! 署名:小蘿卜 轉載請注明出處,謝謝!