Delphi - Indy TIdHTTP方式创建程序外壳 - 实现可执行程序的自动升级
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 #
#############################################################
#url2=http://192.1.1.0/exe/Test/Test.exe
#url3=http://192.19.1.0/exe/Test/version.inf
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方式创建程序外壳 - 实现可执行程序的自动升级的更多相关文章
- DevExpress XtraReports 入门六 控件以程序方式创建一个 交叉表 报表
原文:DevExpress XtraReports 入门六 控件以程序方式创建一个 交叉表 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助 ...
- [delphi]indy idhttp post方法
网易 博客 LOFTCam-用心创造滤镜 LOFTER-最美图片社交APP 送20张免费照片冲印 > 注册登录 加关注 techiepc的博客 万事如意 首页 日志 LOFTER 相册 音乐 ...
- Delphi中DLL的创建和使用
参考:http://blog.csdn.net/ninetowns2008/article/details/6311663 结合这篇博客:http://www.cnblogs.com/xumenger ...
- Delphi XE5教程2:程序组织
内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误! 也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者 ...
- 有谁知道Delphi中"窗口"的创建过程?
求助:有谁知道Delphi中窗口的创建过程,此“窗口”不仅仅指 TForm 类型, 还包括一般的窗口控件,如TButton,TEdit等等,希望有能够十分详细的运作 过程,比如说CreatPara ...
- 零基础逆向工程39_Win32_13_进程创建_句柄表_挂起方式创建进程
1 进程的创建过程 打开系统 --> 双击要运行的程序 --> EXE开始执行 步骤一: 当系统启动后,创建一个进程:Explorer.exe(也就是桌面进程) 步骤二: 当用户双击某一个 ...
- Delphi中DLL的创建和使用(转)
Delphi中DLL的创建和使用 1.DLL简介: 2.调用DLL: 3.创建DLL: 4.两个技巧: 5.初始化: 6.例外处理. 1.DLL简介 ...
- [转]C#创建服务及使用程序自动安装服务,.NET创建一个即是可执行程序又是Windows服务的exe
写在前面 原文地址:C#创建服务及使用程序自动安装服务,.NET创建一个即是可执行程序又是Windows服务的exe 这篇文章躺在我的收藏夹中有很长一段时间了,今天闲着没事,就自己动手实践了一下.感觉 ...
- Spring工厂方式创建Bean实例
创建Bean实例的方式: 1) 通过构造器(有参或无参) 方式: <bean id="" class=""/> 2) 通过静态工厂方法 方式: &l ...
随机推荐
- React入门理解demo
1.React文档结构 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- jquery 实现图片上传,并在前端显示出来
目前遇到一个图片上上传的需求,突然发现,原来之前都没有做过此种类型的需求,以下是需求样式: 看到需求后之所以有点懵,是因为我接触到的文件上传,一般都是按钮类型的,例如以下这种: 深呼吸,好好想一下,整 ...
- iOS 注释
1) 参数的注释: UIButton *btnSend;/**< 发送按钮 */ 效果: 2) 方法的注释: type1(无参数): /** table 相关设置 */ -(void)confi ...
- IO流的Properties集合,序列化流与反序列化流,打印流及commons-IO
内容介绍 Properties集合 序列化流与反序列化流 打印流 commons-IO Properties类 Properties类介绍 Properties 类表示了一个持久的属性集.Proper ...
- 【vue】------ 路由创建 ------ 【William】
路由常用的配置项: path:路由请求的路径 component:路由匹配成功后需要渲染的组件或者页面 tag:改变组件内部渲染的元素 假设组件内部渲染的是a标签 tag="li" ...
- 如何使用Arrays工具类操作数组
介绍 我们要先知道Arrays 是什么. java.util.Arrays 类是 JDK 提供的一个工具类主要用来操作数组,比如数组的复制转换等各种方法,Arrays 的方法都是静态方法可以通过Arr ...
- Linux基础管道管理
一.I/O重定向 标准输入,标准输出,标准错误 file descriptors (FD, 文件描述符或Process I/O channels); 进程使用文件描述符来管理打开的文件 [root@l ...
- 第四章 文件的基本管理和XFS文件系统备份恢复 随堂笔记
第四章 文件的基本管理和XFS文件系统备份恢复 本节所讲内容: 4.1 Linux系统目录结构和相对/绝对路径. 4.2 创建/复制/删除文件,rm -rf / 意外事故 4.3 查看文件内容的命令 ...
- SpringBoot 集成Jedis操作set
题外话: Redis是个有趣的东西,相信搞java的或多或少都会用到,面试时也总离不开问Redis,之前觉得redis只是用做缓存,飞快!也因为最初在封装底层的时候,使用Redisson,所以大部分都 ...
- S3 Select for Java 使用记录
背景 后台基本使用 Amazon 的全家桶(EC2.DynamoDB.S3.Step Fuction 等等)构建.现在需要根据访问者的 IP 确定访问者的国家或地区. 已知: 访问者 IP 一个 ip ...