在写C/S结构程序时往往会出现一些升级,因而又要重新编译程序生成新的EXE,但是这样去覆盖每台机器上之前的EXE文件确实太麻烦。我知道有一种方法可以让软件从数据库里自动加载最近EXE,但不知道怎么写,或者另有其他方法解决此问题也可以。最好是之前这种方法。代码和步骤尽量详细一点,解决后另开贴送200分。谢谢。来说废话的就不要说了。

解决方案 »

  1.   

    一般不会把exe写到数据库里这么麻烦.很多采用独立的exe进程从http下载然后杀死自身进程启动安装或更新bat并加载新版本.
    qq则采用一个独立的后来进程做这些操作(txplatform.exe)但更新也是独立的一个exe.判断版本的话也是从web的inf或相关配置文件来检查对比本地版本.
    有个东西你可以使用或参考.AutoUpgraderPro
      

  2.   

    楼上讲得不错,很少人会把exe写到数据库里,你可以把版本号写到某个表里,软件连上网络时进行判断,如果本地的版本号和网络上的版本号不一致则进行升级
      

  3.   

    手头上有个项目刚好就是用这种方式来升级的。
    我是这么做的:
    建表,有三个字段,文件名、版本号、文件内容。版本可以用时间,即更新的时间,文件内容用Blob字段。
    做一个UpLoad程序,维护这个表,就是增删改,软件维护者将DLL、EXE等要升级的文件信息写到这个表里
    Update升级程序,先检测注册表里是否有新版本,有就从那个表里读取Blob字段,下载覆盖掉需要升级的文件,完了之后写注册表,更新版本号
    项目的执行程序,启动时检测注册表,有新版本就调用Update程序,关闭自身。这样只要连上数据库就可以升级,速度是很快的。
      

  4.   


    注册表操作使用TRegistry类,常用方法OpenKey、ReadString、WriteString等 实际上版本号也不一定要放在注册表啊,用配置文件也是可以的
    INI文件使用TIniFile进行操作,常用方法也有ReadXXX,WriteXXX方法
      

  5.   

    使用loader.exe启动主程序,loader启动后,首先检测更新,无更新则启动主程序,有更新则下载
      

  6.   

    如果程序不大,最简单的方法是md5一个文件,然后值保存在一个.ini文件中。客户端执行的时候,可以先采用楼上的方式检查本地.ini中的md5值,若不同,则自动更新,且更新.ini文件。这样最省心了。也不用顾虑版本号。
      

  7.   


    我们的做法和“老之”的类似,有一个专门的升级程序,启动客户端时先启动升级程序,从服务器端数据库中进行检索,生成一个XML,然后下载XML,分析,下载文件,更新数据库(如果需要的话),下载完成,启动客户端
      

  8.   

    根据你的网路环境决定下载方式。
    1. 如果是局域网或不用考虑带宽的
       简单办法:服务端开个共享目录每次将新程序放到那个目录里,自己程序中要增加一段比对版本号的代码,和一个升级下载的可执行文件。
       客户端程序启动后,执行版本号检测代码,如果有新的版本,运行升级下载的那个可执行文件,关闭掉已经启动的客户端程序,下载到一个临时目录,下载正常完成后拷贝到执行目录。2. 如果网路带宽有限而且慢速,就要用http,tcp,udp了
       用这种方法比较好,自己可以花时间写个通用的,以后copy就OK了
       1.服务端要建立一个文件更新列表(包括可执行文件的版本和其他动态链接库等),服务端最好写读取列表的程序。
       2.客户端程序跟前面一样需要两部分,一是客户端程序,二是升级程序方法跟前面一样。
       3.无论你用http,还是tcp或udp都要先获得更新列表,跟现有文件或本地列表进行比较。
         获取列表的方法很多,http比较简单些服务端可以不写代码,在IIS等web server 上建立一个虚拟目录,从上面下载就可以了;
         TCP和UDP服务端需要写个读取列表的程序,自己可以定义一个格式。
         剩下的就属于文件传输了。
         网上有很多 http,tcp,udp文件传输的例子(注:udp要根据mtu的大小进行分包)
      

  9.   

    学到东西了,谢谢各位。我去试试用INI文件的方法。
      

  10.   

    将版本号存储在数据库中,每次打开程序时比较以下版本号,需要升级时,
    给个提示自动关闭该程序,同时shellexecute调用update.exe从服务器
    下载新文件覆盖原来的.然后在shellexecute现在的系统.
      

  11.   

    建议去盒子网找点相关代码...然后再自己改改就成了...
    http://www.2ccc.com/article.asp?articleid=4142
      

  12.   

    //delphi 7 MD5;
    uses
      IdHashMessageDigest, IdHash;var
      md5: TIdHashMessageDigest5;
      longWordRec: T4x4LongWordRecord;
      fs: TFileStream;
      
    begin
      ...
      md5 := TIdHashMessageDigest5.Create;
      fs := TFileStream.Create('C:\INSTALL.LOG', 0) ;
      longWordRec := md5.HashValue(fs);
      ShowMessage(md5.AsHex(longWordRec)); //该值可以存放到指定位置;
      FreeAndNil(md5) ;
      ...
    end;//=====================================================//
    比较可以通过网络或者特定位置读取一个MD5值,若不同,则下载更新。
    还是喜欢采用8楼的loader.exe的方式启动程序,维护简单。
      

  13.   

    //以下代码从局域网内的服务器中指定的共享目录下载最新版本的程序
    //在客户端每次运行的时候就
    //检测一下服务器的共享目录下的程序与当前的程序比较(比较程序的文件版本号),
    //若发现比自己的版本高的话则自动下载并替换自身的程序。
    //主程序运行的时候在 onShow事件调用以下过程procedure TMainForm._IsNewVersion;
    var
      UpDateFileVersion:string;
    begin
      //1。首先获取GetVersionString当前软件的文件版本号,
      MainForm.MyCurVersion:=GetVersionString(Application.ExeName);  if MainForm.IsAutoUpdate then //自动检测新版本
      begin
        //2。检测数据库是否设置了软件升级文件名,如果有,继续第3步
        if fileexists(MainForm.UpdateFileName)=false then
        begin
           Application.MessageBox(#13+'软件自动升级失败! '+#13+#13+'    原因是无法访问服务器上所设置的升级程序['+MainForm.UpdateFileName+']'+#13+#13+'请确认该升级程序是否存在或者尝试您的电脑是否有权限访问该升级文件!');
          exit;
        end;
            //3。检测软件升级文件的文件版本号,如果不一致,继续第4步
        UpdateFileVersion:=GetVersionString(MainForm.UpdateFileName);
        if f_CheckIsNewVersion(MyCurVersion,UpdateFileVersion) then
        begin
          //启动升级程序
          if fileexists(ExtractFilePath(Application.ExeName)+'\UpdateProgram.exe')=false then
          begin
            showmessage('在当前软件的安装目录下找不到升级程序UpdateProgram.exe,请确认!');
            exit;
          end; 
          //调用另一个小程序用来下载最新版本的程序
          WinExec(pchar(ExtractFilePath(Application.ExeName)+'\UpdateProgram.exe'),SW_SHOW);
          //结束程序
          application.Terminate;
        end; 
      end;
    end;
    function GetVersionString(FileName: string): string;
    var
      VerInfoSize: DWORD;
      VerInfo: Pointer;
      VerValueSize: DWORD;
      Dummy: DWORD;
      VerValue: PVSFixedFileInfo;
    begin
      Result := '';
      VerInfoSize := GetFileVersionInfoSize(PChar(FileName), Dummy);
      if VerInfoSize = 0 then Exit;  GetMem(VerInfo, VerInfoSize);
      GetFileVersionInfo(PChar(FileName), 0, VerInfoSize, VerInfo);
      VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
      Result := IntToStr(VerValue^.dwFileVersionMS shr 16) + '.' +
      IntToStr(VerValue^.dwFileVersionMS and $FFFF) + '.' +
      IntToStr(VerValue^.dwFileVersionLS shr 16) + '.' +
      IntToStr(VerValue^.dwFileVersionLS and $FFFF);
      FreeMem(VerInfo);
    end;{
     比较两个版本,如果CurVersion<ServerVersion 则返回True ,否则返回False;
     版本号的格式是:2008(年份).5(月份).31(日期).2(编译号)
    }
    function f_CheckIsNewVersion(CurVersion,ServerVersion:string):boolean;
    var
      i,j,IntTemp1,IntTemp2:integer;
      strTemp1,strTemp2,Tmp1,Tmp2:string;
    begin
      Result:=false;  Tmp1:=CurVersion;
      Tmp2:=ServerVersion;  Try
      //比较年份
      StrTemp1:=copy(Tmp1,1,4);
      IntTemp1:=StrToInt(StrTemp1);
      StrTemp2:=copy(Tmp2,1,4);
      IntTemp2:=StrToInt(StrTemp2);
      if IntTemp1<IntTemp2 then
        result:=True
      else
      begin
        if IntTemp1=IntTemp2 then
        begin
          //比较月份   版本号的格式是:2008(年份).5(月份).31(日期).2(编译号)
          i:=pos('.',Tmp1);
          Tmp1:=copy(Tmp1,i+1,10);
          j:=pos('.',Tmp1);
          StrTemp1:=copy(Tmp1,1,j-1);
          IntTemp1:=StrToInt(StrTemp1);
          i:=pos('.',Tmp2);
          Tmp2:=copy(Tmp2,i+1,10);
          j:=pos('.',Tmp2);
          StrTemp2:=copy(Tmp2,1,j-1);
          IntTemp2:=StrToInt(StrTemp2);      if IntTemp1<IntTemp2 then
            result:=True
          else
          begin  //月份比较完毕
            if IntTemp1=IntTemp2 then
            begin
              //开始比较日期   版本号的格式是: 5(月份).31(日期).2(编译号)
              i:=pos('.',Tmp1);
              Tmp1:=copy(Tmp1,i+1,10);
              i:=pos('.',Tmp1);
              StrTemp1:=copy(Tmp1,1,i-1);
              IntTemp1:=StrToInt(StrTemp1);
              i:=pos('.',Tmp2);
              Tmp2:=copy(Tmp2,i+1,10);
              i:=pos('.',Tmp2);
              StrTemp2:=copy(Tmp2,1,i-1);
              IntTemp2:=StrToInt(StrTemp2);
              if IntTemp1<IntTemp2 then     //比较日期
                result:=True
              else
              begin
                if IntTemp1=IntTemp2 then
                begin
                  //开始比较编译号 版本号的格式是: 31(日期).2(编译号)
                  i:=pos('.',Tmp1);
                  Tmp1:=copy(Tmp1,i+1,10);
                  StrTemp1:=trim(Tmp1);
                  IntTemp1:=StrToInt(StrTemp1);              i:=pos('.',Tmp2);
                  Tmp2:=copy(Tmp2,i+1,10);
                  StrTemp2:=trim(Tmp2); 
                  IntTemp2:=StrToInt(StrTemp2);              if IntTemp1<IntTemp2 then
                    Result:=true
                  else
                    Result:=false;
                end
              end
            end
          end
        end
      end;
      Except
        result:=false;
      end;
    end;
    //程序 UpdateProgram.exe 里放一个Timer执行以下代码既可
    //exeName 是主程序的文件名,如QQ的程序文件名为: "QQ.exe"
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      try
        if fileexists(pchar(ExtractFilePath(application.ExeName)+'\'+ExeFileName)) then
          deletefile(pchar(ExtractFilePath(application.ExeName)+'\'+ExeFileName));    copyfileto(pchar(UpdateFileName),pchar(ExtractFilePath(application.ExeName)+'\'+ExeFileName));    Timer1.Enabled:=false;
         
        //复制完成后自启动主程序
        WinExec(pchar(application.ExeName)+'\'+ExeFileName),SW_SHOW);
        Application.Terminate;
      except
        Timer1.Enabled:=false;
        showmessage('升级失败!');
      end;
      Timer1.Enabled:=false;
      Application.Terminate;
    end;