在進行軟體開發時,程式的版本控制非常重要。我控製版本的方案如下:
版本號碼一般如下形式:AA.BB.CC.DDDD。其中AA,BB,CC由自己定義,DDDD由我做的版本控制宏自動遞增。 AA代表大版本號碼,有大的更新和功能增加時改變此號碼。此版本升級後,BB、CC清零。 BB代表小一級版本號碼,有小的更新和功能增加時改變此號碼。此版本升級後,CC清零。 CC代表更小一級的版本號碼,用於代表對Bug的修正。每次修正Bug即改變此號碼。 DD代表編譯次數,依次累加遞增,不做清零。
我編寫的宏響應OnBuildBegin,每次編譯project時自動增加DDDD的版本號碼。此宏目前支援C#,VC++,應該也支援VB,不過沒有測試過,呵呵。有幾點需要說明一下: 對於C# project,只修改AssemblyVersion。刪除了AssembleInfo.cs中的FileVersion段。 對於VC project,修改的.rc中的四處版本號碼。 由於Visual Stdio多語言特性的原因(猜想應該是這個原因),對於VC Project,修改.rc檔案後,必須採用unicode編碼輸出,才能實現對多語言的支援,比如中文。而對於C# project則不需要也不能以unicode編碼輸出。
代碼如下:
EnvironmentEvents中,響應BuildBegin事件
Private Sub BuildEvents_OnBuildBegin(ByVal Scope As EnvDTE.vsBuildScope, ByVal Action As EnvDTE.vsBuildAction) Handles BuildEvents.OnBuildBegin Start() End Sub
Main中如下:
Imports System Imports EnvDTE Imports EnvDTE80 Imports System.Diagnostics Imports System.IO Imports System.Text.RegularExpressions Public Module Main ' Path to file AssemblyInfo.cs, relative to path of the project ReadOnly m_sAssemblyInfoFilePath As String = "Properties/AssemblyInfo.cs" Dim m_OutputWindowPane As OutputWindowPane ' Regular expression to match the version string ReadOnly m_sVersion As String = "AssemblyVersion/(" & Chr(34) & "([0-9]+)/.([0-9]+)/.([0-9]+)/.([0-9/.]+)" & Chr(34) & "/)" ReadOnly m_sFileVersion As String = "FILEVERSION ([0-9]+)/,([0-9]+)/,([0-9]+)/,([0-9/.]+)" ReadOnly m_sProductVersion As String = "PRODUCTVERSION ([0-9]+)/,([0-9]+)/,([0-9]+)/,([0-9/.]+)" ReadOnly m_sFileVersion2 As String = "VALUE " + Chr(34) + "FileVersion" + Chr(34) + ", " + Chr(34) + "([0-9]+)/.([0-9]+)/.([0-9]+)/.([0-9/.]+)" + Chr(34) ReadOnly m_sProductVersion2 As String = "VALUE " + Chr(34) + "ProductVersion" + Chr(34) + ", " + Chr(34) + "([0-9]+)/.([0-9]+)/.([0-9]+)/.([0-9/.]+)" + Chr(34) Function GetOutputWindowPane(ByVal sName As String, Optional ByVal show As Boolean = True) As OutputWindowPane Dim win As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput) If show Then win.Visible = True Dim outputWindow As OutputWindow = win.Object Dim outputWindowPane As OutputWindowPane Try outputWindowPane = outputWindow.OutputWindowPanes.Item(sName) Catch e As System.Exception outputWindowPane = outputWindow.OutputWindowPanes.Add(sName) End Try If show Then outputWindowPane.Activate() Return outputWindowPane End Function Sub Start() Dim project As Project m_OutputWindowPane = GetOutputWindowPane("Build", False) project = CType(DTE.ActiveSolutionProjects().GetValue(0), EnvDTE.Project) If project.ConfigurationManager.ActiveConfiguration.ConfigurationName = "Release" Then m_OutputWindowPane.OutputString("[DSVerCtrl]: Release build, skip the version control." & Microsoft.VisualBasic.Constants.vbCrLf) Exit Sub End If If project.CodeModel.Language = CodeModelLanguageConstants.vsCMLanguageCSharp Or project.CodeModel.Language = CodeModelLanguageConstants.vsCMLanguageVB Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: The project is not C# project, pass the version control." & Microsoft.VisualBasic.Constants.vbCrLf) UpdateCSharpVersion(project) Exit Sub ElseIf project.CodeModel.Language = CodeModelLanguageConstants.vsCMLanguageVC Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: The project is VC project, pass the version control." & Microsoft.VisualBasic.Constants.vbCrLf) UpdateVCVersion(project) Exit Sub Else m_OutputWindowPane.OutputString("[DSVerCtrl]: The project is not C#, VB or VC project, pass the version control." & Microsoft.VisualBasic.Constants.vbCrLf) End If End Sub Private Sub UpdateCSharpVersion(ByVal project As Project) Dim vsProject As VSLangProj.VSProject Dim sProjectPath As String Dim sAssemblyInfoFile As String Dim sContent As String Dim verStrRegEx As Regex Dim match As Match Dim nVer As Integer Dim sNewVer As String vsProject = CType(project.Object(), VSLangProj.VSProject) sProjectPath = vsProject.Project.Properties.Item("FullPath").Value sAssemblyInfoFile = sProjectPath & m_sAssemblyInfoFilePath 'outputWindowPane.OutputString("[DSVerCtrl]: Changing the version of """ + project.FullName + """..." + Microsoft.VisualBasic.Constants.vbCrLf) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Changing the version of """ + sProjectPath + """..." + Microsoft.VisualBasic.Constants.vbCrLf) m_OutputWindowPane.OutputString("[DSVerCtrl]: Modifying the version of """ & project.Name & """..." & Microsoft.VisualBasic.Constants.vbCrLf) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Assembly info file name is """ + sAssemblyInfoFile + """." + Microsoft.VisualBasic.Constants.vbCrLf) sContent = ReadFileContent(sAssemblyInfoFile) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: File content is """ + sContent + "" + Microsoft.VisualBasic.Constants.vbCrLf) verStrRegEx = New Regex(m_sVersion) match = verStrRegEx.Match(sContent) If match.Success Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Found match string." + Microsoft.VisualBasic.Constants.vbCrLf) nVer = Convert.ToInt32(match.Groups.Item(4).Value) nVer = nVer + 1 sContent = sContent.Remove(match.Groups.Item(4).Index, match.Groups.Item(4).Length) sContent = sContent.Insert(match.Groups.Item(4).Index, nVer.ToString()) Else m_OutputWindowPane.OutputString("[DSVerCtrl]: Can not find the version string." & Microsoft.VisualBasic.Constants.vbCrLf) End If sNewVer = match.Groups.Item(1).Value & "." & match.Groups.Item(2).Value & "." & match.Groups.Item(3).Value & "." & nVer.ToString() m_OutputWindowPane.OutputString("[DSVerCtrl]: Modified the version to """ & sNewVer & """." & Microsoft.VisualBasic.Constants.vbCrLf) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: File content after modify is """ + sContent + "" + Microsoft.VisualBasic.Constants.vbCrLf) WriteFileContent(sAssemblyInfoFile, sContent, False) End Sub Private Sub UpdateVCVersion(ByVal project As Project) Dim vsProject As VSLangProj.VSProject Dim sProjectPath As String Dim sAssemblyInfoFile As String Dim sContent As String Dim verStrRegEx As Regex Dim match As Match Dim nVer As Integer Dim sNewVer As String vsProject = CType(project.Object(), VSLangProj.VSProject) sProjectPath = vsProject.Project.Properties.Item("ProjectDirectory").Value 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Changing the version of """ + sProjectPath + """..." + Microsoft.VisualBasic.Constants.vbCrLf) sAssemblyInfoFile = sProjectPath + project.Name + ".rc" 'outputWindowPane.OutputString("[DSVerCtrl]: Changing the version of """ + project.FullName + """..." + Microsoft.VisualBasic.Constants.vbCrLf) m_OutputWindowPane.OutputString("[DSVerCtrl]: Modifying the version of """ & project.Name & """..." & Microsoft.VisualBasic.Constants.vbCrLf) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Recourse file name is """ + sAssemblyInfoFile + """." + Microsoft.VisualBasic.Constants.vbCrLf) sContent = ReadFileContent(sAssemblyInfoFile) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: File content is """ + sContent + "" + Microsoft.VisualBasic.Constants.vbCrLf) verStrRegEx = New Regex(m_sFileVersion) match = verStrRegEx.Match(sContent) If match.Success Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Found match string." + Microsoft.VisualBasic.Constants.vbCrLf) nVer = Convert.ToInt32(match.Groups.Item(4).Value) nVer = nVer + 1 sContent = sContent.Remove(match.Groups.Item(4).Index, match.Groups.Item(4).Length) sContent = sContent.Insert(match.Groups.Item(4).Index, nVer.ToString()) Else m_OutputWindowPane.OutputString("[DSVerCtrl]: Can not find the FILEVERSION version string." & Microsoft.VisualBasic.Constants.vbCrLf) End If verStrRegEx = New Regex(m_sProductVersion) match = verStrRegEx.Match(sContent) If match.Success Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Found match string." + Microsoft.VisualBasic.Constants.vbCrLf) sContent = sContent.Remove(match.Groups.Item(4).Index, match.Groups.Item(4).Length) sContent = sContent.Insert(match.Groups.Item(4).Index, nVer.ToString()) Else m_OutputWindowPane.OutputString("[DSVerCtrl]: Can not find the PRODUCTVERSION version string." & Microsoft.VisualBasic.Constants.vbCrLf) End If verStrRegEx = New Regex(m_sFileVersion2) match = verStrRegEx.Match(sContent) If match.Success Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Found match string." + Microsoft.VisualBasic.Constants.vbCrLf) sContent = sContent.Remove(match.Groups.Item(4).Index, match.Groups.Item(4).Length) sContent = sContent.Insert(match.Groups.Item(4).Index, nVer.ToString()) Else m_OutputWindowPane.OutputString("[DSVerCtrl]: Can not find the FileVersion version string." & Microsoft.VisualBasic.Constants.vbCrLf) End If verStrRegEx = New Regex(m_sProductVersion2) match = verStrRegEx.Match(sContent) If match.Success Then 'm_OutputWindowPane.OutputString("[DSVerCtrl]: Found match string." + Microsoft.VisualBasic.Constants.vbCrLf) sContent = sContent.Remove(match.Groups.Item(4).Index, match.Groups.Item(4).Length) sContent = sContent.Insert(match.Groups.Item(4).Index, nVer.ToString()) Else m_OutputWindowPane.OutputString("[DSVerCtrl]: Can not find the ProductVersion version string." & Microsoft.VisualBasic.Constants.vbCrLf) End If sNewVer = match.Groups.Item(1).Value & "." & match.Groups.Item(2).Value & "." & match.Groups.Item(3).Value & "." & nVer.ToString() m_OutputWindowPane.OutputString("[DSVerCtrl]: Modified the version to """ & sNewVer & """." & Microsoft.VisualBasic.Constants.vbCrLf) 'm_OutputWindowPane.OutputString("[DSVerCtrl]: File content after modify is """ + sContent + "" + Microsoft.VisualBasic.Constants.vbCrLf) WriteFileContent(sAssemblyInfoFile, sContent, True) End Sub ' Read file content to a string Private Function ReadFileContent(ByVal sFileName As String) As String Dim readerStream As StreamReader Dim sFileContent As String Try readerStream = New StreamReader(sFileName, True) Catch e As FileNotFoundException m_OutputWindowPane.OutputString("[DSVerCtrl] - ERROR: Can not find the file """ & sFileName & """." & Microsoft.VisualBasic.Constants.vbCrLf) Exit Function Catch e As Exception m_OutputWindowPane.OutputString("[DSVerCtrl] - ERROR: Open file """ & sFileName & """ failed: " & e.Message & Microsoft.VisualBasic.Constants.vbCrLf) Exit Function End Try sFileContent = readerStream.ReadToEnd() readerStream.Close() Return sFileContent End Function ' Write the modified file content back Private Sub WriteFileContent(ByVal sFileName As String, ByVal sContent As String, ByVal bVCProject As Boolean) Dim writerStream As StreamWriter Try If (bVCProject) Then writerStream = New StreamWriter(sFileName, False, System.Text.Encoding.Unicode) Else writerStream = New StreamWriter(sFileName, False) End If Catch e As FileNotFoundException m_OutputWindowPane.OutputString("[DSVerCtrl] - ERROR: Can not find the file """ & sFileName & """." & Microsoft.VisualBasic.Constants.vbCrLf) Exit Sub Catch e As Exception m_OutputWindowPane.OutputString("[DSVerCtrl] - ERROR: Write file """ & sFileName & """ failed: " & e.Message & Microsoft.VisualBasic.Constants.vbCrLf) Exit Sub End Try writerStream.Write(sContent) writerStream.Flush() writerStream.Close() End Sub End Module