实现软件自动升级

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bdmh/archive/2011/01/06/6120459.aspx

原理简单,在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.  
posted @ 2011-02-10 16:32  kaka9  阅读(539)  评论(0编辑  收藏  举报