Update programu

chmolu

Fajnie byłoby, aby program miał możliwość sprawdzenia, czy wyszła jego nowsza wersja. Zaprezentuję tutaj prosty sposób wg mojego pomysłu.

Potrzebne będą nam: konto na jakimś serwerze i komponent HTTPGet. Nie wiem, czy jest on na tej stronie, ale zamieszczam go do przykładowego programu, który znajdziecie w kodach źródłowych.

No więc zaczynamy.
Na początek stwórz plik version.ini. Potrzebny będzie, aby odczytać, czy wyszła nowa wersja programu. Plik będzie wyglądał tak:

[update]
version=1.3
url=http://www.web-page.pl/program.exe

Oczywiście url trzeba dostosować do swojej strony www.
Teraz przechodzimy do Delphi. Wrzuć na formę komponenty: Memo, Button, 2 HTTPGet i ProgressBar.
Wersję można wyciągnąć z zasobów, ale ja zadeklaruję tylko stałą:

const
  wersja = '1.2';

W zdarzeniu OnClick przycisku wpisz:

procedure TForm1.Button1Click(Sender: TObject);
begin
 HTTPGet1.URL := 'http://www.web-page.pl/version.ini';  //lokalizacja pliku z informacją
 HTTPGet1.FileName := ExtractFilePath(Application.ExeName) + 'version.ini'; 
 HTTPGet1.GetFile;  //pobranie pliku ini
 Memo1.Lines.Add('Pobieranie informacji...'); 
end;

Teraz w zdarzeniu onDoneFile komponentu HttpGet1 wpisz:

procedure TForm1.HTTPGet1DoneFile(Sender: TObject; FileName: String;
  FileSize: Integer);
var
 INI : TINIFile;
 updtVersion : string;
 cyfra1 : integer;
 cyfra2 : integer;
 updtCyfr1 : integer;
 updtCyfr2 : integer;
begin
 Memo1.Lines.Add('Sprawdzanie, czy jest nowa wersja');
 INI := TINIFile.Create(HTTPGet1.FileName);
 try
   updtVersion := INI.ReadString('update','version','');  //odcytanie wersji z pliku ini

   //nie śmiejcie sie z tego sposobu. To tylko przykład :)
   cyfra1 := StrToInt(wersja[1]);
   cyfra2 := StrToInt(wersja[3]);
   updtCyfr1 := StrToInt(updtVersion[1]);
   updtCyfr2 := StrToInt(updtVersion[3]);
   if (cyfra1 < updtCyfr1) or (cyfra2 < updtCyfr2) then  //sprawdzenie, czy jest nowa wersja
   begin
     Memo1.Lines.Add('Jest nowa wersja programu');

{wyświetlenie zapytania. Jeśli użytkownik wybierze Tak, rozpoczyna się pobieranie programu }
     if Application.MessageBox('Czy chcesz pobrać nową wersję programu?','Informacja',MB_YesNo) =
      ID_NO then
      exit
     else
      begin
       HTTPGet2.URL := INI.ReadString('update','url','');
       if SaveDialog1.Execute then  // tu użytkownik wybierze, gdzie zapisać program
         HTTPGet2.FileName := SaveDialog1.FileName;  
       HTTPGet2.GetFile;  //pobieranie pliku
       Memo1.Lines.Add('Pobieranie pliku');
      end;
   end
   else
      Memo1.Lines.Add('Nie znaleziono nowej wersji prormu');
 finally
   INI.Free;
   DeleteFile(HTTPGet1.FileName); //usunięcie pliku ini
 end;

end;

Następnie w OnError komponentu HttpGet1:

procedure TForm1.HTTPGet1Error(Sender: TObject);
begin
 Memo1.Lines.Add('Wystąpił błąd');
end;

Następnie w OnDoneFile komponentu HttpGet2:

procedure TForm1.HTTPGet2DoneFile(Sender: TObject; FileName: String;
  FileSize: Integer);
begin
 Memo1.Lines.Add('Pobieranie zakończone sukcesem');
end;

Teraz w OnError HttpGet2:

procedure TForm1.HTTPGet2Error(Sender: TObject);
begin
  Memo1.Lines.Add('Wystąpił błąd podczas pobierania pliku');
end;

No i na koniec w onProgress komponentu HttpGet2:

procedure TForm1.HTTPGet2Progress(Sender: TObject; TotalSize,
  Readed: Integer);
begin
  ProgressBar1.Max := TotalSize;
  ProgressBar1.Position := Readed;
end;

Teraz wystarczy tylko wrzucić plik version.ini na serwer.
To był oczywiście najprostszy sposób na uaktualnienie swojego programu, ale wystarczy troszkę wyobraźni i
rozbudowanie tego kodu nie będzie problemem.

pozdrawiam:
Piotrek Chmolowski

Kod przykładowego programu możecie pobrać tutaj:

http://4programmers.net/download.html?id=1036

30 komentarzy

Wpisz INIFiles do uses

Zgadzam sie z Wolverinem, na taki sam pomysl wpadlem podczas pisania swojego programu. Bo najlatwiej go zrealizowac :P

Dobre do czasu, do kiedy nie usuna Ci konta (na bezplatnym serwerze) :D

prawie to samo jest w kompendium programisty d7 Adama... ;]

dzieki. moze sie przydac :)
a wiecie ze ja znalazlem gdzies w sieci opis uzycia OpenDialog. Slowko w slowko to samo ;) Musieli zerznac z ksiazki Adama B. ;)

Swoją drogą, co wy tak macie z tym HTTPGet ? ;) Ja tam wolę stare dobre UrlDownloadToFile, bo mozna go zastosować wszędzie, również programując w API. I dzięki temu mój programik Downloader nie musi mieć formy w dfm ani classes w uses :P

Ja mam problem...[Error] Unit2.pas(53): Undeclared identifier: 'TINIFile'

Wiecie dlaczego?

ja nie mowie ze zerznales..mowie tylko ze kod adama to 1/3 tego

zerżnołeś albo ktoś zerżną z ciebie słuwko w słuwko znalazłem to na koder.prv.pl
// o mamo, ale byki... - ŁF

hej nie bulwersuj sie, na taka metode wpada sie po 5 sekundach myslenia o update'ach programu. Poza tym nawet ja nie pisze "sluwko"

Taki drobny problem - 1.9 będzie nowsza niż 2.1 :-) Lepiej skonwertować na floata.

TO samo (tzn podobny sposob, tyle ze prostszy) znajduje sie w ksiazce Adama (D7cwzaw) ciekawe.. :/

zapewniam Cię, lofix, że tej książki nie widziałem na oczy.

Przecież mój sposób bardzo łatwo rozbudować.
Wystarczy jakiś pomysł. Można np. dać drugi link do pliku z informacją co nowego w programie.

Nawet niezłe, ale powien Ci co ja zrobiłem : na serwerku walnąłem plik textowy w takim formacie :

NAZWAPLIKU;URL_DO_NIEGO

W ten sposób można zamieścić nie tylko jedną wersję, ale np. uaktualnienia do bibliotek (jeśli ich używamy), starsze wersje programu itp...

wyskakuje blad httpget, bo nie masz tego komponentu zainstalowanego [ot, caly problem]

A mi wyskakuje bląd cos SaveDialog1 undeclared? co to znaczy??

Teraz juz wiem..... moglem najpierw pomyslec, a pozniej dodac komentarz :)

uprałem sie z problemem xD jak ktoś nie wie to do uses trzeba dopisać IniFiles

a mi w tym miejscu kodu podkreśla błąd... o co chodzi??
INI : TINIFile;

Undeclared identifer: 'TINIfile'

używam delphi 7 personal

Zawsze można zrobić tak że na serwerze jest plik np. nazwa_numer.wersji i przy odpalaniu program próbuje pobrać ten plik jeśli go nie ma na serwerze, to nie ma aktualizacji wydaje mi się za bardzo prymitywna wersja jest chyba najlepsza :]

a znacie może jakaś dobra stronkę gdzie by założyć konto ?? bo na yoyo trzeba sie zalogować żeby ściągnąć plik na cba.pl i republice tez :(((

na yoyo żeby ściągać plik przez HTTP nigdzie się nie musisz logować, nie wiem skąd to wziąłeś

nav, pisałem o tym trochę niżej...

Kodzik ciekawy, mi się przyda niedługo :)

Witajcie. Dlaczego wersję programu odczytujecie jako łańcuch? Przecież klasa TINIFile posiada możliwość odczytywania zawartości kluczy jako liczb metodą INI.ReadInteger... Zamiast kombinować z konwertowaniem tekstu na liczby wystarczy podzielić numer wersji na bloki i je porównywać (zawartość pliku version.ini):

[CURRENT_VERSION]
Major=1
Minor=0
Release=0
Build=2043

Teraz pobrać do odpowiednich zmiennych te liczby i porównać. Można by było zapisać je do tablicy i jedną pętlą sprawdzić czy wersja aplikacji w pliku version.ini jest nowsza niż tej na dysku. No ale trzeba by było trochę pogłówkować =)

BTW: A poza tym algorytm nie jest w pełni poprawny, by jeżeli wersja aplikacji wzrośnie do 10, program odczyta go jako 1...

Metoda z liczbami jest uniwersalna, na łańcuchach niestety nie...

Zapraszam na moją stronę www.programistakuty.pl. Tam prezentuje mój darmowy program (bardzo łatwo konfigurowalny) do aktualizacji programu. Prezentuje tam wykorzystanie go w delphi oraz dołączam przykładowy projekt. Strona artykułu http://programistakuty.pl/kuty-updater/

Mam mały problem w use występuje mi błąd [Fatal Error] Unit1.pas(7): File not found: 'HTTPGet.dcu' i zaznacza mi się HTTPGet prosze poradzcie mi co mam z tym zrobić [???]

bordeux, nie dodałeś komponentu SaveDialog na formatkę.

Mam jedną uwagę dot. linijki 21 z procedury TForm1.HTTPGet1DoneFile. Tam jest:

if (cyfra1 < updtCyfr1) or (cyfra2 < updtCyfr2) then ...

ale jeśli program będzie np. w wersji 2.1 a ktoś nieszczęśliwie zapomni zaktualizować pliku na serwerze i tam będzie podane 1.9 to zacznie się nie upgrade, tylko DOWNGRADE (bo w tym wypadku cyfra2 > updtCyfr2)! To jest sytuacja wyjątkowa spowodowana przez osobę opiekującą się serwerem, ale pamięć ludzka jest zawodna więc proponuję takie coś:

if (cyfra1 < updtCyfr1) or ((cyfra1 = updtCyfr1) and (cyfra2 < updtCyfr2)) then ...

chyba będzie działać, ale nie jestem pewny bo dopiero zaczynam przygodę z Delphi

Czy mógł by ktoś zamieścić kod żródłowy tego programu , ponieważ niewiem dlaczego ale wywala mi błąd podczas kliknięcia na button .
bład jest w tej linijce :

updtCyfr1 := StrToInt(updtVersion[1]);

kod programu :

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IniFiles, XPMan, ComCtrls, StdCtrls, HTTPGet;

type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
ProgressBar1: TProgressBar;
XPManifest1: TXPManifest;
SaveDialog1: TSaveDialog;
HTTPGet1: THTTPGet;
HTTPGet2: THTTPGet;
procedure Button1Click(Sender: TObject);
procedure HTTPGet1DoneFile(Sender: TObject; FileName: String;
FileSize: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;

const
wersja = '1.2';

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
HTTPGet1.URL := 'http://www.pm2a.yoyo.pl/updater/version.ini'; //lokalizacja pliku z informacją
HTTPGet1.FileName := ExtractFilePath(Application.ExeName) + 'version.ini';
HTTPGet1.GetFile; //pobranie pliku ini
Memo1.Lines.Add('Pobieranie informacji...');
end;

procedure TForm1.HTTPGet1DoneFile(Sender: TObject; FileName: String;
FileSize: Integer);

var
INI : TINIFile;
updtVersion : string;
cyfra1 : integer;
cyfra2 : integer;
updtCyfr1 : integer;
updtCyfr2 : integer;
begin
Memo1.Lines.Add('Sprawdzanie, czy jest nowa wersja');
INI := TINIFile.Create(HTTPGet1.FileName);
try
updtVersion := INI.ReadString('update','version',''); //odcytanie wersji z pliku ini

//nie śmiejcie sie z tego sposobu. To tylko przykład :)
cyfra1 := StrToInt(wersja[1]);
cyfra2 := StrToInt(wersja[3]);
updtCyfr1 := StrToInt(updtVersion[1]);
updtCyfr2 := StrToInt(updtVersion[3]);
if (cyfra1 < updtCyfr1) or (cyfra2 < updtCyfr2) then //sprawdzenie, czy jest nowa wersja
begin
Memo1.Lines.Add('Jest nowa wersja programu');

{wyświetlenie zapytania. Jeśli użytkownik wybierze Tak, rozpoczyna się pobieranie programu }
if Application.MessageBox('Czy chcesz pobrać nową wersję programu?','Informacja',MB_YesNo) =
ID_NO then
exit
else
begin
HTTPGet2.URL := INI.ReadString('update','url','');
if SaveDialog1.Execute then // tu użytkownik wybierze, gdzie zapisać program
HTTPGet2.FileName := SaveDialog1.FileName;
HTTPGet2.GetFile; //pobieranie pliku
Memo1.Lines.Add('Pobieranie pliku');
end;
end
else
Memo1.Lines.Add('Nie znaleziono nowej wersji prormu');
finally
INI.Free;
DeleteFile(HTTPGet1.FileName); //usunięcie pliku ini
end;
end;

end.

Co w nim jest nie tak ??

Wklejam kod funkcji, która sprawdza czy jest nowa wersja programu bazując na dwóch plikach:

function TMainForm.IsNewVesrion(const VersionFileName, UpdateFileName: ShortString): Boolean;
var
{ZMIENNE PLIKOWE}
iniVersion, iniUpdate: TINIFile;
{ZMIENNA LICZNIKOWA}
I: Byte;
begin
{DOMYŚLNY REZULTAT FUNKCJI}
Result := False;

try
{TWORZENIE ZMIENNYCH PLIKOWYCH}
iniVersion := TINIFile.Create(VersionFileName);
iniUpdate := TINIFile.Create(UpdateFileName);

{SPRAWDZANIE POSZCZEGÓLNYCH LICZB WERSJI}
for I := 0 to 3 do
  if iniUpdate.ReadInteger('CURRENT_VERSION', IntToStr(I), 0) > iniVersion.ReadInteger('CURRENT_VERSION', IntToStr(I), 0) then
    begin
      {JEŚLI JEST WYŻSZA LICZBA WERSJI ZWRÓĆ TRUE}
      Result := True;
      Break;
    end;

finally
{USUŃ ZMIENNE PLIKOWE Z PAMIĘCI}
FreeAndNil(iniVersion);
FreeAndNil(iniUpdate);
end;
end;

Budowa plików jest prosta. Oto plik Version.ini - są w nim informacje na temat aktualnie posiadanej wersji programu:

[CURRENT_VERSION]
0=1
1=0
2=0
3=154

A to zawartość pliku Update.ini - jest to plik pobrany z sieci przechowujący informacje na temat najnowszej wersji programu:

[CURRENT_VERSION]
0=1
1=0
2=0
3=157

Jak widać jest w nim młodsza wersja programu, stąd funkcja zwróci prawdę. Algorytm nie myli się i nalezy go używać tuż po pobraniu pliku wersji z Internetu. Pozdrawiam.