Delphi如何实现软件自动更新源代码

关键技术是获取版本号功能和批处理删除自身的功能 unit UnitUpG;interfaceuses Forms, Windows, SysUtil

 

关键技术是获取版本号功能和批处理删除自身的功能

unit UnitUpG;

interface

uses
  Forms,
  Windows,
  SysUtils,
  Classes,
  Controls,
  URLMON,
  SHellAPi,
  iniFiles,
  Tlhelp32;
  procedure UpGrade;
  procedure KillExe;
var
  SName:String;
  UpGradeB:Boolean;
type
  TLANGANDCODEPAGE=record
    wLanguage,wCodePage:Word;
end;
  PLANGANDCODEPAGE=^TLANGANDCODEPAGE;

type
  TUpDateThread=class(TThread)
  protected
    procedure Execute;override;
  end;

implementation

uses UNIT1;

function ShowVersion:String;
var
  VerInfo:PChar;
  lpTranslate:PLANGANDCODEPAGE;
  FileName:String;
  VerInfoSize,cbTranslate:DWORD;
  VerValueSize:DWORD;
  Data:String;

  VerFileV:PChar;
  lpFileVersion:string;
begin
  Result:='0.0.0.0';
  FileName:=Application.ExeName;
  VerInfoSize:=GetFileVersionInfoSize(PChar(FileName),VerInfoSize);
  if VerInfoSize>0 then
  begin
    VerInfo:=AllocMem(VerInfoSize);

    GetFileVersionInfo(PChar(FileName),0,VerInfoSize,VerInfo);

    VerQueryValue(VerInfo, PChar('\VarFileInfo\Translation'), Pointer(lpTranslate),cbTranslate);

    if cbTranslate<>0  then
    begin
      Data := format('\StringFileInfo\%.4x%.4x\FileVersion',[lpTranslate^.wLanguage,lpTranslate^.wCodePage]);

      VerQueryValue(VerInfo, PAnsiChar(data),Pointer(VerFileV), VerValueSize);
      if VerValueSize <> 0 then
      begin
        SetString(lpFileVersion,VerFileV,VerValueSize-1);
        Result:=lpFileVersion;
      end;
    end;
    FreeMem(VerInfo,VerInfoSize);
  end
  else begin
    Result:='0.0.0.0';
    Application.MessageBox('获取文件版本信息时遇到致命错误,请重新打开软件。','错误',MB_OK+MB_ICONSTOP);
    Application.Terminate;
  end;
end;


function KillTask(ExeFileName:string):integer;
const
  PROCESS_TERMINATE = $0001;
var
  ContinueLoop: BOOLean;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  Result :=0;
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  while Integer(ContinueLoop) <> 0 do
  begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
      UpperCase(ExeFileName))) then
      Result := Integer(TerminateProcess(OpenProcess(PROCESS_TERMINATE,BOOL(0),
        FProcessEntry32.th32ProcessID),0));
      ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;

procedure TUpDateThread.Execute;
var
  FindUD:Boolean;
  inifile:TiniFile;
  i,Num:integer;
  DownFile,FSaveFile:String;
  Name,Path,CliVersion,SerVersion:String;
begin

  FindUD:=False;
  inifile:=TiniFile.Create(ExtractFilePath(Application.ExeName)+'UpDate.ini');
  Num:=StrToInt(inifile.ReadString('Program Number','Num',''));
  for i:=1 to Num do
  begin
    Name:=inifile.ReadString('session'+inttostr(i),'Name','');
    Path:=inifile.ReadString('session'+inttostr(i),'Path','');
    SerVersion:=inifile.ReadString('session'+inttostr(i),'Version','');
    CliVersion:=ShowVersion;

    if (Name=ExtractFileName(Application.ExeName)) and (CliVersion<>SerVersion) then
    begin
      FindUD:=True;
      DownFile:=Path+Name;
      SName:=DownFile;
      FSaveFile:=Application.ExeName;
      break;
    end;
  end;

  try
    DeleteFile(ExtractFilePath(Application.ExeName)+Name+'.old');
  except
    On E:Exception do
      Application.MessageBox('删除旧版本失败!','Error',MB_OK);
  end;

  if  FindUD then
  begin
    if Application.MessageBox('发现一个新版本的软件,是否更新软件?','软件更新',MB_OKCancel)=mrOK then
    begin
      if Application.MessageBox('请选择更新软件的时间!现在更新点''yes'',关闭软件时更新点''No''','软件更新',MB_YESNO)=mrYes then
      begin
        Application.MessageBox('软件更新期间请停止对软件的操作,更新成功会自动重新打开程序!','软件更新',MB_OK);
        Application.ProcessMessages;
        Screen.Cursor:=crHourGlass;
        
        try
          ReNameFile(FSaveFile,FSaveFile+'.old');
        except
          On E:Exception do
            Application.MessageBox('拷贝文件副本失败!','Error',MB_OK);
        end;

        try
          URLDownloadToFile(nil,PAnsiChar(DownFile),PAnsiChar(FSaveFile),0,nil);

          ShellExecute(0, 'open', PChar(Name),PChar(ExtractFilePath(Application.ExeName)), nil, SW_SHOWNORMAL);
          KillTask(ExtractFileName(Application.ExeName));

        except
          On E:Exception do
          begin
            ReNameFile(FSaveFile+'.old',FSaveFile);
            Application.MessageBox('下载失败!','Error',MB_OK);
            Screen.Cursor:=crDefault;
          end;
        end;
      end
      else begin
        UpGradeB:=True;
      end;
    end;
  end;
  iniFile.Free;
end;

procedure KillExe;
var
   BatchFile: TextFile;
   BatchFileName: string;
   ProcessInfo: TProcessInformation;
   StartUpInfo: TStartupInfo;
begin
   BatchFileName := ExtractFilePath(ParamStr(0)) + '_KillExe.bat';
   AssignFile(BatchFile, BatchFileName);
   Rewrite(BatchFile);

   Writeln(BatchFile, 'del "' + ParamStr(0) + '.old"');
   Writeln(BatchFile,
     'if exist "' + ParamStr(0) + '.old"' + ' goto try');
   Writeln(BatchFile, 'del %0');
   CloseFile(BatchFile);

   FillChar(StartUpInfo, SizeOf(StartUpInfo), $00);
   StartUpInfo.dwFlags := STARTF_USESHOWWINDOW;
   StartUpInfo.wShowWindow := SW_HIDE;
   if CreateProcess(nil, PChar(BatchFileName), nil, nil,
     False, IDLE_PRIORITY_CLASS, nil, nil, StartUpInfo,
     ProcessInfo) then
   begin
     CloseHandle(ProcessInfo.hThread);
     CloseHandle(ProcessInfo.hProcess);
   end;
end;

procedure UpGrade;
var
  FSaveFile,DownFile:String;
begin
  if UpGradeB then
  begin
    DownFile:=SName;
    FSaveFile:=Application.ExeName;
    Application.MessageBox('软件更新期间请停止对软件的操作!','软件更新',mb_OK);
    Application.ProcessMessages;
    Screen.Cursor:=crHourGlass;
    try
      DeleteFile(FSaveFile+'.old');
    except
      On E:Exception do
        Application.MessageBox('删除旧软件失败!','软件更新',mb_OK);
    end;

    try
      ReNameFile(FSaveFile,FSaveFile+'.old');
    except
      On E:Exception do
        Application.MessageBox('拷贝文件副本失败!','Error',mb_OK);
    end;

    try
      URLDownloadToFile(nil,PAnsiChar(DownFile),PAnsiChar(FSaveFile),0,nil);
      Screen.Cursor:=crdefault;

      Application.MessageBox('软件更新成功!','软件更新',mb_OK);
    except
      On E:Exception do
      begin
        ReNameFile(FSaveFile+'.old',FSaveFile);
        Application.MessageBox('更新软件失败,原软件将恢复!','Error',mb_OK);
      end;
    end;

    try
      KillExe;
    except
      On E:Exception do
      begin
        Application.MessageBox('删除旧软件失败!','Error',mb_OK);
      end;
    end;
  end;
end;


end.