自动修改Delphi工程文件(dpr)的编译版本号
2008-10-01 17:46
549 查看
软件截图:
Delphi工程的版本修改只能通过Project/Options/Version Info来手动修改,当我们有几十个项目需要同时修改版本时,就会被折腾的累死。本人就是因为要维护一个项目,而这个项目有50多个不同的版本,需要更新版本的时候,几乎所有的工程都得手动改一遍,费时费力费神。于是,我就产生了编写一个批处理修改项目版本的工具的想法,并立即付诸实现。
首先我用源代码管理工具SVN, 比较了我修改版本好前后的文件的差异,发现仅仅就有两个文件不同,一个是 *.Dproj, 另外一个是*.Res。于是我就开始分析两个文件的格式,*.Dproj是一个XML文件,UTF8存储。*.Res是标准的资源文件。知道了文件格式就好办了,后边就不多说了,贴上代码(代码中用到了第三方控件ResourceUtils):
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ButtonGroup;
type
TMainForm = class(TForm)
lvwProjectList: TListView;
btnAddProject: TButton;
btnDeleteProject: TButton;
btnSingleModify: TButton;
btnMultiModify: TButton;
edMajor: TEdit;
Label1: TLabel;
edMinor: TEdit;
Label2: TLabel;
edRelease: TEdit;
Label3: TLabel;
edBuild: TEdit;
Label4: TLabel;
UpMajor: TUpDown;
UpMinor: TUpDown;
UpRelease: TUpDown;
UpBuild: TUpDown;
btnRefreshProjects: TButton;
btnSaveProjectList: TButton;
btnLoadProjectList: TButton;
procedure btnAddProjectClick(Sender: TObject);
procedure lvwProjectListDeletion(Sender: TObject; Item: TListItem);
procedure btnDeleteProjectClick(Sender: TObject);
procedure lvwProjectListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
procedure lvwProjectListClick(Sender: TObject);
procedure btnSingleModifyClick(Sender: TObject);
procedure btnRefreshProjectsClick(Sender: TObject);
procedure btnMultiModifyClick(Sender: TObject);
procedure btnSaveProjectListClick(Sender: TObject);
procedure btnLoadProjectListClick(Sender: TObject);
private
function GetProjectResFileName(const FileName: string): string;
procedure AddProjectToList(const FileName: string);
function ExistsProject(const FileName: string): Boolean;
function ModifySingle(Item: TListItem; var ErrStr: string): Boolean;
public
end;
TRecordObject = class
Major, Minor, Release, Build: Word;
FileName: string;
end;
var
MainForm: TMainForm;
implementation
uses MiscFuncsUnit;
{$R *.dfm}
procedure TMainForm.AddProjectToList(const FileName: string);
var
ListItem: TListItem;
LFileName: string;
VerObj: TRecordObject;
begin
LFileName := GetProjectResFileName(FileName);
VerObj := TRecordObject.Create;
VerObj.FileName := FileName;
ListItem := lvwProjectList.Items.Add;
ListItem.Caption := '';
ListItem.Data := Pointer(VerObj);
ListItem.SubItems.Add(FileName);
if ReadResVer(LFileName, VerObj.Major, VerObj.Minor, VerObj.Release, VerObj.Build) then
begin
ListItem.SubItems.Add(Format('%d.%d.%d.%d',
[VerObj.Major, VerObj.Minor, VerObj.Release, VerObj.Build]));
end else
ListItem.SubItems.Add('-');
ListItem.SubItems.Add('');
end;
procedure TMainForm.btnAddProjectClick(Sender: TObject);
begin
with TOpenDialog.Create(nil) do
try
Filter := '*.dproj|*.dproj';
if Execute then
begin
if ExistsProject(FileName) then
MessageBox(0, '您选择的工程已经添加了!', '提示信息', MB_ICONINFORMATION)
else
AddProjectToList(FileName);
end;
finally
Free;
end;
end;
procedure TMainForm.btnDeleteProjectClick(Sender: TObject);
begin
lvwProjectList.DeleteSelected;
end;
procedure TMainForm.btnLoadProjectListClick(Sender: TObject);
var
StrList: TStringList;
I: Integer;
OpenFileName: string;
begin
OpenFileName := '';
with TOpenDialog.Create(nil) do
try
Filter := '*.dlist|*.dlist';
if Execute then
OpenFileName := FileName;
finally
Free;
end;
if OpenFileName = '' then
Exit;
StrList := TStringList.Create;
try
StrList.LoadFromFile(OpenFileName);
for I := 0 to StrList.Count - 1 do
begin
AddProjectToList(StrList[I]);
end;
finally
StrList.Free;
end;
end;
procedure TMainForm.btnMultiModifyClick(Sender: TObject);
var
I: Integer;
ErrStr: string;
begin
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
with TRecordObject(lvwProjectList.Items[I].Data) do
begin
lvwProjectList.Selected := lvwProjectList.Items[I];
ModifySingle(lvwProjectList.Items[I], ErrStr);
lvwProjectList.Items[I].SubItems[1] := Format('%d.%d.%d.%d',
[Major, Minor, Release, Build]);
end;
end;
end;
procedure TMainForm.btnRefreshProjectsClick(Sender: TObject);
var
I: Integer;
begin
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
with TRecordObject(lvwProjectList.Items[I].Data) do
begin
ReadResVer(GetProjectResFileName(FileName), Major, Minor, Release, Build);
lvwProjectList.Items[I].SubItems[1] := Format('%d.%d.%d.%d',
[Major, Minor, Release, Build]);
end;
end;
end;
procedure TMainForm.btnSaveProjectListClick(Sender: TObject);
var
StrList: TStringList;
I: Integer;
SaveFileName: string;
begin
SaveFileName := '';
with TSaveDialog.Create(nil) do
try
Filter := '*.dlist|*.dlist';
if Execute then
SaveFileName := FileName;
finally
Free;
end;
if SaveFileName = '' then
Exit;
if Pos('.dlist', SaveFileName) <= 0 then
SaveFileName := SaveFileName + '.dlist';
StrList := TStringList.Create;
try
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
StrList.Add(lvwProjectList.Items[I].SubItems[0]);
end;
StrList.SaveToFile(SaveFileName);
finally
StrList.Free;
end;
end;
procedure TMainForm.btnSingleModifyClick(Sender: TObject);
var
ErrStr: string;
begin
if lvwProjectList.Selected = nil then
Exit;
with TRecordObject(lvwProjectList.Selected.Data) do
begin
if ModifySingle(lvwProjectList.Selected, ErrStr) then
begin
lvwProjectList.Selected.SubItems[2] :=
Format('%d.%d.%d.%d', [Major, Minor, Release, Build]);
MessageBox(Self.Handle, '修改成功!', '提示信息', MB_ICONINFORMATION);
end else
MessageBox(Self.Handle, PChar('修改失败! 原因:' + ErrStr), '提示信息', MB_ICONWARNING);
end;
end;
function TMainForm.ModifySingle(Item: TListItem; var ErrStr: string): Boolean;
begin
Result := False;
if Item = nil then
Exit;
with TRecordObject(Item.Data) do
begin
try
ModifyDprojVer(FileName, StrToInt(edMajor.Text), StrToInt(edMinor.Text)
, StrToInt(edRelease.Text), StrToInt(edBuild.Text));
ModifyResVer(GetProjectResFileName(FileName),
StrToInt(edMajor.Text), StrToInt(edMinor.Text)
, StrToInt(edRelease.Text), StrToInt(edBuild.Text));
ReadResVer(GetProjectResFileName(FileName), Major, Minor, Release, Build);
Result := True;
except
on E: Exception do
begin
ErrStr := E.Message;
end;
end;
end;
end;
function TMainForm.ExistsProject(const FileName: string): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
if SameText(lvwProjectList.Items[I].SubItems[0], FileName) then
begin
Result := True;
Break;
end;
end;
end;
function TMainForm.GetProjectResFileName(const FileName: string): string;
function ExtractMainFileName(const AFileName: string): string;
begin
Result := ExtractFileName(AFileName);
Result := Copy(Result, 1, Length(Result) - Length(ExtractFileExt(AFileName)));
end;
begin
Result := ExtractMainFileName(FileName) + '.res';
end;
procedure TMainForm.lvwProjectListClick(Sender: TObject);
begin
if lvwProjectList.Selected = nil then
Exit;
with TRecordObject(lvwProjectList.Selected.Data) do
begin
UpMajor.Position := Major;
UpMinor.Position := Minor;
UpRelease.Position := Release;
UpBuild.Position := Build;
end;
end;
procedure TMainForm.lvwProjectListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
Item.Caption := IntToStr(Item.Index + 1);
end;
procedure TMainForm.lvwProjectListDeletion(Sender: TObject; Item: TListItem);
begin
TRecordObject(Item.Data).Free;
end;
end.
unit MiscFuncsUnit;
interface
uses
Windows, SysUtils, unitResFile, unitResourceVersionInfo, xmldom, XMLIntf,
msxmldom, XMLDoc;
procedure ModifyDprojVer(const FileName: string; Major, Minor, Release, Build: Word);
procedure ModifyResVer(const FileName: string; Major, Minor, Release, Build: Word);
function ReadResVer(const FileName: string; var Major, Minor, Release, Build: Word): Boolean;
implementation
function FindNodeByAttrName(Node: IXMLNode; const NodeName, AttrName, AttrNameValue: WideString): IXMLNode;
var
I: Integer;
begin
Result := nil;
if (Node.NodeName = NodeName) and Node.HasAttribute(AttrName) and
(Node.Attributes[AttrName] = AttrNameValue) then
begin
Result := Node;
Exit;
end;
if Node.HasChildNodes then
begin
for I := 0 to Node.ChildNodes.Count - 1 do
begin
Result := FindNodeByAttrName(Node.ChildNodes[I], NodeName, AttrName, AttrNameValue);
if Result <> nil then
Break;
end;
end;
end;
procedure ModifyDprojVer(const FileName: string; Major, Minor, Release, Build: Word);
var
XmlDoc: IXMLDocument; // 注意此处一定要用IXMLDocument,否则会出错
RootNode, LNode: IXMLNode;
begin
XmlDoc := TXMLDocument.Create('');
XmlDoc.LoadFromFile(FileName);
RootNode := XmlDoc.Node;
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'MajorVer');
if LNode <> nil then
LNode.NodeValue := IntToStr(Major);
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'MinorVer');
if LNode <> nil then
LNode.NodeValue := IntToStr(Minor);
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'Release');
if LNode <> nil then
LNode.NodeValue := IntToStr(Release);
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'Build');
if LNode <> nil then
LNode.NodeValue := IntToStr(Build);
LNode := FindNodeByAttrName(RootNode, 'VersionInfoKeys', 'Name', 'FileVersion');
if LNode <> nil then
LNode.NodeValue := Format('%d.%d.%d.%d', [Major, Minor, Release, Build]);
XmlDoc.SaveToFile(FileName);
end;
procedure ModifyResVer(const FileName: string; Major, Minor, Release, Build: Word);
var
Res: TResModule;
I: Integer;
ResVer: TVersionInfoResourceDetails;
VerData: TULargeInteger;
begin
ResVer := nil;
Res := TResModule.Create;
try
Res.LoadFromFile(FileName);
for I := 0 to Res.ResourceCount - 1 do
begin
if Res.ResourceDetails[I] is TVersionInfoResourceDetails then
ResVer := Res.ResourceDetails[I] as TVersionInfoResourceDetails;
end;
if ResVer <> nil then
begin
VerData.HighPart := MakeLong(Minor, Major);
VerData.LowPart := MakeLong(Build, Release);
ResVer.FileVersion := VerData;
Res.SaveToFile(FileName);
end;
finally
Res.Free;
end;
end;
function ReadResVer(const FileName: string; var Major, Minor, Release, Build: Word): Boolean;
var
Res: TResModule;
I: Integer;
ResVer: TVersionInfoResourceDetails;
begin
Result := False;
ResVer := nil;
Res := TResModule.Create;
try
try
Res.LoadFromFile(FileName);
for I := 0 to Res.ResourceCount - 1 do
begin
if Res.ResourceDetails[I] is TVersionInfoResourceDetails then
ResVer := Res.ResourceDetails[I] as TVersionInfoResourceDetails;
end;
if ResVer <> nil then
begin
Major := HiWord(ResVer.FileVersion.HighPart);
Minor := ResVer.FileVersion.HighPart and $0000FFFF;
Release := HiWord(ResVer.FileVersion.LowPart);
Build := ResVer.FileVersion.LowPart and $0000FFFF;
Result := True;
end;
except
Result := False;
end;
finally
Res.Free;
end;
end;
end.
Delphi工程的版本修改只能通过Project/Options/Version Info来手动修改,当我们有几十个项目需要同时修改版本时,就会被折腾的累死。本人就是因为要维护一个项目,而这个项目有50多个不同的版本,需要更新版本的时候,几乎所有的工程都得手动改一遍,费时费力费神。于是,我就产生了编写一个批处理修改项目版本的工具的想法,并立即付诸实现。
首先我用源代码管理工具SVN, 比较了我修改版本好前后的文件的差异,发现仅仅就有两个文件不同,一个是 *.Dproj, 另外一个是*.Res。于是我就开始分析两个文件的格式,*.Dproj是一个XML文件,UTF8存储。*.Res是标准的资源文件。知道了文件格式就好办了,后边就不多说了,贴上代码(代码中用到了第三方控件ResourceUtils):
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ButtonGroup;
type
TMainForm = class(TForm)
lvwProjectList: TListView;
btnAddProject: TButton;
btnDeleteProject: TButton;
btnSingleModify: TButton;
btnMultiModify: TButton;
edMajor: TEdit;
Label1: TLabel;
edMinor: TEdit;
Label2: TLabel;
edRelease: TEdit;
Label3: TLabel;
edBuild: TEdit;
Label4: TLabel;
UpMajor: TUpDown;
UpMinor: TUpDown;
UpRelease: TUpDown;
UpBuild: TUpDown;
btnRefreshProjects: TButton;
btnSaveProjectList: TButton;
btnLoadProjectList: TButton;
procedure btnAddProjectClick(Sender: TObject);
procedure lvwProjectListDeletion(Sender: TObject; Item: TListItem);
procedure btnDeleteProjectClick(Sender: TObject);
procedure lvwProjectListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
procedure lvwProjectListClick(Sender: TObject);
procedure btnSingleModifyClick(Sender: TObject);
procedure btnRefreshProjectsClick(Sender: TObject);
procedure btnMultiModifyClick(Sender: TObject);
procedure btnSaveProjectListClick(Sender: TObject);
procedure btnLoadProjectListClick(Sender: TObject);
private
function GetProjectResFileName(const FileName: string): string;
procedure AddProjectToList(const FileName: string);
function ExistsProject(const FileName: string): Boolean;
function ModifySingle(Item: TListItem; var ErrStr: string): Boolean;
public
end;
TRecordObject = class
Major, Minor, Release, Build: Word;
FileName: string;
end;
var
MainForm: TMainForm;
implementation
uses MiscFuncsUnit;
{$R *.dfm}
procedure TMainForm.AddProjectToList(const FileName: string);
var
ListItem: TListItem;
LFileName: string;
VerObj: TRecordObject;
begin
LFileName := GetProjectResFileName(FileName);
VerObj := TRecordObject.Create;
VerObj.FileName := FileName;
ListItem := lvwProjectList.Items.Add;
ListItem.Caption := '';
ListItem.Data := Pointer(VerObj);
ListItem.SubItems.Add(FileName);
if ReadResVer(LFileName, VerObj.Major, VerObj.Minor, VerObj.Release, VerObj.Build) then
begin
ListItem.SubItems.Add(Format('%d.%d.%d.%d',
[VerObj.Major, VerObj.Minor, VerObj.Release, VerObj.Build]));
end else
ListItem.SubItems.Add('-');
ListItem.SubItems.Add('');
end;
procedure TMainForm.btnAddProjectClick(Sender: TObject);
begin
with TOpenDialog.Create(nil) do
try
Filter := '*.dproj|*.dproj';
if Execute then
begin
if ExistsProject(FileName) then
MessageBox(0, '您选择的工程已经添加了!', '提示信息', MB_ICONINFORMATION)
else
AddProjectToList(FileName);
end;
finally
Free;
end;
end;
procedure TMainForm.btnDeleteProjectClick(Sender: TObject);
begin
lvwProjectList.DeleteSelected;
end;
procedure TMainForm.btnLoadProjectListClick(Sender: TObject);
var
StrList: TStringList;
I: Integer;
OpenFileName: string;
begin
OpenFileName := '';
with TOpenDialog.Create(nil) do
try
Filter := '*.dlist|*.dlist';
if Execute then
OpenFileName := FileName;
finally
Free;
end;
if OpenFileName = '' then
Exit;
StrList := TStringList.Create;
try
StrList.LoadFromFile(OpenFileName);
for I := 0 to StrList.Count - 1 do
begin
AddProjectToList(StrList[I]);
end;
finally
StrList.Free;
end;
end;
procedure TMainForm.btnMultiModifyClick(Sender: TObject);
var
I: Integer;
ErrStr: string;
begin
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
with TRecordObject(lvwProjectList.Items[I].Data) do
begin
lvwProjectList.Selected := lvwProjectList.Items[I];
ModifySingle(lvwProjectList.Items[I], ErrStr);
lvwProjectList.Items[I].SubItems[1] := Format('%d.%d.%d.%d',
[Major, Minor, Release, Build]);
end;
end;
end;
procedure TMainForm.btnRefreshProjectsClick(Sender: TObject);
var
I: Integer;
begin
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
with TRecordObject(lvwProjectList.Items[I].Data) do
begin
ReadResVer(GetProjectResFileName(FileName), Major, Minor, Release, Build);
lvwProjectList.Items[I].SubItems[1] := Format('%d.%d.%d.%d',
[Major, Minor, Release, Build]);
end;
end;
end;
procedure TMainForm.btnSaveProjectListClick(Sender: TObject);
var
StrList: TStringList;
I: Integer;
SaveFileName: string;
begin
SaveFileName := '';
with TSaveDialog.Create(nil) do
try
Filter := '*.dlist|*.dlist';
if Execute then
SaveFileName := FileName;
finally
Free;
end;
if SaveFileName = '' then
Exit;
if Pos('.dlist', SaveFileName) <= 0 then
SaveFileName := SaveFileName + '.dlist';
StrList := TStringList.Create;
try
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
StrList.Add(lvwProjectList.Items[I].SubItems[0]);
end;
StrList.SaveToFile(SaveFileName);
finally
StrList.Free;
end;
end;
procedure TMainForm.btnSingleModifyClick(Sender: TObject);
var
ErrStr: string;
begin
if lvwProjectList.Selected = nil then
Exit;
with TRecordObject(lvwProjectList.Selected.Data) do
begin
if ModifySingle(lvwProjectList.Selected, ErrStr) then
begin
lvwProjectList.Selected.SubItems[2] :=
Format('%d.%d.%d.%d', [Major, Minor, Release, Build]);
MessageBox(Self.Handle, '修改成功!', '提示信息', MB_ICONINFORMATION);
end else
MessageBox(Self.Handle, PChar('修改失败! 原因:' + ErrStr), '提示信息', MB_ICONWARNING);
end;
end;
function TMainForm.ModifySingle(Item: TListItem; var ErrStr: string): Boolean;
begin
Result := False;
if Item = nil then
Exit;
with TRecordObject(Item.Data) do
begin
try
ModifyDprojVer(FileName, StrToInt(edMajor.Text), StrToInt(edMinor.Text)
, StrToInt(edRelease.Text), StrToInt(edBuild.Text));
ModifyResVer(GetProjectResFileName(FileName),
StrToInt(edMajor.Text), StrToInt(edMinor.Text)
, StrToInt(edRelease.Text), StrToInt(edBuild.Text));
ReadResVer(GetProjectResFileName(FileName), Major, Minor, Release, Build);
Result := True;
except
on E: Exception do
begin
ErrStr := E.Message;
end;
end;
end;
end;
function TMainForm.ExistsProject(const FileName: string): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to lvwProjectList.Items.Count - 1 do
begin
if SameText(lvwProjectList.Items[I].SubItems[0], FileName) then
begin
Result := True;
Break;
end;
end;
end;
function TMainForm.GetProjectResFileName(const FileName: string): string;
function ExtractMainFileName(const AFileName: string): string;
begin
Result := ExtractFileName(AFileName);
Result := Copy(Result, 1, Length(Result) - Length(ExtractFileExt(AFileName)));
end;
begin
Result := ExtractMainFileName(FileName) + '.res';
end;
procedure TMainForm.lvwProjectListClick(Sender: TObject);
begin
if lvwProjectList.Selected = nil then
Exit;
with TRecordObject(lvwProjectList.Selected.Data) do
begin
UpMajor.Position := Major;
UpMinor.Position := Minor;
UpRelease.Position := Release;
UpBuild.Position := Build;
end;
end;
procedure TMainForm.lvwProjectListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
Item.Caption := IntToStr(Item.Index + 1);
end;
procedure TMainForm.lvwProjectListDeletion(Sender: TObject; Item: TListItem);
begin
TRecordObject(Item.Data).Free;
end;
end.
unit MiscFuncsUnit;
interface
uses
Windows, SysUtils, unitResFile, unitResourceVersionInfo, xmldom, XMLIntf,
msxmldom, XMLDoc;
procedure ModifyDprojVer(const FileName: string; Major, Minor, Release, Build: Word);
procedure ModifyResVer(const FileName: string; Major, Minor, Release, Build: Word);
function ReadResVer(const FileName: string; var Major, Minor, Release, Build: Word): Boolean;
implementation
function FindNodeByAttrName(Node: IXMLNode; const NodeName, AttrName, AttrNameValue: WideString): IXMLNode;
var
I: Integer;
begin
Result := nil;
if (Node.NodeName = NodeName) and Node.HasAttribute(AttrName) and
(Node.Attributes[AttrName] = AttrNameValue) then
begin
Result := Node;
Exit;
end;
if Node.HasChildNodes then
begin
for I := 0 to Node.ChildNodes.Count - 1 do
begin
Result := FindNodeByAttrName(Node.ChildNodes[I], NodeName, AttrName, AttrNameValue);
if Result <> nil then
Break;
end;
end;
end;
procedure ModifyDprojVer(const FileName: string; Major, Minor, Release, Build: Word);
var
XmlDoc: IXMLDocument; // 注意此处一定要用IXMLDocument,否则会出错
RootNode, LNode: IXMLNode;
begin
XmlDoc := TXMLDocument.Create('');
XmlDoc.LoadFromFile(FileName);
RootNode := XmlDoc.Node;
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'MajorVer');
if LNode <> nil then
LNode.NodeValue := IntToStr(Major);
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'MinorVer');
if LNode <> nil then
LNode.NodeValue := IntToStr(Minor);
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'Release');
if LNode <> nil then
LNode.NodeValue := IntToStr(Release);
LNode := FindNodeByAttrName(RootNode, 'VersionInfo', 'Name', 'Build');
if LNode <> nil then
LNode.NodeValue := IntToStr(Build);
LNode := FindNodeByAttrName(RootNode, 'VersionInfoKeys', 'Name', 'FileVersion');
if LNode <> nil then
LNode.NodeValue := Format('%d.%d.%d.%d', [Major, Minor, Release, Build]);
XmlDoc.SaveToFile(FileName);
end;
procedure ModifyResVer(const FileName: string; Major, Minor, Release, Build: Word);
var
Res: TResModule;
I: Integer;
ResVer: TVersionInfoResourceDetails;
VerData: TULargeInteger;
begin
ResVer := nil;
Res := TResModule.Create;
try
Res.LoadFromFile(FileName);
for I := 0 to Res.ResourceCount - 1 do
begin
if Res.ResourceDetails[I] is TVersionInfoResourceDetails then
ResVer := Res.ResourceDetails[I] as TVersionInfoResourceDetails;
end;
if ResVer <> nil then
begin
VerData.HighPart := MakeLong(Minor, Major);
VerData.LowPart := MakeLong(Build, Release);
ResVer.FileVersion := VerData;
Res.SaveToFile(FileName);
end;
finally
Res.Free;
end;
end;
function ReadResVer(const FileName: string; var Major, Minor, Release, Build: Word): Boolean;
var
Res: TResModule;
I: Integer;
ResVer: TVersionInfoResourceDetails;
begin
Result := False;
ResVer := nil;
Res := TResModule.Create;
try
try
Res.LoadFromFile(FileName);
for I := 0 to Res.ResourceCount - 1 do
begin
if Res.ResourceDetails[I] is TVersionInfoResourceDetails then
ResVer := Res.ResourceDetails[I] as TVersionInfoResourceDetails;
end;
if ResVer <> nil then
begin
Major := HiWord(ResVer.FileVersion.HighPart);
Minor := ResVer.FileVersion.HighPart and $0000FFFF;
Release := HiWord(ResVer.FileVersion.LowPart);
Build := ResVer.FileVersion.LowPart and $0000FFFF;
Result := True;
end;
except
Result := False;
end;
finally
Res.Free;
end;
end;
end.
相关文章推荐
- (转) 自动编译iOS工程,生成app及ipa文件的方法
- windows下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件
- linux(以ubuntu为例)下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件
- webstorm修改文件,webpack-dev-server及roadhog不会自动编译刷新
- linux(以ubuntu为例)下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件
- Unity编译到Xcode自动添加文件及代码修改
- eclipse 在编译运行项目之前自动保存修改的文件
- Android之版本-自动添加编译时间-自动修改版本号
- jean同学的android编译自动修改版本号
- webstorm设置修改文件后自动编译并刷新浏览器页面
- eclipse 修改文件不自动编译
- webstorm设置修改文件后自动编译并刷新浏览器页面
- 设置eclipse在编译运行项目之前自动保存修改的文件
- myeclipse修改不能自动编译成相应的文件
- 在Visual C++中编译工程时自动增加版本号
- windows下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件
- Unity编译至Xcode工程后自动添加文件和库的方法
- webstorm修改文件,webpack-dev-server不会自动编译刷新
- webstorm修改文件,webpack-dev-server不会自动编译刷新
- eclipse中设置在编译运行项目之前自动保存修改的文件