• 快速制作通用LiveUpdate程序


    很多朋友开发好程序,又需要时间去开发升级模块,比较麻烦,我在这里给出一个通用升级工具的解决方法。

    首先,我们考虑下对这个升级程序或模块的要求,主要是通用性和便捷性这两点;在这里,我忽然想到了网络游戏的更新程序,发现它非常不错,我们可以像它一样,由主程序调用独立的LiveUpdate程序,对自己进行升级,这样就解决了通用性的问题,具体如何做呢?我们可以利用EXE文件参数的方法来实现,也就是给程序添加运行参数。

    功能描述:通过参数和配置文件的形式,实现文件更新,采用HTTP协议,可方便的集成到软件中或用于文件升级。
    缺点描述:配置时需要手工设置,不是断点续传,单线程。
    特别说明:程序会自动开户下载任务,没有设置自动关闭的,可在下载后手工再点更新键下载一次。
    参数描述:LiveUpdate 配置文件地址 是否自动关闭 需要执行的文件(只支持一个文件)
    具体例子:

    自动下载、关闭、启动|LiveUpdate http://localhost/outcall/liveupdate.ini 1 c:\smallarmy.exe
    自动下载、关闭
    |LiveUpdate http://localhost/outcall/liveupdate.ini 1
    自动下载
    |LiveUpdate http://localhost/outcall/liveupdate.ini

    配置文件:注意FileTime这个项目,必须是yyyy-MM-dd hh:mm:ss,升级时只比较到秒的十位,个位不比较。

    [Update]
    ;需要更新的文件数 后面需要配套
    Count
    =2
    ;文件名
    File1
    =picturepartner.rar
    ;下载地址
    FileUrl1
    =http://esin.onlinedown.net/down/picturepartner.rar
    ;覆盖路径
    FilePath1
    =$AppPath
    ;文件版本号
    FileVer1
    =88.88.88.8888
    ;更新时间,升级以这个为准,时间由您设置,升级后会强制更新文件的时间为以下时间
    FileTime1
    =2010-10-21 12:12:33

    File2
    =Smallarmy.exe
    FileUrl2
    =http://sq.onlinedown.net/down/Smallarmy.exe
    FilePath2
    =$AppPath
    FileVer2
    =1.0.0.0
    FileTime2
    =2010-10-11 12:12:33

    LiveUpdate开发过程:

        首先找一些图片和图标资源,主要是与下载有关的即可;然后在Delphi中新建一个工程,在窗口上添加一个ListView用来显示下载项,两个ProgressBar用来显示总进度和下载项进度;由于考虑的是http方式,这个方式也比较方便,只需找个web空间就行,所以,在Delphi中,我们采用自带的indy组件包中的idHttp组件;在窗口中添加IdHttp和IdAntiFreeze各一个;IdHttp组件,用到两个事项,分别是WorkBegin和Work,主要是处理进程条的显示,代码如下:

    procedure TfrmMain.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
    AWorkCount: Int64);
    begin
    ProgressBar1.Position :
    = ProgressBar1.Position + AWorkCount;
    Application.ProcessMessages;
    end;

    procedure TfrmMain.IdHTTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
    AWorkCountMax: Int64);
    begin
    ProgressBar1.Max :
    = AWorkCountMax;
    ProgressBar1.Min :
    = 0;
    ProgressBar1.Position :
    = 0;
    end;

    在listview上,我们添加几列内容,分别是图标列、文件、版本、日期、地址、路径,分别调整下宽度,后面地址和路径两列宽度为0,进行隐藏,这是用来保存下载项的放置目标地址和下载地址的;接下去我贴上主要的处理代码:

    格式化文件修改日期的函数:

    type
    TFileTimeType
    = (fttCreation, fttLastAccess, fttLastWrite);

    function SetFileDateTime(const FileName: string; FileTimeType: TFileTimeType;
    DateTime: TDateTime): integer;
    var
    Handle : THandle;
    LocalFileTime, FileTime: TFileTime;
    DosDateTime : integer;
    I : TFileTimeType;
    FileTimes :
    array[TFileTimeType] of Pointer;
    begin
    Result :
    = 0;
    DosDateTime :
    = DateTimeToFileDate(DateTime);
    Handle :
    = FileOpen(FileName, fmOpenWrite or fmShareDenyNone);
    if Handle <> INVALID_HANDLE_VALUE then
    try
    for I := fttCreation to fttLastWrite do
    FileTimes[I] :
    = nil;
    DosDateTimeToFileTime(LongRec(DosDateTime).Hi, LongRec(DosDateTime).Lo,
    LocalFileTime);
    LocalFileTimeToFileTime(LocalFileTime, FileTime);
    FileTimes[FileTimeType] :
    = @FileTime;
    if SetFileTime(Handle, FileTimes[fttCreation], FileTimes[fttLastAccess],
    FileTimes[fttLastWrite])
    then
    Exit;
    finally
    FileClose(Handle);
    end;
    Result :
    = GetLastError;
    end;

    下载处理代码:

    procedure TfrmMain.BitBtn1Click(Sender: TObject);
    var
    vStream : TMemoryStream;
    vIni : TIniFile;
    vSF, vS :
    string;
    I, vI : integer;
    vList : TListItem;
    vDown : Boolean;
    begin
    BitBtn1.Enabled :
    = False;
    IdAntiFreeze1.OnlyWhenIdle :
    = False; //设置使程序有反应.
    vSF :
    = ParamStr(1); //第一个参数必须是配置文件的地址
    vStream :
    = TMemoryStream.Create;
    try
    try
    IdHTTP1.Get(vSF, vStream);
    //取升级配置,由参数传进
    except
    Application.MessageBox(
    '网络错误!无法获取升级配置文件。', '', MB_OK +
    MB_ICONSTOP);
    Exit;
    end;
    vSF :
    = ExtractFilePath(ParamStr(0)) + 'LiveUpdate.ini';
    vStream.SaveToFile(vSF);
    vIni :
    = TIniFile.Create(vSF);
    try
    vI :
    = vIni.ReadInteger('Update', 'Count', 0);
    if vI = 0 then
    begin
    Application.MessageBox(
    '没有可升级的文件!', '', MB_OK +
    MB_ICONINFORMATION);
    Application.Terminate;
    Exit;
    end;
    ListView1.Clear;
    for I := 1 to vI do
    begin
    vList :
    = ListView1.Items.Add;
    vList.ImageIndex :
    = 0;
    vList.SubItems.Add(vIni.ReadString(
    'Update', 'File' + inttostr(I), ''));
    vList.SubItems.Add(
    vIni.ReadString(
    'Update', 'FileVer' + inttostr(I), ''));
    vList.SubItems.Add(
    vIni.ReadString(
    'Update', 'FileTime' + inttostr(I), ''));
    vList.SubItems.Add(
    vIni.ReadString(
    'Update', 'FileUrl' + inttostr(I), ''));
    vS :
    = vIni.ReadString('Update', 'FilePath' + inttostr(I), '');
    if StrUtils.ContainsText(vS, '$AppPath') then
    vS :
    = StringReplace(vS, '$AppPath', ExtractFilePath(ParamStr(0)),
    [rfReplaceAll]);
    //其实,用相对路径的方式也能实现一样的效果
    vList.SubItems.Add(vS);
    end;
    ProgressBar1.Position :
    = 0;
    ProgressBar2.Position :
    = 0;
    ProgressBar2.Max :
    = ListView1.Items.Count;
    for I := 0 to ListView1.Items.Count - 1 do
    begin
    vStream.Clear;
    try
    vS :
    = ListView1.Items.Item[I].SubItems.Strings[4]
    + ListView1.Items.Item[I].SubItems.Strings[0];
    if fileexists(vS) then //如果文件存在,则进行校验
    begin //只比较到秒的十位,秒的个位不比较
    vDown :
    = Copy(FormatDateTime('yyyy-MM-dd hh:mm:ss',
    FileDateToDateTime(FileAge(vS))),
    1, 18)
    <> Copy(ListView1.Items.Item[I].SubItems.Strings[2], 1, 18);
    end
    else
    vDown :
    = True;
    if vDown then
    begin
    ListView1.Items.Item[I].ImageIndex :
    = 3;
    IdHTTP1.Get(ListView1.Items.Item[I].SubItems.Strings[
    3], vStream);
    ListView1.Items.Item[I].ImageIndex :
    = 4;
    Application.ProcessMessages;
    vStream.SaveToFile(vS);
    SetFileDateTime(vS, fttLastWrite,
    StrToDateTime(ListView1.Items.Item[I].SubItems.Strings[
    2]));
    end;
    ListView1.Items.Item[I].ImageIndex :
    = 1;
    except //INDY控件一般要使用这种try..except结构.
    ListView1.Items.Item[I].ImageIndex :
    = 2;
    end;
    ProgressBar2.Position :
    = I + 1;
    vEnd :
    = True;
    end;
    finally
    FreeAndNil(vIni);
    end;
    finally
    vStream.Free;
    BitBtn1.Enabled :
    = True;
    DeleteFile(vSF);
    end;
    end;

    其他关于界面美化什么的,不再描述。完成后,就可以直接在各个项目中引用它,而无需每个项目都去开发升级程序或模块了。

  • 相关阅读:
    堆与堆排序
    利用openssl进行RSA加密解密
    [转载]编辑器圣战
    七月底的小结
    计算机是怎么样工作的?
    Linux进程地址空间之初探:一
    微软2013暑期实习笔试回忆
    微软编程之美资格赛
    微软编程之美初赛
    rootkit:实现隐藏进程
  • 原文地址:https://www.cnblogs.com/star5/p/liveupdate.html
Copyright © 2020-2023  润新知