Delphi 实现可执行程序的自动升级

准备工作:

1:Delphi调用TIdHTTP方式开发程序,生成程序打包外壳

说明:程序工程命名为ERP_Update

界面布局如下:

代码实现如下:

 unit Unit1;

 interface

 uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls,
IdTCPConnection, SHELLAPI, ComCtrls, jpeg, IdHTTP,
IdTCPClient, IdBaseComponent, IdComponent, Registry; type
TFrm_FTP = class(TForm)
Label4: TLabel;
IdHTTP1: TIdHTTP;
Image1: TImage;
ProgressBar1: TProgressBar;
Label1: TLabel;
procedure RUN_START;
procedure FormCreate(Sender: TObject);
procedure IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCount: Integer);
procedure IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCountMax: Integer);
procedure IdHTTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
function HttpDownLoad(aURL, aFile: string): Boolean;
function GetURLFileName(aURL: string): string;
function GET_CODE(V_s: TstringS; V_CODE: string): string;
function GET_SubStr(V_s: string; V_CODE1, V_CODE2: string): string;
procedure DelFile(V_Name: string);
function GET_Ora_Home(): string;
private
{ Private declarations } public
{ Public declarations }
end; var
Frm_FTP: TFrm_FTP;
ss: Tstrings;
V_Err: Boolean;
BytesToTransfer: LongWord; implementation {$R *.dfm} function TFrm_FTP.GET_Ora_Home(): string;
var
v_Result: string;
begin
v_Result := '';
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKey('\Software\ORACLE', false) then
begin
v_Result := ReadString('ORACLE_HOME');
if v_Result <> '' then
v_Result := v_Result + '\network\admin\tnsnames.ora';
CloseKey;
end;
finally
Free;
end;
Result := v_Result;
end; procedure TFrm_FTP.RUN_start;
var
V_LiveUpdate, V_version, C_ServerIP, C_ServerVer, C_ExeVer, c_ExeName, C_ExePath: string;
i: Integer;
begin
V_Err := False;
C_ExePath := ExtractFilePath(Application.ExeName); //可执行程序的路径[D:\CDERP\长电包装生产管理系统\]
//获取本地的版本信息等数据
ss := Tstringlist.create;
ss.loadfromfile(C_ExePath + 'LiveUpdate.ini');
V_version := GET_SubStr(ss.Strings[], 'url=', ''); //服务器地址
V_LiveUpdate := stringreplace(UpperCase(V_version), 'VERSION.INF', 'LIVEUPDATE.INI', [rfReplaceAll]); //服务器地址
C_ExeVer := GET_SubStr(ss.Strings[], 'version=', ''); //本地程序的版本
C_ExeName := GET_SubStr(ss.Strings[], 'exe=', ''); //本地程序的名称
//获取服务器的版本
if HttpDownLoad(V_version, C_ExePath + GetURLFileName(V_version)) then
begin
ss.loadfromfile(C_ExePath + 'version.inf');
C_ServerVer := get_code(ss, '#version=');
end
else
C_ServerVer := C_ExeVer; //如果升级服务器异常就不升级
if (trim(ParamStr()) = '') or (trim(ParamStr()) = '/afterupgrade0') then
begin
//程序在本地第一次执行,如果需要升级将下载cderp.exe到本地update.exe并执行
//比较版本信息
if C_ServerVer > C_ExeVer then
begin
C_ExeVer := C_ServerVer;
DelFile(C_ExePath + 'update.exe');
HttpDownLoad(GET_SubStr(V_version, '', '/exe/') + '/exe/ERP_Update.exe', C_ExePath + 'update.exe');
ShellExecute(handle, 'open', pchar(C_ExePath + 'ERP_Update.exe'), pchar('"' + C_ExePath + '" "' + C_ExeVer + '"'), nil, SW_ShowNormal);
end
else
ShellExecute(handle, 'open', pchar(C_ExePath + C_ExeName), nil, nil, SW_ShowNormal);
application.Terminate;
end
else
begin
Frm_FTP.WindowState := wsNormal;
Frm_FTP.Visible := true;
Frm_FTP.Refresh;
V_Err := False;
//防止可执行程序没有完全关闭, 等待一会
ProgressBar1.max := ;
for i := to do
begin
Label4.Caption := '升级准备...';
ProgressBar1.Position := i;
Application.ProcessMessages;
Sleep();
end;
for i := to do
begin
C_ServerIP := get_code(ss, '#url' + trim(IntToStr(i)) + '=');
if C_ServerIP = '' then
begin
Break;
end;
HttpDownLoad(C_ServerIP, C_ExePath + GetURLFileName(C_ServerIP));
end;
HttpDownLoad(V_LiveUpdate, C_ExePath + GetURLFileName(V_LiveUpdate));
if not V_Err then
begin
ss.loadfromfile(C_ExePath + GetURLFileName(V_LiveUpdate));
ss.delete();
ss.delete();
ss.Add('version=' + C_ServerVer);
ss.Add('exe=' + C_ExeName);
ss.savetofile(C_ExePath + GetURLFileName(V_LiveUpdate));
ss.free;
Application.MessageBox('程序已经升级完成!', '升级完成', MB_ICONINFORMATION + MB_OK);
ShellExecute(handle, 'open', pchar(C_ExePath + C_ExeName), nil, nil, SW_ShowNormal);
end;
application.Terminate;
end;
end; procedure TFrm_FTP.FormCreate(Sender: TObject);
begin
RUN_start;
end; function TFrm_FTP.GET_CODE(V_s: TstringS; V_CODE: string): string;
var
i, j, l: integer;
v_Result: string;
begin
j := V_s.Count - ;
l := length(v_code);
i := ;
while i <= j do
begin
if copy(trim(UpperCase(V_s.Strings[i])), , l) = UpperCase(V_CODE) then
begin
v_Result := copy(trim(V_s.Strings[i]), l + , );
j := ;
end;
i := i + ;
end;
Result := v_Result;
end; function TFrm_FTP.GET_SubStr(V_s: string; V_CODE1, V_CODE2: string): string;
var
j, k: integer;
v_str: string;
begin
//Label4.Caption := GET_SubStr('url=http://192.1.1.0/exe/ERP_Update/version.inf', '://', '/exe');
//数据解析,找到字符串中的子串
v_str := UpperCase(V_s);
k := pos(UpperCase(v_code1), v_str);
if v_code1 = '' then
begin
k := ;
end;
if k > then
begin
v_str := copy(v_str, k + length(v_code1), );
if v_code2 = '' then
k :=
else
k := pos(UpperCase(v_code2), v_str);
if k > then
begin
v_str := copy(v_str, , k - );
end
else
begin
v_str := '';
end;
end
else
begin
v_str := '';
end;
Result := v_str;
end; procedure TFrm_FTP.DelFile(V_Name: string);
var
i: integer;
begin
i := ;
while FileExists(V_Name) do
begin
DeleteFile(V_Name);
Application.ProcessMessages;
i := i + ;
if i > then
begin
if MessageDlg('系统不能执行删除操作[' + V_Name + '],是否重试?', mtConfirmation, [mbYes, mbNo], ) = mrNO then
begin
i := ;
Abort;
end;
end;
end;
end; procedure TFrm_FTP.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCount: Integer);
begin
ProgressBar1.Position := AWorkCount;
end; procedure TFrm_FTP.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCountMax: Integer);
begin
if AWorkCountMax > then
ProgressBar1.max := AWorkCountMax
else
ProgressBar1.Max := BytesToTransfer; end; procedure TFrm_FTP.IdHTTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
begin
BytesToTransfer := ; end;
//http方式下载 function TFrm_FTP.HttpDownLoad(aURL, aFile: string): Boolean;
var
MyStream: TMemoryStream; //如果文件不存在
F_Str: string;
begin
if V_Err then exit;
try
label4.Caption := '正在升级...' + GetURLFileName(aURL);
label4.Refresh;
MyStream := TMemoryStream.Create;
IdHTTP1.Request.ContentRangeStart := ;
try
IdHTTP1.Get(stringreplace(UpperCase(aURL), '192.1.1.0/EXE/', '192.1.1.0/EXE/', [rfReplaceAll]), MyStream); //开始下载
MyStream.SaveToFile(aFile);
if pos('.REG', UpperCase(aFile)) > then
WinExec(pchar('regedit.exe /s "' + aFile + '"'), SW_HIDE); if pos('TNSNAMES.ORA', UpperCase(aFile)) > then
begin
F_Str := GET_Ora_Home;
if F_Str <> '' then MyStream.SaveToFile(F_Str);
end; label4.Caption := '升级完成';
finally
MyStream.Free;
end;
Result := True;
except
on E: Exception do
begin
Application.MessageBox(PChar('升级[' + GetURLFileName(aURL) + ']过程中出现错误了,错误信息如下:' + # + # + E.Message), PChar('系统提示'), Mb_OK + MB_ICONERROR);
V_Err := True;
Result := False;
end;
end;
end; function TFrm_FTP.GetURLFileName(aURL: string): string;
var
i: integer;
s: string;
begin
s := aURL;
i := Pos('/', s);
while i <> do //去掉"/"前面的内容剩下的就是文件名了
begin
Delete(s, , i);
i := Pos('/', s);
end;
Result := s;
end; end.

2:FTP服务器搭建,FTP用户创建

举例说明如下:

在192.1.1.0上创建FTP账户Test 密码Test,路径 \exe\;

案例:将Test.exe系统做出一个可以自动升级的系统

文件准备:

1:Test.exe (目标系统);

2:ERP_Update.exe (自动升级外壳程序);

3:创建配置文件 (LiveUpdate.ini、Version.inf);

建立一个记事本文件,命名为LiveUpdate.ini,内容输入

[LiveUpdate]
url=http://192.1.1.0/exe/Test/version.inf
version=0
exe=Test.EXE

建立一个记事本文件,命名为version.inf,内容输入

#############################################################
#   Generated by AutoUpgrader Pro at: 2019-8-29 20:50:39    #
#############################################################
#message={}
#url1=http://192.1.1.0/exe/ERP_Update.exe
#url2=http://192.1.1.0/exe/Test/Test.exe
#url3=http://192.19.1.0/exe/Test/version.inf
#method=0 (self-upgrade)
#version=0

4:FTP操作(文件替换、配置文件更新);

将Test.exe (目标系统)、ERP_Update.exe (自动升级外壳程序)、创建配置文件 (LiveUpdate.ini、Version.inf)文件同时放到192.1.1.0FTP服务器\exe\Test\文件夹下。

并手工修改LiveUpdate中的Version,同理Version中也需要这么改。

至此在本地打开ERP_Udapate即可实现自动升级。

作者:Jeremy.Wu
  出处:https://www.cnblogs.com/jeremywucnblog/

  本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

Delphi - Indy TIdHTTP方式创建程序外壳 - 实现可执行程序的自动升级的更多相关文章

  1. DevExpress XtraReports 入门六 控件以程序方式创建一个 交叉表 报表

    原文:DevExpress XtraReports 入门六 控件以程序方式创建一个 交叉表 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助 ...

  2. [delphi]indy idhttp post方法

    网易 博客 LOFTCam-用心创造滤镜 LOFTER-最美图片社交APP 送20张免费照片冲印 > 注册登录  加关注 techiepc的博客 万事如意 首页 日志 LOFTER 相册 音乐 ...

  3. Delphi中DLL的创建和使用

    参考:http://blog.csdn.net/ninetowns2008/article/details/6311663 结合这篇博客:http://www.cnblogs.com/xumenger ...

  4. Delphi XE5教程2:程序组织

    内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误! 也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者 ...

  5. 有谁知道Delphi中"窗口"的创建过程?

      求助:有谁知道Delphi中窗口的创建过程,此“窗口”不仅仅指 TForm 类型, 还包括一般的窗口控件,如TButton,TEdit等等,希望有能够十分详细的运作 过程,比如说CreatPara ...

  6. 零基础逆向工程39_Win32_13_进程创建_句柄表_挂起方式创建进程

    1 进程的创建过程 打开系统 --> 双击要运行的程序 --> EXE开始执行 步骤一: 当系统启动后,创建一个进程:Explorer.exe(也就是桌面进程) 步骤二: 当用户双击某一个 ...

  7. Delphi中DLL的创建和使用(转)

    Delphi中DLL的创建和使用     1.DLL简介:   2.调用DLL:   3.创建DLL:   4.两个技巧:   5.初始化:   6.例外处理.            1.DLL简介  ...

  8. [转]C#创建服务及使用程序自动安装服务,.NET创建一个即是可执行程序又是Windows服务的exe

    写在前面 原文地址:C#创建服务及使用程序自动安装服务,.NET创建一个即是可执行程序又是Windows服务的exe 这篇文章躺在我的收藏夹中有很长一段时间了,今天闲着没事,就自己动手实践了一下.感觉 ...

  9. Spring工厂方式创建Bean实例

    创建Bean实例的方式: 1) 通过构造器(有参或无参) 方式: <bean id="" class=""/> 2) 通过静态工厂方法 方式: &l ...

随机推荐

  1. UML同一建模语言

    结构型图:描述系统静态结构,显示系统类之间的静态关系. 行为型图:描述系统的动态属性,显示系统元素如何协作产生满足要求的系统行为. 类图分类名,属性清单,方法清单,性质清单几层 类之间的关系:1 一般 ...

  2. PLSQL连接数据库报监听程序找不到符合协议堆

    服务器上某个数据库出现' ORA-12516: TNS: 监听程序找不到符合协议堆栈要求的可用处理程'错误,要解决该问题首先查看一下数据库现有的进程数,是否已经达到参数processes的大小   根 ...

  3. 11. Java常用类

    1. Scanner类 1.1 基本语法 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入. Scanner s = new Scanne ...

  4. Java学习-内存划分及内存的调用关系

    一.JAVA内存划分 JAVA的内存可以划分为五个部分:堆.栈.方法区.本地方法区和寄存器. 堆(Heap):凡是new出来的东西都在堆中 如: integer = new Integer(2) // ...

  5. html以前没有学到的标签

    <q>标签,短文本引用 <blockquote>标签,长文本引用 <address>标签,为网页加入地址信息 <code>标签,插入单行代码 <p ...

  6. 从js 讲解时间复杂度和空间复杂度

    1. 博客背景 今天有同事在检查代码的时候,由于函数写的性能不是很好,被打回去重构了,细思极恐,今天和大家分享一篇用js讲解的时间复杂度和空间复杂度的博客 2. 复杂度的表示方式 之前有看过的,你可能 ...

  7. 转载 vue-awesome-swiper - 基于vue实现h5滑动翻页效果

    说到h5的翻页,很定第一时间想到的是swiper.但是我当时想到的却是,vue里边怎么用swiper?! 中国有句古话叫:天塌下来有个高的顶着. 在前端圈里,总有前仆后继的仁人志士相继挥洒着热汗(这里 ...

  8. 【简洁易懂】CF372C Watching Fireworks is Fun dp + 单调队列优化 dp优化 ACM codeforces

    题目大意 一条街道有$n$个区域. 从左到右编号为$1$到$n$. 相邻区域之间的距离为$1$. 在节日期间,有$m$次烟花要燃放. 第$i$次烟花燃放区域为$a_i$ ,幸福属性为$b_i$,时间为 ...

  9. java并发编程(四)----(JUC)Lock锁初探

    首先我们来回忆一下上一节讲过的synchronized关键字,该关键字用于给代码段或方法加锁,使得某一时刻它修饰的方法或代码段只能被一个线程访问.那么试想,当我们遇到这样的情况:当synchroniz ...

  10. springboot整合websocket高级版

    目录 sockjs介绍 产生的原因 环境搭建 springboot整合sockjs 使用场景 聊天室开发 点对点通信 群聊 效果 总结 加入战队 微信公众号 上一章节我们说了websocket的优缺点 ...