通过网络自动升级软件: Detect and Download a new version of (an own) application? uses {...,}IniFiles, UrlMon, type TForm1 = class(TForm) {...} private winsc: TiniFile; old: Integer; vernfo: TIniFile; end;
implementation {$R *.dfm} function DownloadFile(Source, Dest: string): Boolean; { Function for Downloading the file found on the net } begin try Result := UrlDownloadToFile(nil, PChar(Source), PChar(Dest), 0, nil) = 0; except Result := False; end; end; function GetPathPath: string; { Retrive app path } begin Result := ExtractFilePath(Application.ExeName); end; procedure TForm1.DownLoadNewVersion1Click(Sender: TObject); var apath: string; new: Integer; begin // This is the exact code from my application apath := GetPathPath; Gauge1.Progress := 0; StatusBar1.SimplePanel := True; StatusBar1.SimpleText := 'Connecting to http://tsoft.home.ro'; Gauge1.Progress := 20; if DownloadFile('http://www.tsoft.home.ro/update.ini', PChar(apath) + '/update.ini') then begin Gauge1.Progress := 50; StatusBAr1.SimplePanel := True; StatusBar1.SimpleText := 'Checking for newer versions...'; vernfo := TiniFile.Create(GetPathPath + '/update.ini'); new := vernfo.ReadInteger('version', 'wsc', 7); vernfo.Free; if (old = new) then begin StatusBar1.SimplePanel := True; StatusBar1.SimpleText := 'No new version detected'; Gauge1.Progress := 100; end else if DownloadFile('http://www.tsoft.home.ro/winsafe.exe', PChar(apath) + '/winsafe.exe') then begin ShowMessage('Update succeseful'); Gauge1.Progress := 100; winsc := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini')); winsc.WriteInteger('wsc', 'vernfo', new); winsc.Free; end else MessageDlg('A new version has appeard but it requires a second install', mtInformation, [mbOK], 0); end else begin StatusBar1.SimplePanel := True; StatusBar1.SimpleText := 'Failed to connect probably a internet problem'; Gauge1.Progress := 0; end; end; procedure TForm1.FormCreate(Sender: TObject); begin //App version winsc := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini')); try old := winsc.ReadInteger('wsc', 'vernfo', 1); finally winsc.Free; end; end; end. {The concept is very simple u download a ini file from your website that contains the version you compare it with the one from your computer and it downloads the file if the versions are Not equal if you find any froblems write me.}
Detect and Download a new version of (an own) application?
uses
{...,}IniFiles, UrlMon, type
TForm1 = class(TForm)
{...}
private
winsc: TiniFile;
old: Integer;
vernfo: TIniFile;
end;
implementation {$R *.dfm} function DownloadFile(Source, Dest: string): Boolean;
{ Function for Downloading the file found on the net }
begin
try
Result := UrlDownloadToFile(nil, PChar(Source), PChar(Dest), 0, nil) = 0;
except
Result := False;
end;
end; function GetPathPath: string;
{ Retrive app path }
begin
Result := ExtractFilePath(Application.ExeName);
end; procedure TForm1.DownLoadNewVersion1Click(Sender: TObject);
var
apath: string;
new: Integer;
begin
// This is the exact code from my application
apath := GetPathPath;
Gauge1.Progress := 0;
StatusBar1.SimplePanel := True;
StatusBar1.SimpleText := 'Connecting to http://tsoft.home.ro';
Gauge1.Progress := 20;
if DownloadFile('http://www.tsoft.home.ro/update.ini', PChar(apath) + '/update.ini') then
begin
Gauge1.Progress := 50;
StatusBAr1.SimplePanel := True;
StatusBar1.SimpleText := 'Checking for newer versions...';
vernfo := TiniFile.Create(GetPathPath + '/update.ini');
new := vernfo.ReadInteger('version', 'wsc', 7);
vernfo.Free;
if (old = new) then
begin
StatusBar1.SimplePanel := True;
StatusBar1.SimpleText := 'No new version detected';
Gauge1.Progress := 100;
end
else if DownloadFile('http://www.tsoft.home.ro/winsafe.exe',
PChar(apath) + '/winsafe.exe') then
begin
ShowMessage('Update succeseful');
Gauge1.Progress := 100;
winsc := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
winsc.WriteInteger('wsc', 'vernfo', new);
winsc.Free;
end
else
MessageDlg('A new version has appeard but it requires a second install',
mtInformation, [mbOK], 0);
end
else
begin
StatusBar1.SimplePanel := True;
StatusBar1.SimpleText := 'Failed to connect probably a internet problem';
Gauge1.Progress := 0;
end;
end; procedure TForm1.FormCreate(Sender: TObject);
begin
//App version
winsc := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
old := winsc.ReadInteger('wsc', 'vernfo', 1);
finally
winsc.Free;
end;
end; end. {The concept is very simple u download a ini file from your website that contains
the version you compare it with the one from your computer and it downloads the
file if the versions are Not equal if you find any froblems write me.}
http://www.aslike.net
实现原理
PiUpdate模块的基本设计思想是将要更新的文件放在文件服务器上,工作站上的程序启动时调用PiUpdate, 对比服务器上的文件和本地的文件,如发现有新文件,则更新本地的对应文件。
首先,考虑到通用性的要求,将该模块设计成一个Windows标准的动态链接库(DLL),并在DLL中提供一个接口函数供其他程序调用。由于几乎各种开发工具都支持DLL调用机制,这样就保证了模块的通用性。
其次,为了灵活控制具体的更新文件,笔者使用了一个ini文件来提供相关的更新信息。ini文件名在主程序调用DLL接口函数时传入程序。
接口函数的定义形式如下:
function ExecuteUpdate(IniFileName:Pchar):integer; stdcall;
如果更新成功,则返回0,如果出现错误,则返回-1; 当将要更新的文件被运行中的应用程序使用时,接口函数会向主程序返回1。
接口函数的调用形式如下:
Delphi调用:function ExecuteUpdate(inifilename:pchar):integer;stdcall;external ‘PiUpdate.dll’;
PB调用:function integer ExecuteUpdate(ref string name) library“PiUpdate.dll”
考虑到不同编程语言中字符串存储形式不尽相同,函数参数采用了Windows API标准的C语言字符串形式,并且调用形式也采用Windows标准的StdCall形式。
配置ini文件的形式如下:
[程序名称]
filename1=\\Server\Share\filename1
filename2=\\Server\Share\filename2
…
更新方法
本文在更新一般文件时,使用的是CopyFile API。对于正在使用的文件,这个方法就行不通了。开始时,笔者查找了Windows API的有关资料,发现MoveFileEx函数可以在Windows重新启动时更新指定文件,这可以作为一种更新正在使用的文件的方法。但如果只是更新一个小程序,就要用户重新启动,有点小题大做的味道。后来,笔者在网上看到HAPPYZSL的一篇文章,发现其中使用的技巧十分有效。更新过程的思路是:如果发现被更新的文件正在使用,则将源文件复制到本地的一个临时文件,并建立一个del.BAT文件。在程序结束时运行该BAT文件,以完成对这些正在使用的文件的更新。del.BAT文件的内容如下:
@echo off
: loop
del destfile
if exist destfile goto loop
copy tmpfile destfile
del tmpfile
del .\del.bat
由于del.BAT运行后会一直执行,直到成功地删除了目标文件为止,所以主程序在检测到接口函数ExecuteUpdate返回值为1时,要立即退出,以便del.BAT能顺利地执行下去。
程序实现
主程序的实现代码如下:
function ExecuteUpdate(IniFileName: Pchar):integer;
//返回值:0 更新成功;-1 更新出错; 1 要更新的文件正在使用,需要立即退出程序
begin
result: =-1 ;
//获取配置文件名称
FName: =StrPas(IniFileName);
ProgList: =TStringList.Create;
try
//初始化更新配置信息
if InitUpdate(FName) then
begin
UpdateList:=TStringList.Create;
try
//检查需要更新的文件
if CheckNeedUpdate(ProgList,
UpdateList) then
//执行更新操作
result: =DoUpdate(UpdateList)
else
result: =0;
finally
UpdateList.Free;
end;
end;
finally
ProgList.Free;
end;
end;
小 结
如果在建立ini文件时,没有指定文件的目录位置,则默认使用Windows的系统目录,所以在调用接口函数时最好用ini文件的全路径名称。如果不方便给出全路径名称,也可以采用“.\filename.ini”的形式进行调用。
对于文件是否需要更新,程序员可以根据实际情况来编写判断标准。为方便修改,在程序中将其写成函数FileDiff(sFile,dFile: string)的形式,可以加上文件大小、版本号等条件。
为了使更新过程能更加完善,建议将本模块及更新配置文件也放在服务器上相应的共享目录下,并作为待更新的文件加到更新文件列表中。这样一来,如果服务器端的PiUpdate.dll更新了,用户的PiUpdate.dll也会同样得到更新。如果由于程序功能的增加,加入了新的文件,只要将新加的文件放到服务器上,并修改服务器上的更新配置文件,工作站上的程序启动时会先将新的配置文件复制到本地,下次本地程序再启动时就可以更新新加入的文件。