Delphi 如何在一个位置为多个应用程序定义应用程序版本?

Delphi 如何在一个位置为多个应用程序定义应用程序版本?,delphi,msbuild,compilation,version,delphi-xe2,Delphi,Msbuild,Compilation,Version,Delphi Xe2,我们有一个由许多应用程序组成的系统。所有应用程序都会同时更改其版本。目前,当我们发布新版本时,我们必须手动打开每个应用程序的项目选项,并逐个更改版本。是否有办法在同一版本上编译所有应用程序,例如,将其保存在全局文件中,编译后读取此文件并将该版本分配给项目?我只是想消除太多的步骤,因为我们计划更频繁地更改版本号。我只想在一个地方换。这能做到吗?如何创建?您可以在纯文本文件中创建VERSIONINFO资源(例如,VERSIONINFO.rc) 注意:如图所示,为了使资源编译器正确终止字符串,每个项的

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

您可以在纯文本文件中创建
VERSIONINFO
资源(例如,
VERSIONINFO.rc

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

在项目源文件中添加一行:

{$R VersionInfo.res VersionInfo.rc}
我建议将公共版本信息资源放入版本控制系统中的外部引用中,然后您可以将其签出到每个项目的文件夹中,并轻松地进行更新

执行Project->Build,您的版本信息将嵌入到.exe中。您可以使用Windows资源管理器并查看应用程序的属性进行验证

在CodeNewsFast档案馆的Embarcadero Delphi论坛上有两篇帖子(一篇是我写的,另一篇是Jim Fleming的回复)。我的是[这里],在这里,我一步一步地描述如何在项目中使用预构建事件来更新我上面发布的资源脚本中的版本号

Jim发布了一些回复,但下面大约有十几篇文章提供了一个可执行文件的源代码,可以从对他有效的预构建事件中调用该文件。(我会做一些不同的事情,比如让IDE在命令行上传递项目名称和位置;如何做到这一点在分步文章中有描述。我也会以不同的方式处理版本解析和增量,但基本应用程序是一个很好的起点。)

Embarcadero的团队目前处于关闭状态,但我也能够从中检索Jim的代码,并可以在此处复制:

多亏了你,我才得以成功

为了防止其他人想要实现此解决方案,您可以在下面找到必要的步骤和辅助程序

吉姆·弗莱明

A) 使用以下命令在项目目录或任何位置创建版本信息资源文件

目录和文件扩展名.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) 在某个文件夹中创建新项目,仅模块的代码应类似于:

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 "a.b.c.d".' + #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 "a.b.c.d".' + #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 "a.b.c.d".' + #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 "a.b.c.d\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.
单位格式递增建筑编号;
接口
使用
Winapi.Windows、Winapi.Messages、System.SysUtils、System.Variants、,
系统类、Vcl图形、Vcl控件、Vcl窗体、Vcl对话框、,
Vcl.StdCtrls、System.IOUtils、System.StrUtils;
类型
TIncrementBuildNumber=类(TForm)
递增BuildNumberLabel:TLabel;
程序表单显示(发送方:TObject);
激活程序(发送方:TObject);
私有的
{私有声明}
公众的
{公开声明}
结束;
变量
递增BuildNumber:t递增BuildNumber;
实施
{$R*.dfm}
程序TIncrementBuildNumber.FormShow(发送方:ToObject);
变量
资源文件内容:TStringList;
完整文件名和路径:字符串;
_文件的第一个_行:字符串;
位置\第一个\点:整数;
位置第二个点:整数;
第三个点的位置:整数;
位置\尾随\反斜杠:整数;
构建编号的起始编号:整数;
构建编号的长度:整数;
在ASCII:string中生成\u编号\u;
构建编号:整数;
旧资源文件名称:字符串;
成功:布尔;
开始
如果(System.ParamCount 1),则
开始
ShowMessage('资源文件名不在第一个命令行参数中');
出口
结束;
完整文件名和路径:=System.ParamStr(1);
如果(不存在TFile.Exists(完整文件名和路径,False)),则
开始
ShowMessage('Resource file'+完整文件名和路径+
“没有找到。”);
出口
结束;
资源文件内容:=TStringList.Create;
尝试
资源文件内容。LoadFromFile(完整文件名和路径);
文件的第一行:=资源文件内容。字符串[0];
如果(复制(文件的第一行,1,21)#定义常量版本),则
开始
ShowMessage('版本信息的第一行必须以“#定义常量版本”开头。“+
#13+“版本未增加”。);
出口
结束;
位置\第一个\点:=位置('.',第一行\文件);
如果(位置首先\u点=0),则
开始
ShowMessage('版本必须具有格式“a.b.c.d.”+#13+
“内部版本号未增加。”);
出口
结束;
位置\u第二个\u点:=PosEx('.',文件的第一行\u,
位置_第一_点+1);
如果(位置秒点=0),则
开始
ShowMessage('版本必须具有格式“a.b.c.d.”+#13+
“内部版本号未增加。”);
出口
结束;
位置\u第三个\u点:=PosEx('.',文件的第一行\u,
位置(第二个点+1);
如果(位置第三个点=0),则
开始
ShowMessage('版本必须具有格式“a.b.c.d.”+#13+
“内部版本号未增加。”);
出口
结束;
位置\u拖尾\u反斜杠:=PosEx('\',文件的第一行\u,
位置(第三个点+1);
如果(位置\尾随\反斜杠=0),则
开始
ShowMessage('版本必须具有格式“a.b.c.d\000”。'+#13+
“内部版本号未增加。”);
出口
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 "a.b.c.d".' + #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 "a.b.c.d".' + #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 "a.b.c.d".' + #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 "a.b.c.d\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.
{$R '<whatever you called it>.res' '<whatever you called it>.rc'} // I think both names must