如何在一个地方为多个应用程序定义应用程序版本?

我们有一个由众多应用程序组成的系统。 所有应用程序的版本都在同一时间更改。 目前,当我们发布一个新版本时,我们必须手动打开每个应用程序的项目选项并逐个更改版本。 有没有办法编译同一版本的所有应用程序,例如,将其保存在全局文件中,并在编译时读取此文件并将该版本分配给项目? 我只是试图消除太多的步骤,因为我们计划更频繁地更改版本号。 我只想在一个地方改变它。 可以这样做吗? 如何?

您可以使用纯文本文件(例如Versioninfo.rc )创buildVERSIONINFO资源,

 1 VERSIONINFO FILEVERSION 2,0,0,0 PRODUCTVERSION 2,0,0,0 FILEOS 0x4 FILETYPE 0x1 { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "CompanyName", "Your Company Name Here\0" VALUE "FileDescription", "Your File Description Here\0" VALUE "FileVersion", "2.0.0.0\0" VALUE "InternalName", "Your Internal Name\0" VALUE "LegalCopyright", "© Your Copyright Notice\0" VALUE "LegalTrademarks", "Your Trademark Notice\0" VALUE "OriginalFilename", "YourExeName\0" VALUE "ProductName", "Your Product Name\0" VALUE "ProductVersion", "2.0.0.0\0" VALUE "Comments", "No Comments\0" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x0409 0x04E4 } } 

注意:为了资源编译器正确地终止string,每个项目末尾都需要C样式的空终止符( \0 )。 否则,当您使用资源pipe理器显示可执行文件的版本信息时,可能会出现乱码或部分连接的值。

将一行添加到项目源文件中:

 {$R VersionInfo.res VersionInfo.rc} 

我build议在你的版本控制系统中把常见的版本信息资源放到外部引用中,然后你可以直接在每个项目的文件夹中检查出来,并且很容易地进行更新。

做一个Project-> Build,你的版本信息被embedded到.exe中。 您可以使用Windows资源pipe理器进行validation,并查看您的应用程序的属性。

在CodeNewsFast档案的Embarcadero Delphi论坛上有几个post(我和Jim Fleming的一个回复)。 Mine是[在这里],在这里,我将逐步描述如何在项目中使用预生成事件来更新上面张贴的资源脚本中的版本号。

Jim发表了一些回复,但是大约有十几篇文章可以从可用于预编译事件的可执行文件中find。 (有一些事情我会做不同的事情,比如让IDE在命令行上传递项目名称和位置;在分步骤的文章中描述了如何实现这一点,同时也处理版本parsing和递增不同,但基本的应用程序是一个很好的起始位置。)

Embarcadero公司的团队目前正在倒闭,但是我也能够从CodeNewsFast中检索到Jim的代码,并且可以在这里重现:

肯,

感谢你,我得到了它的工作。

以防万一谁想要实施这个解决scheme,下面你会find必要的步骤和辅助程序。

吉姆·弗莱明

A)在您的项目目录或任何地方使用以下命令创build您的版本信息资源文件

内容和文件扩展名.rc:

 // Note the \000 !!!! Here and elsewhere below !!!! // C string terminator !!! #define CONST_VERSION "4.1.1.1003\000" 1 VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEOS 0x4 FILETYPE 0x1 { BLOCK "StringFileInfo" { BLOCK "040904E4" // Will need changing if your language is not English and char-set not 1252 (multilingual). { VALUE "CompanyName", "Whatever\000" VALUE "FileDescription", "Whatever\000" VALUE "FileVersion", CONST_VERSION VALUE "InternalName", "My Internal Name\000" VALUE "LegalCopyright", "Copyright © whoever\000" VALUE "LegalTrademarks", "\000" VALUE "OriginalFileName", "If you wish\000" VALUE "ProductName", "What pleases you\000" VALUE "ProductVersion", CONST_VERSION VALUE "Comments", "Anything you wish to add\000" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x0409 0x04E4 } } 

B)在一些文件夹中创build一个新的项目,只有模块的代码应该类似于:

 unit FormIncrementBuildNumber; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.IOUtils, System.StrUtils; type TIncrementBuildNumber = class(TForm) IncrementingBuildNumberLabel: TLabel; procedure FormShow (Sender: TObject); procedure FormActivate(Sender: TObject); private { Private declarations } public { Public declarations } end; var IncrementBuildNumber: TIncrementBuildNumber; implementation {$R *.dfm} procedure TIncrementBuildNumber.FormShow (Sender: TObject); var Resource_File_Contents: TStringList; Full_File_Name_And_Path: string; First_Line_Of_File: string; Position_First_Dot: Integer; Position_Second_Dot: Integer; Position_Third_Dot: Integer; Position_Trailing_Backslash: Integer; Start_of_Build_Number: Integer; Length_of_Build_Number: Integer; Build_Number_In_ASCII: string; Build_Number_Numeric: Integer; Old_Resource_File_Name: string; Success: Boolean; begin if (System.ParamCount <> 1) then begin ShowMessage ('Resource File name not in first command-line parameter.'); Exit; end; Full_File_Name_And_Path := System.ParamStr(1); if (not TFile.Exists(Full_File_Name_And_Path, False)) then begin ShowMessage ('Resource file ' + Full_File_Name_And_Path + ' not found.'); Exit; end; Resource_File_Contents := TStringList.Create; try Resource_File_Contents.LoadFromFile(Full_File_Name_And_Path); First_Line_Of_File := Resource_File_Contents.Strings[0]; if (Copy(First_Line_Of_File, 1, 21) <> '#define CONST_VERSION') then begin ShowMessage ('First line of Version Info must start with "#define CONST_VERSION".' + #13 + 'Version not incremented.'); Exit; end; Position_First_Dot := Pos('.', First_Line_Of_File); if (Position_First_Dot = 0) then begin ShowMessage ('Version must have format "abcd".' + #13 + 'Build Number not incremented.'); Exit; end; Position_Second_Dot := PosEx('.', First_Line_Of_File, Position_First_Dot+1); if (Position_Second_Dot = 0) then begin ShowMessage ('Version must have format "abcd".' + #13 + 'Build Number not incremented.'); Exit; end; Position_Third_Dot := PosEx('.', First_Line_Of_File, Position_Second_Dot+1); if (Position_Third_Dot = 0) then begin ShowMessage ('Version must have format "abcd".' + #13 + 'Build Number not incremented.'); Exit; end; Position_Trailing_Backslash := PosEx('\', First_Line_Of_File, Position_Third_Dot+1); if (Position_Trailing_Backslash = 0) then begin ShowMessage ('Version must have format "abcd\000".' + #13 + 'Build Number not incremented.'); Exit; end; Start_of_Build_Number := Position_Third_Dot + 1; Length_of_Build_Number := Position_Trailing_Backslash - Start_of_Build_Number; if (Length_of_Build_Number < 1) then begin ShowMessage ('Build Number must be present.' + #13 + 'Build Number not incremented.'); Exit; end; Build_Number_In_ASCII := Copy (First_Line_Of_File, Start_of_Build_Number, Length_of_Build_Number); Success := TryStrToInt (Build_Number_In_ASCII, Build_Number_Numeric); if (not Success) then begin ShowMessage ('Build Number must be numeric integer.' + #13 + 'Build Number not incremented.'); Exit; end; Build_Number_Numeric := Build_Number_Numeric + 1; Build_Number_In_ASCII := IntToStr(Build_Number_Numeric); Resource_File_Contents.Strings[0] := Copy(First_Line_Of_File, 1, Position_Third_Dot) + Build_Number_In_ASCII + '\000"'; Old_Resource_File_Name := Full_File_Name_And_Path; Old_Resource_File_Name := TPath.ChangeExtension(Old_Resource_File_Name, '~rc'); if TFile.Exists(Old_Resource_File_Name, False) then TFile.Delete(Old_Resource_File_Name); Success := RenameFile(Full_File_Name_And_Path, Old_Resource_File_Name); if (not Success) then begin ShowMessage ('Error renaming old resource file to have extension "~rc".' + #13 + 'Build Number not incremented.'); Exit; end; Resource_File_Contents.SaveToFile(Full_File_Name_And_Path); finally Resource_File_Contents.Free; end; end; procedure TIncrementBuildNumber.FormActivate (Sender: TObject); begin Close; end; end. 

C)在项目的项目的内部编号应增加的选项:

  • 删除勾号“包含版本信息”。

  • 使用以下文本添加一个预生成事件,包括两对双引号,replace<>中的部分:

“”“”

D)添加到项目源,在“程序”关键字的正下方:

 {$R '<whatever you called it>.res' '<whatever you called it>.rc'} // I think both names must 

这里是一样的:IIRC,当他们不同时有错误。

E)尽pipeEmbarcadero已经移除了这个设施,但编译,运行和享受Auto-Increment内部版本号的回报。

吉姆的内容结束

您可以使用预生成事件来更新ProductNameFileDescription值,或者任何其他必须与基本脚本不同的其他事件。

更新 :它不是RADStudio本身的一部分,但来自安德烈亚斯豪斯拉登的DDevExtensions (我已经习惯了…!)。

您可以在IDE中使用ProjectGroup,只要您安装了来自Andreas Hausladen的优秀DDevExtensions。

  • 有一个项目组来包含所有的项目
  • 确保每个项目在“ Options|Version Info page都有“在项目中包含版本信息”。
  • 使用菜单Project|Set Versioninfo...打开Set Project Versioninfo对话框(只有一次,当前项目无关紧要)。
  • 在那里,您可以指定所有的版本信息,并select“应用于全部”,或者选中“应用到选定”来select要应用于所选的项目。

例如,看看我如何设置版本到两个项目一次: 例如,我将版本同时设置到两个项目

然后ProjectGroup上的Build All生成了1.1.1.9版本的所有其他细节。

这是dzPrepBuild的用例之一: http ://www.dummzeuch.de/delphi/dzprepbuild/englisch.html

(注意:这个项目已经被移植到了sourceforge,因为去年berlios会被closures。http://sourceforge.net/projects/dzprepbuild/