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

发布时间 - 2026-01-11 03:05:37    点击率:

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. 

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


# Delphi  # 实现软件自动升级的功能  # 软件的升级功能  # Delphi 用DLL实现插件的简单实例  # Delphi 根据字符串找到函数并执行的实例  # Delphi 中内存映射对于大文件的使用  # Delphi提取PDF文本实例  # Delphi XE5 为Android应用制作签名的方法(图文)  # ListView 百分比进度条(delphi版)  # Delphi实现截屏存盘的方法  # Delphi实现窗体感知鼠标滑过并自动隐藏与显示窗口的方法  # 主程序  # 命令行  # 这是  # 也有  # 如有  # 这两个  # 希望能  # 还有一个  # 谢谢大家  # 不加  # 快捷方式  # 而不是  # 升级程序  # 自动升级  # 疑问请  # 器上  # 加载  # 完毕后  # 在同一  # string 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  iOS UIView常见属性方法小结  如何在 React 中条件性地遍历数组并渲染元素  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制  PHP 500报错的快速解决方法  EditPlus 正则表达式 实战(3)  简单实现jsp分页  Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例  如何构建满足综合性能需求的优质建站方案?  lovemo网页版地址 lovemo官网手机登录  怎样使用JSON进行数据交换_它有什么限制  如何快速建站并高效导出源代码?  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  如何快速搭建高效服务器建站系统?  实现点击下箭头变上箭头来回切换的两种方法【推荐】  如何在宝塔面板中修改默认建站目录?  如何正确选择百度移动适配建站域名?  Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门  什么是JavaScript解构赋值_解构赋值有哪些实用技巧  Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】  如何在搬瓦工VPS快速搭建网站?  深圳网站制作的公司有哪些,dido官方网站?  如何快速打造个性化非模板自助建站?  百度浏览器网页无法复制文字怎么办 百度浏览器复制修复  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  如何用AWS免费套餐快速搭建高效网站?  如何确保FTP站点访问权限与数据传输安全?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  三星、SK海力士获美批准:可向中国出口芯片制造设备  中国移动官方网站首页入口 中国移动官网网页登录  如何快速搭建高效WAP手机网站?  个人摄影网站制作流程,摄影爱好者都去什么网站?  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤  七夕网站制作视频,七夕大促活动怎么报名?  北京网站制作公司哪家好一点,北京租房网站有哪些?  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  ,南京靠谱的征婚网站?  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  5种Android数据存储方式汇总  Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程  Laravel怎么连接多个数据库_Laravel多数据库连接配置  *服务器网站为何频现安全漏洞?  Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】  免费视频制作网站,更新又快又好的免费电影网站?  原生JS获取元素集合的子元素宽度实例  如何在阿里云部署织梦网站?