Delphi 实现软件自动升级的功能

Delphi 实现软件自动升级的功能

原理简单,在FTP上维护一个Update.ini文件,里面记录着要更新文件的版本号,本地也有一个Update.ini文件,每次启动更新程序时,先从FTP上下载Update.ini文件到本地名字为Update_new.ini,然后比较这两个文件,如果新的版本号大于旧的,或者新的文件在就ini中没有,这些就表示要更新的文件,然后逐一下载。

本程序名字为AutoUpdate,你生成这个exe,然后和主程序一起打包,创建桌面快捷方式时,指向AutoUpdate,而不是主程序。

在本地还有一个ini文件,比如叫ftp.ini吧,里面内容是

[coninfo]
main=Project1.exe
param={app}sayyes.pj2 -y bde.txt

main=Project1.exe:是主程序名称,和升级程序在同一目录

param={app}sayyes.pj2 -y bde.txt:这是命令行参数,app为当前路径,在程序中替换掉,传递给主程序(如果需要的话)

update.ini的内容格式如下

[root]

办事处查询.txt=20100519
[dbcard]
sayyes.pj2=20100519
FTP用户密码.txt=20100519

[root]代表根目录,后面的[dbcard]代表子目录,依次类推

unit Main; 

interface 

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, IdHTTP, IdBaseComponent, IdComponent, IdTCPConnection,
 IdTCPClient, IdFTP, ComCtrls, ExtCtrls,IniFiles,ShellAPI, jpeg; 

type
 TfrmMain = class(TForm)
  IdFTP1: TIdFTP;
  IdHTTP1: TIdHTTP;
  ProgressBar1: TProgressBar;
  GroupBox1: TGroupBox;
  ld_host: TLabeledEdit;
  ld_username: TLabeledEdit;
  ld_psw: TLabeledEdit;
  ld_port: TLabeledEdit;
  Label1: TLabel;
  cb_mode: TComboBox;
  ProgressBar2: TProgressBar;
  Label3: TLabel;
  list_file: TListView;
  Label4: TLabel;
  procedure IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;
   const AWorkCount: Integer);
  procedure IdFTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
  procedure FormCreate(Sender: TObject); private
  { Private declarations }
  FSize:Integer;
  FPath: string;
  FExePath: string;
  FInitPath: string;
  FIniFile:TIniFile;
  FHandle:HWND;
  FMainExe:string;
  FParam: string; 

  procedure CheckUpdateList;
  function ConnectFTP:Boolean;
  procedure DownLoadFile;
  procedure LoadIni;
  procedure SaveIni;
 public
  { Public declarations }
 end; 

var
 frmMain: TfrmMain; 

implementation
uses
 Flash;
{$R *.dfm}
//下载进度
procedure TfrmMain.IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;
 const AWorkCount: Integer);
begin
 ProgressBar1.Position := AWorkCount;
 Application.ProcessMessages;
end; 

procedure TfrmMain.IdFTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
begin
 ProgressBar1.Position := 0;
 ProgressBar2.StepBy(1);
end; 

procedure TfrmMain.FormCreate(Sender: TObject);
var
 frm: TfrmFlash;
begin
 Self.Visible := False;
 //闪屏,可以不加
 frm := TfrmFlash.Create(nil);
 frm.Show;
 Application.ProcessMessages;
 FExePath := ExtractFilePath(Application.ExeName);
 FIniFile := TIniFile.Create(FExePath+'ftp.ini');
 //加载ini信息,就是主机和端口之类的信息
 LoadIni;
 try
  ConnectFTP;
  CheckUpdateList;
  Self.Visible := True;
  Application.ProcessMessages;
  DownLoadFile;
 finally 

  FreeAndNil(frm);
  IdFTP1.Quit;
  FParam := StringReplace(FParam,'{app}',FExePath,[rfReplaceAll]);
//更新完毕后,启动主程序,并传入命令行参数
  ShellExecute(Handle,'open',PChar(FExePath+FMainExe),PChar(FParam),nil,SW_NORMAL);
  Application.Terminate;
 end;
end; 

//检查更新列表
procedure TfrmMain.CheckUpdateList;
var
 oldFile,newFile:TStringList;
 i,ver,index:Integer;
 itemstr,itempath: string;
 item:TListItem;
begin
 oldFile := TStringList.Create;
 newFile := TStringList.Create;
 try
  list_file.Clear;
  //先下载服务器上的update.ini文件,存到本地update_new.ini
  IdFTP1.Get('update.ini',FExePath+'update_new.ini',True);
  if FileExists(FExePath + 'update.ini') = False then Exit;
  oldFile.LoadFromFile(FExePath + 'update.ini');
  newFile.LoadFromFile(FExePath + 'update_new.ini');
  itempath := '';
  //下面开始比较两个list,如果newFile的版本号大于oldFile的版本号或者oldFile中没有的都表示要更新的
  for i := 0 to newFile.Count - 1 do
  begin
   itemstr := newFile.Strings[i];
   if itemstr = '' then Continue;
   if itemstr[1] = '[' then
   begin
    itempath := Copy(itemstr,2,Length(itemstr)-2);
    //如果是根目录
    if itempath = 'root' then
     itempath := '/';
    Continue;
   end;
   itemstr := newFile.Names[i];
   index := oldFile.IndexOfName(itemstr);
   if index = - 1 then
   begin
    item := list_file.Items.Add;
    item.Caption := itemstr;
    item.SubItems.Add(itempath)
   end
   else
   begin
    ver := StrToIntDef(newFile.Values[itemstr],0);
    if ver > StrToIntDef(oldFile.Values[itemstr],0) then
    begin
     item := list_file.Items.Add;
     item.Caption := itemstr;
     item.SubItems.Add(itempath);
    end;
   end;
  end;
  if list_file.Items.Count = 0 then Application.Terminate;
 finally
  oldFile.Free;
  newFile.Free;
 end;
end; 

function TfrmMain.ConnectFTP: Boolean;
begin
 Result := False;
 try
 IdFTP1.Host := ld_host.Text;
 IdFTP1.Port := StrToIntDef(ld_port.Text,21);
 IdFTP1.Username := ld_username.Text;
 IdFTP1.Password := ld_psw.Text;
 IdFTP1.Connect;
 IdFTP1.Passive := cb_mode.ItemIndex = 1;
 FInitPath := IdFTP1.RetrieveCurrentDir;
 Result := IdFTP1.Connected;
 except
  Result := False;
 end;
end; 

//下载文件更新
procedure TfrmMain.DownLoadFile;
var
 i:Integer;
 path:string;
 s1,s2:String;
begin
 ProgressBar2.Max := list_file.Items.Count;
 ProgressBar2.Position := 0;
 FIniFile.EraseSection('error');
 for i := 0 to list_file.Items.Count - 1 do
 begin
  Label4.Caption := '正在下载 '+list_file.Items[i].Caption;
  Application.ProcessMessages;
  IdFTP1.ChangeDir(FInitPath);
  path := list_file.Items[i].SubItems.Strings[0];
  if path <>'/' then
  begin
   IdFTP1.ChangeDir(path);
   ForceDirectories(FExePath+path);
   s1 := list_file.Items[i].Caption;
   s2 := FExePath+path+'/'+list_file.Items[i].Caption;
   IdFTP1.Get(s1,s2,True);
  end
  else
  begin
   s1 := list_file.Items[i].Caption;
   s2 := FExePath+'/'+list_file.Items[i].Caption;
   IdFTP1.Get(s1,s2,True);
   //记录失败项
   FIniFile.WriteString('error',list_file.Items[i].Caption,'成功');
  end;
  except
   //记录失败项
   FIniFile.WriteString('error',list_file.Items[i].Caption,'失败');
  end;
 end;
 Label4.Caption := '所有文件更新完毕!';
 DeleteFile(FExePath+'update.ini');
 CopyFile(PChar(FExePath+'update_new.ini'),PChar(FExePath+'update.ini'),False);
end; 

procedure TfrmMain.LoadIni;
begin
 ld_host.Text := FIniFile.ReadString('coninfo','host','******');
 ld_username.Text := FIniFile.ReadString('coninfo','user','******');
 ld_psw.Text := FIniFile.ReadString('coninfo','psw','******');
 ld_port.Text := FIniFile.ReadString('coninfo','port','21');
 cb_mode.ItemIndex := FIniFile.ReadInteger('coninfo','mode',1);
 FMainExe := FIniFile.ReadString('coninfo','main','Main.exe');
 FParam := FIniFile.ReadString('coninfo','param','');
end; 

procedure TfrmMain.SaveIni;
begin
 FIniFile.WriteString('coninfo','host',ld_host.Text);
 FIniFile.WriteString('coninfo','user',ld_username.Text);
 FIniFile.WriteString('coninfo','psw',ld_psw.Text);
 FIniFile.WriteString('coninfo','port',ld_port.Text);
 FIniFile.WriteInteger('coninfo','mode',cb_mode.ItemIndex);
end; 

end.

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Delphi实现窗体感知鼠标滑过并自动隐藏与显示窗口的方法

    本文实例讲述了Delphi实现窗体感知鼠标滑过并自动隐藏与显示窗口的方法.分享给大家供大家参考.具体实现方法如下: const WM_MouseEnter = $B013; WM_MouseLeave = $B014; type TfrmMain = class(TForm) . . Timer1: TTimer; procedure Timer1Timer(Sender: TObject); protected procedure WMMouseEnter(var Msg: TMessage)

  • Delphi 中内存映射对于大文件的使用

    Delphi 中内存映射对于大文件的使用 平时很少使用大文件的内存映射,碰巧遇到了这样的要求,所以把过程记录下来,当给各位一个引子吧,因为应用不算复杂,可能有考虑不到的地方,欢迎交流. 对于一些小文件,用普通的文件流就可以很好的解决,可是对于超大文件,比如2G或者更多,文件流就不行了,所以要使用API的内存映射的相关方法,即使是内存映射,也不能一次映射全部文件的大小,所以必须采取分块映射,每次处理一小部分. 先来看几个函数 CreateFile :打开文件 GetFileSize : 获取文件尺

  • Delphi XE5 为Android应用制作签名的方法(图文)

    要发布android应用,必须做签名的.看一下具体的操作步骤: 1.进入Project-Options: 2.打开Options窗口,选择Provisioning,在这里,可以为目标平台选择签名文件,也可生成新的签名文件. 2.1 选择目标平台,可以为dubug或release设置签名,默认情况下,debug签名文件是存在的,可不用设置,这也是我们建立一个新的Android项目,就可以不用签名就能在模拟器上跑的原因,真正发布时,是必须做签名的. 2.2,为发布做一个新的签名,选择Target为R

  • Delphi 用DLL实现插件的简单实例

    Delphi 用DLL实现插件的简单实例 这是DLL的代码 实现代码: library MyDll; uses SysUtils, Dialogs, Classes; procedure ShowInfo(info:PChar);stdcall; begin ShowMessage('您选择了['+info+']'); end; function GetCaption:Pchar; begin Result := '中国'; end; exports ShowInfo, GetCaption;

  • Delphi实现截屏存盘的方法

    本文实例讲述了Delphi实现截屏存盘的方法.分享给大家供大家参考.具体分析如下: 该实例可实现截取屏幕,并保存为JPEG文件格式的功能. procedure TForm1.ScreenCap(LeftPos,TopPos,RightPos,BottomPos:integer); var RectWidth,RectHeight:integer; SourceDC,DestDC,Bhandle:integer; Bitmap:TBitmap; MyJpeg: TJpegImage; Stream

  • ListView 百分比进度条(delphi版)

    在看代码之前先给大家附上效果图: 废话不多说了,直接给大家贴代码了. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ImgList; type TForm1 = class(TForm) btn1: TButton; lv1: TListView; trckbr1: TTrackBa

  • Delphi提取PDF文本实例

    生成PDF的控件很多,但解析的不是太多,pdf Toolkit可以,但测试的第一个复杂的pdf就报告错误,并且汉字乱码,可能使用的版本或使用方法不对. 想起之前使用java调用的Apache名下的pdfBox库很好用,于是就用下载了pdfBox,使用Delphi来调用pdfBox解析pdf文本. 环境要求:java运行环境 pdfBox应用包:pdfbox-app-2.0.6.jar 这里使用了DOS命令行来解析,然后调用解析结果. 首先是执行DOS命令: procedure CheckResu

  • Delphi 根据字符串找到函数并执行的实例

    Delphi 根据字符串找到函数并执行的实例  关键字:MethodAddress:取得方法的地址,这个方法需要是published的. 实例代码: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TShowInfo = procedure(info:string) of object; //声

  • Delphi 实现软件自动升级的功能

    Delphi 实现软件自动升级的功能 原理简单,在FTP上维护一个Update.ini文件,里面记录着要更新文件的版本号,本地也有一个Update.ini文件,每次启动更新程序时,先从FTP上下载Update.ini文件到本地名字为Update_new.ini,然后比较这两个文件,如果新的版本号大于旧的,或者新的文件在就ini中没有,这些就表示要更新的文件,然后逐一下载. 本程序名字为AutoUpdate,你生成这个exe,然后和主程序一起打包,创建桌面快捷方式时,指向AutoUpdate,而不

  • C#基于FTP协议的简易软件自动升级程序

    最近在重写了一个老的产品条码扫描程序,客户端数越有30个,因为经常有更新,C/S维护非常不方便,所以做一个自动更新程序特别有必要. 在网上随便找了找自动更新的方案,大多使用VS的发布/更新功能,不太喜欢此方案,觉得太麻烦,然后自己初步琢磨了一下如下方案. 现在比较喜欢的编程方式,先画图. 软件更新流程 安装包的制作 为了简单,采用了自解压压缩包的方式制作更新包,将整个新程序包打包为一个自解压压缩包. 以下是我的自解压包的参数设置,怎样制作自解压包网上有很多教程,可以自己去搜索. 常规-解压路径:

  • ASP 程序实现自动升级功能

    现在流行虚拟主机建站,我也有个网站,也算是个站长咯.当了近一年的站长,感到网站程序每次升级的时候颇为麻烦:先去官方看公告,然后下载升级包到本地,解压,FTP上传到虚拟主机.这些都是累人的体力活,加之本人又懒得很,所以异想天开的觉得要是程序能够自动升级就好了.所以就想了想,写了本文,希望对WEB程序开发者有帮助.这里只针对ASP,因为我只会ASP :-( 先看看传统的win32程序的升级过程(比如杀毒软件),它是依靠软件的升级程序通过网络连接到服务器分析并下载升级文件到本地. WEB程序有点不一样

  • 采用C#实现软件自动更新的方法

    本文实例分析了采用C#实现软件自动更新的方法,是非常实用的功能,值得学习和借鉴.具体如下: 1.问题概述: 长期以来,广大程序员为到底是使用Client/Server,还是使用Browser/Server结构争论不休,在这些争论当中,C/S结构的程序可 维护性差,布置困难,升级不方便,维护成本高就是一个相当重要的因素.有很多企业用户就是因为这个原因而放弃使用C/S.然而当一个应用必须要使用C/S 结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程

  • Electron实现应用打包、自动升级过程解析

    上次成功搭建了vue + electron的helloworld程序,这次将electron应用打包及自动升级的流程梳理了一下. 1. 应用打包 使用electron builder打包只需要在vue.config.js中配置即可,这里需要注意的是,默认情况下electron builder打包出来的安装程序是不能修改安装目录的,需要allowToChangeInstallationDirectory这个配置设置为true. // see https://cli.vuejs.org/config

  • c#使用FreeSql生产环境时自动升级备份数据库

    目录 项目场景: 解决方案: 概要描述: 详细说明: 总结: 项目场景: 使用FreeSql,包含所有的ORM数据库,都会存在这样的问题.在codefirst模式下,根据代码自动更新数据库,都建议不要在生产环境使用.为什么呢? 其实不建议使用,主要是根据代码自动生成数据时,极有可能会造成数据的丢失,比如修改字段类型,自动更新的结果可能并不是自己想的. 但是有一些使用场景是需要在生产环境自动升级的,比如 我们有一个CS客户端的产品,客户本地离线使用,客户本地部署,数据库也是本地数据库,版本从100

  • android实现软件自动更新的步骤

    本篇文章是直接下载最新的APK安装的方法,并不是增量下载该APk. 想要实现一个android应用,自动更新下载APK软件的方法,我采取的是以下几步方法: 1.每次进入主界面时,获取服务器的数据,看是否是最新版本,是,则无操作,否,则进行以下步骤: 2.弹出是否更新软件的对话框,点击下载后 3.弹出下载的进度条的对话框,开始下载,可以上随时点击按钮,停止下载 4.下载完成后,调用系统安装软件的服务,安装软件 效果图:     实现过程:   新建一个UpdateManager方法,具体内容我已经

  • 详解如何在低版本的Spring中快速实现类似自动配置的功能

    在 Spring 4 后才引入了 @Conditional 等条件注解,它是 Spring Boot 中实现自动配置的最大功臣! 那么问题来了:如果我们还在使用 Spring 3.x 的老版本,这时候要怎么实现一个自动配置呢? 需求和问题 核心的诉求 现存系统,不打算重构 Spring 版本为 3.x,也不打算升级版本和引入 Spring Boot 期望能够在少改代码的前提下实现功能增强 比如说: 希望能够给全站统一添加上日志记录(如:RPC 框架 Web 调用的摘要信息.数据库访问层的摘要信息

  • Python实现12306自动抢火车票功能

    目录 一.效果展示 二.代码详解 1 导入库 2 确定好购票基本信息 3 登录12306 4 模拟滑动滑块 5 处理疫情特殊要求 6 点击购票并填写出发地.目的地.出发时间 7 锁定车票 大家有没有这种感觉,一到国庆.春节这种长假,抢火车票就非常困难?各大互联网公司都推出抢票服务,只要加钱给服务费就可以增加抢到票的几率.有些火车票代售网点和一些加速买票软件,说你只要给100元服务费就可以优先帮忙抢到票.本文和你一起探索抢票软件背后的原理. 一.效果展示 在正式进入代码讲解之前,先来看下本文的实现

  • Android编程实现自动检测版本及自动升级的方法

    本文实例讲述了Android编程实现自动检测版本及自动升级的方法.分享给大家供大家参考,具体如下: 步骤: 1.检测当前版本的信息AndroidManifest.xml-->manifest-->android:versionName. 2.从服务器获取版本号(版本号存在于xml文件中)并与当前检测到的版本进行匹配,如果不匹配,提示用户进行升级,如果匹配则进入程序主界面. 3.当提示用户进行版本升级时,如果用户点击了确定,系统将自动从服务器上下载并进行自动升级,如果点击取消将进入程序主界面.

随机推荐