之前有一个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 原创! 署名:小萝卜 转载请注明出处,谢谢!