如何在内部网内实现:分机启动某程序,判断版本,自动升级(0分)

N

nutian

Unregistered / Unconfirmed
GUEST, unregistred user!
判断版本用什么方法?设想过程:
1、主程序读指定主机指定文件的内容,(用读INI文件的方法可行不?)(错误处理:
没找到那个文件;主机没开机;),-------和程序内的版本字符比较---更新另一个
升级文件-----判断更新完成(用什么方法判断?),--------运行升级文件,--主程序自己退出。
2、升级文件启动后SLEEP几秒,扫描主程序进程,关闭他,升级、更新主程序(从主机
COPY文件),判断COPY完成,执行升级要运行的一些安装程序(如果有的话),判断升
级完成(如果升级只进行了部分,怎么判断升级是成功了?怎么判断安装程序执行完了?)
,升级程序启动主程序,升级程序自己退出!
3、新的主程序开始运行!
括号中的为我不能解决的问题!

 
客户端程序A每次运行时先到服务器上取版本号,然后与本地INI文件中的版本号对比,如果
不一样则自动升级(运行程序B从服务器上COPY最新版本的程序)。
现在的问题是怎么样关掉客户端的程序A----->执行程序B----->从服务器上COPY最新的
程序A---->最后自动载入运行?
附程序A:
begin
if application.MessageBox(pchar('客户端最新版本为' + ServerVer + ',请立即更新!'), '提示', mb_YesNo + mb_IconQuestion) = Id_Yes then
begin
mainform.WindowState := wsMinimized;
close;
application.Terminate;
ShellExecute(handle, 'open', PChar('b.exe'), '', '', sw_ShowNormal);
end;
end;

程序B:
dirs := ExtractFilePath(Application.ExeName);
DeleteFile(pchar(dirs + 'a.exe'));
CopyFile(pchar('//'+ServerName+'/server_cc/a.exe.exe'), pchar(dirs + 'a.exe'), false);

我原来程序是这样写的,但是不能关掉自己(程序A)啊,有什么办法吗?[?]
=====================================================================
难道application.Terminate不能终止程序运行吗?


ShellExecute(handle, 'open', PChar('b.exe'), '', '', sw_ShowNormal);
application.Terminate;
exit; //<--防止其它因素影响程序退出的速度。

通常程序B还应该有一等待程序A结束的过程。可以用findwindow、loop、ProcessMessages
来完成。
=============================================================================
不知这样可否?
程序A:
procedure TForm1.FormCreate(Sender: TObject);
var mver,mpath,mrpath:string;
m,n:dword;
buf:pchar;
begin
//获取远程服务器上的程序的版本信息
mrpath:='//服务器上新程序路径';
if FileExists(mrpath) then
m:=GetFileVersionInfoSize(PChar(mpath),m) //服务器上新程序和版本号
else m:=0;

//获取当前程序的版本信息
mpath:=ExtractFilePath(Application.ExeName); //当前程序所在路径
n:=GetFileVersionInfoSize(PChar(mpath),n); //当前程序版本号
if (m<>n) and (m<>0) then
if MessageDlg('当前程序需升级',mtconfirmation,[mbyes,mbcancel],0)<>mryes then
exit else
try
ShellExecute(handle,'open',PChar(mpath+'B.exe'),'','',sw_ShowNormal);
Application.Terminate;
Except
ShowMessage('升级失败!');
exit;
end;
end;

程序B:
procedure TForm1.FormCreate(Sender: TObject);
var mpath,mrpath:string;
begin
label2.Caption:='程序正在升级,请稍候..';
bitbtn1.Enabled:=false;
bitbtn2.Enabled:=false;
mpath:=ExtractFilePath(Application.ExeName); //当前程序所在路径
mrpath:='//服务器上新程序路径';
if RenameFile(mpath+'A.exe',mpath+'A.backup')=false then begin
DeleteFile(mpath+'A.backup');
renamefile(mpath+'A.exe',mpath+'A.backup'); //备份原程序
end;
if CopyFile(pchar(mrpath),pchar(mpath+'A.exe'),false) then begin
label3.caption:='程序升级完毕,原程序已备份!';
label5.caption:='如需现在运行新程序则按“确定”继续!'; //bitbtn1
label6.caption:='否则按完成稍后运行!'; //bitbtn2
bitbtn1.Enabled:=true;
bitbtn2.Enabled:=true;
end else begin
showmessage('拷贝文件出错,升级失败!');
exit;
end;
end;

procedure TForm1.BitBtn1Click(Sender: TObject); //现在运行程序
begin
ShellExecute(handle,'open',PChar(ExtractFilePath(Application.ExeName)+'A.exe'),'','',sw_ShowNormal);
Application.Terminate;
end;

procedure TForm1.BitBtn2Click(Sender: TObject); //稍后运行程序
begin
Application.Terminate;
end;

程序A与B在同一目录中
========================================================================
谢谢大家的帮助!
不过最后我自己用了一种更加简单方便的方法,程序如下 :

程序A:
begin
if application.MessageBox(pchar('客户端最新版本为' + ServerVer + ',请立即更新!'), '提示', mb_YesNo + mb_IconQuestion) = Id_Yes then
begin
mainform.WindowState := wsMinimized;
close;
close;
AssignFile(F, 'delself.bat');
Rewrite(F);
WriteLn(F, 'del ' + ExtractFileName(Application.ExeName));
WriteLn(F, 'b.exe');
CloseFile(F);
WinExec('delself.bat', SW_HIDE);
end;
end;

程序b不做任何改动。
=======================================================================

 
比较的我想你应该知道了吧?给你贴点替换的.
procedure ChangeFile(SourceFile,TargetFile:string);
var F:TextFile;
FileName:string;
begin
FileName:=ExtractFileName(SourceFile);
CopyFile(PChar(TargetFile),PChar(SourceFile+'.Bak'),False);
AsSignFile(F,'ChangeFile.bat');
Rewrite(F);
Writeln(F,'ren '+FileName+' '+FileName+'.old');
Writeln(F,'ren '+FileName+'.bak'+' '+FileName);
Writeln(F,'del '+FileName+'.old');
Writeln(F,'del %0');
CloseFile(F);
WinEXEc('ChangeFile.bat',SW_HIDE);
Sleep(1000);
WinEXEc(PChar(SourceFile),SW_SHOW);//这儿重新运行你的程序.
end;
=====================================================================
对于只有一个EXE文件的程序的自动升级,我的经验是:

  一、没有必要区分局域网与广域网,都用统一的网络连接方法,包括检测新版本的方法
和下载新版本程序文件的方法,可以使用HTTP、也可以使用FTP,这两个细节你可以
自己考虑。

  二、版本检测与更新部分程序逻辑:(可以考虑放在MainForm的Create
事件里面,始终注意Windows不许删除与覆盖正在运行的程序)

if 本程序文件名有NEW标识 then
begin
  稍微延时//等待正常文件名的程序自行结束
  复制本文件到正常文件名//覆盖先前内容
  启动正常文件名程序
  结束当前程序执行
end
else 删除有NEW标识的文件;

if 检测新版本成功完成 and 确实存在新版本程序 and 操作者同意立即升级 then
begin
  下载新版本到本目录,文件名字加标识NEW
  运行(NEW文件)
  结束当前程序运行
end;
 
program with delphi6.0
use indy:http
the content of version.ini is:
1.0.0.0 (only one line)

procedure checkupdate;
var
ustream:tmemorystream;
verstr:string;
oldname,newname:pchar;
oldsize,newsize:dword;
begin
ustream :=tmemorystream.Create ;
try
//get new version infomation
verstr:=frmclient.HTTPC.Get('/jfgl/version.ini');
if (verstr<>'') and ((strtointdef(fetch(verstr,'.'),1)>1) or (strtointdef(fetch(verstr,'.'),0)>1) or (strtointdef(fetch(verstr,'.'),1)>0) or (strtointdef(fetch(verstr,'.'),1)>0)) then
try
//get new exe file and rename to filename.tmp
frmclient.httpc.Get('/jfgl/client.exe',ustream);
ustream.SaveToFile(ChangeFileExt(application.ExeName,'.tmp'));
//replace exe file until last boot because it is now running
//if you have better method please tell me,thank's
getmem(oldname,max_path);
fillchar(oldname[0],max_path-1,0);
getshortpathname(pchar(application.exename),oldname,oldsize);
getmem(newname,max_path);
fillchar(newname[0],max_path-1,0);
getshortpathname(pchar(ChangeFileExt(application.ExeName,'.tmp')),newname,newsize);
movefileex(newname,oldname,MOVEFILE_DELAY_UNTIL_REBOOT or MOVEFILE_REPLACE_EXISTING);
except
end;
except
//
end;
freeandnil(ustream);
end;
补充两句:
思路是:(从flashget升级的方法而知)
在升级服务器上存放一个信息文件,注明新版本的各项特性,进行升级时新下载该信息文件
与当前文件进行比较,然后决定是否从服务器上下载新版本的程序文档。
刚发上的例子仅仅是个演示。信息文件中存放的是版本信息
major.minor.release.build,在主程序中用一个变量存放当前的版本信息,也可以在程序
中实时的获取当前使用的文件的版本信息。然后进行比较。
下载完毕后要做的就是如何将当前正在运行的程序文件进行替换的问题了。可以用运行
*.bat的方法,也可以用特殊的文件更名的方法(我给出的程序段就是这种方法),该方法
将在下次启动时将文件替换掉,程序中有一段更改为短文件名的代码,因为我在论坛中获知
说用长文件名可能出现问题。
再说两句:
既然是在线升级就必须有服务器,通常情况下使用ftp、http协议访问服务器比较可行。
我给出的程序段使用的是delphi6.0,但是使用的协议是http协议,在delphi5.0中用也可以
顺利使用的,只要将indy的http控件换为别的http控件就可以了,如果功底深的话,直接
用winsock进行编程也可以。最主要的是探讨一种方法,不要拘泥于程序的版本和编程的
语言。
=============================================================================
有很多方法取得文件信息。
1。规范的文件命名方法 (如: program-version-language-platform.ext)
2。使用信息文件保存文件版本信息
或使用数据库保存文件版本信息
3。使用服务端脚本返回文件信息 (如果可用,这个方法较好)
或客户端程序读取文件信息。
========================================================================

 
我为了方便更新我的程序,自已做了一个自动升级的程序,其中在客户端和服务器
上各有一个配置文件,升级时根据本机的版本号和服务器上的版本号比较,如服务
器上的版本号高就更新程序,否则不更新,两个配置文件的说明如下:
一、本机需文件:
1、autoup.exe(自动更新程序本身)

2、system.ini(不是必须,如无第一次运行将自动生成)

3、system.ini格式
[system]
program=sales ;应用系统代号。同时也是FTP服务器down目录下的子目录名
aUsers=anonymous ;登录FTP服务器的用户名
aPassword= ;登录FTP服务器的密码
FTPServe=10.42.160.3 ;FTP服务器地址。需下载的文件位于down目录下的不同子目录中,根据program节的值决定,服务器的配置文件位于down目录下
SavPath=F:/borland/mycode/tobacco/jxcup/ ;本机业务系统的路径
Version=1.1 ;版本号。这是升级的依据,如果本机的Version号小于服务器端update.ini中的Version号则升级,否则不升级。

二、服务器端文件:
1、配置文件update.ini

2、不同业务系统中需更新的文件(位于不同的子目录中,子目录名同客户端配置文件中的program节的内容相同,可以是压缩文件,但必须用RAR压缩)

3、Update.ini格式
[CanDown]
VerSion=1.1 ;版本号。需大于客户端的版本号
UpdateTime=2002-12-01 ;版本日期。程序中未使用,可不设

[branch] ;必须与客户端的业务系统代号相同,即与program的值相同
compress=1 ;是否压缩,为1,则客户端下载后将自动解压缩,否则不解压缩
FileCounts=1 ;客户端须下载的文件总数
File1=pbl.rar ;客户端须下载的文件列表,用File1=文件名,File2=文件名的格式依次下排


[sales] ;必须与客户端的业务系统代号相同,即与program的值相同
;是否压缩,不需解压缩的可不设Compress节
FileCounts=3 ;客户端须下载的文件总数
File1=tobacco.exe ;客户端须下载的文件列表,用File1=文件名,File2=文件名的格式依次下排
File2=store1.pbd
File3=store2.pbd
========================================================================
不知我的是否能对你有用?

我将部分代码贴出,你参考吧,希望对你有用

程序中FTP下载采用了INDY的FTP控件(DELPHI7自带的),开发环境是(Win2000,Delphi 7)

procedure TFrmMain.BitBtn1Click(Sender: TObject);
var
tmpini:Tinifile;
tver,tsys:string;
begin
BitBtn2.Click;
if MessageDlg('升级前请务必关闭业务管理系统,你已经关闭了吗?',
mtWarning, [mbYes, mbNo], 0) = mrNo then
begin
showmessage('只有在关闭了业务管理系统后才能升级!请先关闭系统!');
exit;
end;
BitBtn4.Visible:=True;
tmpini:=TiniFile.Create(extractfilepath(application.ExeName)+'system.ini');
tver:=tmpini.ReadString('system','Version','');
tsys:=tmpini.ReadString('system','Program','');
if tver='' then
begin
tmpini.WriteString('system','Version','1.0');
tver:='1.0';
end;
if tsys='' then tsys:='branch';
tmpini.Free;
getnewfile('set',tver,tsys);
if tver<NewVer then
begin
getnewfile('Files',tver,tsys);
end
else
showmessage('已经是最新版本!');
end;

procedure TFrmMain.getnewFile(sfile:string;const tver:string='';tsys:string='branch');
var
appini,appini1:Tinifile;
i,compr:integer;
tfiles,dfiles,tdir:string;
begin
idFTP1.Host:=LabeledEdit3.Text;
idFTP1.Username:=LabeledEdit1.Text;
idFTP1.Password:=labeledEdit2.Text;

if not idFTP1.Connected then
try
idFTP1.Connect;
except
showmessage('不能连接远程服务器,请查原因!');
abort;
end;
idFTP1.ChangeDir('/down/');
IdFTP1.TransferType := ftBinary;

//下载配置文件
if sfile='set' then
begin
dfiles:=extractfilepath(application.ExeName)+'UPdate.ini';
BytesToTransfer:=idFTP1.Size('update.ini');
idFTP1.Get('update.ini',dfiles,True);

appini:=Tinifile.Create(extractfilepath(application.ExeName)+'update.ini');
NewVer:=appini.ReadString('CanDown','Version','');
oldVer:=Tver;
appini.Free;
end
else
begin
//下载升级文件

//检查下载文件保存路径是否存在
tdir:=LabeledEdit4.Text;
if tdir[length(tdir)]<>'/' then tdir:=tdir+'/';
if not directoryexists(tdir+'update/') then
mkdir(tdir+'update/');

appini:=Tinifile.Create(extractfilepath(application.ExeName)+'update.ini');
icount:=appini.ReadInteger(tsys,'FileCounts',0);
compr:=appini.ReadInteger(tsys,'compress',0);

if (OldVer<>'') and (OldVer>NewVer) then
begin
showmessage('已经是最新版本了!');
appini.Free;
exit;
end;
if OldVer<NewVer then
begin
appini1:=TiniFile.Create(extractfilepath(application.ExeName)+'system.ini');
appini1.WriteString('system','Version',Newver);
appini1.Free;
end;
if icount>0 then
begin
idFTP1.ChangeDir('/down/'+tsys);

for i:=1 to icount do
begin
tfiles:=appini.ReadString(tsys,'File'+inttostr(i),'');
if tfiles<>'' then
begin
staticText2.Caption:='正在下载文件:'+tfiles;
BytesToTransfer:=idFTP1.Size(tfiles);
idFTP1.Get(tfiles,tdir+'update/'+tfiles,True);
end;
end;
appini.Free;
CopyFileToUse(compr,tsys);
end;
end;
end;


//将新下载的文件拷贝到程序目录中
procedure TFrmMain.CopyFileToUse(Compr:integer;const tsys:string='branch');
var
appini:Tinifile;
i,j:integer;
tfiles,tdir,tmp1:string;
begin
tdir:=LabeledEdit4.Text;
if tdir[length(tdir)]<>'/' then tdir:=tdir+'/';
appini:=Tinifile.Create(extractfilepath(application.ExeName)+'/update.ini');
i:=appini.ReadInteger(tsys,'FileCounts',0);
if i>0 then
begin
for j:=1 to i do
begin
tfiles:=appini.ReadString(tsys,'File'+inttostr(j),'');
if tfiles<>'' then
begin
staticText2.Caption:='正在更新文件:'+tfiles;
if compr=1 then
begin
tmp1:=tdir+'rar e '+tdir+'update/'+tfiles+' -y '+tdir;
// WinexecAndWait32(tmp1,sw_show);
WinexecAndWait32(tmp1,sw_hide);
end
else
CopyFile(tdir+'update/'+tfiles,tdir+tfiles);
end;
end;
appini.Free;
end;
staticText2.Caption:='共更新了'+inttostr(i)+'个文件';
end;

function WinExecAndWait32(FileName:String; Visibility :integer):longword;
var
zAppName:array[0..512] of char;
zCurDir:array[0..255] of char;
WorkDir:String;
StartupInfo:TStartupInfo;
ProcessInfo:TProcessInformation;
begin
StrPCopy(zAppName,FileName);
GetDir(0,WorkDir);
StrPCopy(zCurDir,WorkDir);
FillChar(StartupInfo,Sizeof(StartupInfo),#0);
StartupInfo.cb := Sizeof(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := Visibility;
if not CreateProcess(nil,
zAppName, { pointer to command line string }
nil, { pointer to process security attributes }
nil, { pointer to thread security attributes }
false, { handle inheritance flag }
CREATE_NEW_CONSOLE or { creation flags }
NORMAL_PRIORITY_CLASS,
nil, { pointer to new environment block }
nil, { pointer to current directory name }
StartupInfo, { pointer to STARTUPINFO }
ProcessInfo) then Result :=499 { pointer to PROCESS_INF }
else
begin
WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
GetExitCodeProcess(ProcessInfo.hProcess,Result);
end;
end;

 
顶部