📜 ⬆️ ⬇️

Auto-update program through MSSQL server

In order not to run on their work to each person who uses my program it is reasonable to make an auto-update, which will update the program if you upload a new version to the server. Having tried many ways, I found the easiest to use (although not the most correct)
So the algorithm:
  1. When turned on, the program checks the latest version on the server.
  2. If on the server above the current one, then download the Zip-archive with the program.
  3. We rename the application file to another (for the sake of backup and accessibility to the file), for example from program.exe to program.backup.
  4. Unpack the archive by replacing the files in the folder.
  5. Delete the archive with the update.
  6. Restart the program.


But before all this, we first create the Updater table (for example) in MSSQL with fields:
name - the varchar type;
version — type varchar;
files - type varbinary (max) (or any other blob-field).
It is better to immediately create a record in the table, where program will be in the name field.
Add this procedure to the code to extract the program version number:
function TForm1.GetMyVersion: string; type TVerInfo=packed record Nevazhno: array[0..47] of byte; //   48  Minor,Major,Build,Release: word; //    end; var s:TResourceStream; v:TVerInfo; begin result:=''; try s:=TResourceStream.Create(HInstance,'#1',RT_VERSION); //   if s.Size>0 then begin s.Read(v,SizeOf(v)); //     result:=IntToStr(v.Major)+IntToStr(v.Minor)+ //   ... IntToStr(v.Release)+IntToStr(v.Build); end; s.Free; except; end; end; 

Now we need a library to unpack the archives, because I will store the update in a zip archive, use the SevenZip library, add the path to the library sources in Delphi in the library.
Now we need to download the archive itself with the new version of the program into the database. I made a form with downloading updates to the server:
image
On opening OpenDialog I think everything is clear, we rewrite the path to edit
 if OpenDialog1.Execute then cxButtonEdit1.Text:=OpenDialog1.FileName; 


The version number is best entered in MaskEdit with a mask - ! 9.9.9.0; 1; _
Click the save button to upload the file with the procedure:
 var blobF: TBlobField; begin if not FileExists(OpenDialog1.FileName) then begin ShowMessage('  !'); exit; end else cxButtonEdit1.Text:=OpenDialog1.FileName; try ADOTable1.TableName:=Updater; //       ADOTable1.Close; ADOTable1.Open; //  name   program ADOTable1.Filtered := False; ADOTable1.Filter := 'name='+#39+'program'+#39; ADOTable1.Filtered := True; ADOTable1.Edit; blobF := ADOTable1.FieldByName('files') as TBlobField; blobF.LoadFromFile(OpenDialog1.FileName); ADOTable1.FieldByName('version').AsString:=cxMaskEdit1.Text; ADOTable1.Post; except Showmessage(' !'); end; 

This is a slightly wrong method; it is best to make it a separate stream, especially if the archive is large.

It is necessary to add to Uses - SevenZip and ShellAPI .
Now create the most important update procedure, calling it Update:
')
 Procedure TForm1.Update; var path,fullpath,Ourversion,LastVersion:string; blobF: TBlobField; begin //     adoquery4.Active:=false; adoquery4.sql.text:='SELECT version FROM [dbo].[Updater] WHERE name='+#39+'program'+#39; adoquery4.Active:=true; //        ,    Ourversion:=GetMyVersion; LastVersion:=adoquery4.FieldByName('version').Value; while pos('.',LastVersion)<>0 do delete(LastVersion,pos('.',LastVersion),1); //             if strtoint(LastVersion)>strtoint(Ourversion) then If messageBox(Handle,'   . ?','?', mb_YesNo or mb_iconquestion)=mrYes then try path:=ExtractFileDir(ParamStr(0)); if FileExists(path+'\Program.backup') then DeleteFile(path+'\Project2.backup'); RenameFile(path+'\Program.exe', path+'\Program.backup'); //   // //ADOTable1    Updater ADOTable1.Close; ADOTable1.Open; ADOTable1.Filtered := False; ADOTable1.Filter := 'name='+#39+'program'+#39; ADOTable1.Filtered := True; ADOTable1.Active:=true; //  blobF := ADOTable1.FieldByName('files') as TBlobField; if blobF.Value = nil then Exit; blobF.SaveToFile(path+'\Update_ARMTitan.zip'); ADOTable1.Active:=false; //   with CreateInArchive(CLSID_CFormatZip) do begin OpenFile(ExtractFilePath(ParamStr(0)) + 'Update_ARMTitan.zip'); ExtractTo(ExtractFilePath(ParamStr(0))); Close; end; //    DeleteFile(path+'\Update_ARMTitan.zip'); //  fullpath:=path+'\Project2.exe'; ShellExecute(0, 'open', PWideChar(fullpath), '', nil, SW_SHOW); //WinExec(PAnsiChar(fullpath), SW_SHOW); Application.Terminate; // or: Close; finally end; end; 

Here, too, there is a flaw, it is better to unpack each file individually and check for errors, and not the entire archive as I did.
There are 2 little things that must be observed:
1. In the program directory there should be a 7z.dll file, so it is better to check:
 if FileExists(path+'\7z.dll') then begin ShowMessage('  7z.dll'); exit; end; 
or something else on the other.
2. In the archive with the update should not be present file 7z.dll, as it is used, or unpack everything separately as I wrote above and do not unpack only this file.

That's all. The main thing is not to forget before compiling the finished program for updating, before adding it to the archive, change the version number of the program.

There are some shortcomings in this way and I know it. But so far I have been using it and have not experienced any problems, although it should be refined.

Source: https://habr.com/ru/post/152285/


All Articles