AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi Tutorial für OnlineUpdate (Meine Lösung)
Tutorial durchsuchen
Ansicht
Themen-Optionen

Tutorial für OnlineUpdate (Meine Lösung)

Ein Tutorial von dor557 · begonnen am 11. Jan 2008 · letzter Beitrag vom 18. Mär 2008
Antwort Antwort
Benutzerbild von dor557
dor557
Registriert seit: 23. Okt 2004
Habe nun schon oft Hier gelesen das man seine Anwendung selbst updaten möchte.
Immer wurde gefragt wie mache ich das Hier mal meine Lösung !

Folgende dinge braucht man :
  • Inno Setup (mit PreProcessor und Erkennen ISS)
  • Logischweise Sein eigenes Programm
  • Verständnis für Delphi-Code (Damit man weiss was da passiert)
  • XML-Kenntnisse (Für diese weise) gerne kann man auch ein Anderes Format benutzen

Nun erstelle man eine XML datei die Folgendermassen aussehen könnte :

XML-Code:
<?xml version="1.0" encoding="iso-8859-1"?>
<programme>
  <programm>
    <id>1</id>
   <name>Programmbeschreibung</name>
   <int-name>OwnPrgName</int-name>
   <version>0.4</version>
   <build>2000</build>
   <author>Sascha Nickel</author>
   <file>http://www.yourdomain.de/download/v1.0/update10.exe</file>
    <updatepossible>
      <build>1531</build>
    </updatepossible>
  </programm>
</programme>
Zur erklärung (welche sich nachher durch den Delphi-Code automatisch erklärt) folgendes :

Man kann das auch auf Mehrere Programme erweitern einfach einen Neuen Programm abschnitt einfügen könnte dann so aussehen :

XML-Code:
<?xml version="1.0" encoding="iso-8859-1"?>
<programme>
  <programm>
    <id>1</id>
   <name>Programmbeschreibung</name>
   <int-name>OwnPrgName</int-name>
   <version>1.0</version>
   <build>2000</build>
   <author>Sascha Nickel</author>
   <file>http://www.yourdomain.de/download/Prg1/v1.0/update10.exe</file>
    <updatepossible>
      <build>1531</build>
    </updatepossible>
  </programm>
  <programm>
    <id>2</id>
   <name>Programmbeschreibung für 2. Programm</name>
   <int-name>OwnPrgName2</int-name>
   <version>1.4</version>
   <build>7</build>
   <author>Sascha Nickel</author>
   <file>http://www.yourdomain.de/download/Prg2/v1.4/update14.exe</file>
    <updatepossible>
      <build>2</build>
      <build>3</build>
      <build>4</build>
      <build>5</build>
      <build>6</build>
    </updatepossible>
  </programm>
</programme>
So diese datei dann auf den Webserver des vertrauens hochladen und das nun in die Anwendung einbinden. Man erstellt dann ein Formular mit 2 Buttons einmal mit "Updates Prüfen" und einmal "Schliessen", Eine ProgressBar und 4 Checkbuttons (Ich habe TEwCheckBox benutzt, das kann aber Jeder selbst entscheiden, mir ging es um die Optik ) Könnte dann in etwa so aussehen :

http://www.the-microborgs.de/softwar...ineupdate1.jpg

Nun gibt man noch diese funktion Hinzu :

Delphi-Quellcode:
function GetInetFile (const fileURL, FileName: String; Progress : TProgressBar): boolean;
const
  BufferSize = 1024;
var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  code : array[1..20] of char;
  BufferLen,
  Index,
  CodeLen,
  FileSize : DWord;
  f: File;
  sAppName: string;
  f1 : Integer;
begin
 result := false;
 sAppName := ExtractFileName(Application.ExeName) ;
 hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;
 try
  hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, INTERNET_FLAG_DONT_CACHE, 0) ;
  try
   AssignFile(f, FileName) ;
   Rewrite(f,1);
   if Progress <> NIL then
   begin
     Index := 0;
     CodeLen := 10;
     HttpQueryInfo(hURL, HTTP_QUERY_CONTENT_LENGTH, @code, codeLen, Index);
     Progress.Visible := true;
     Progress.max := strtoint(code);
   end;
   repeat
    InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
    BlockWrite(f, Buffer, BufferLen);
    if Progress <> NIL then
    begin
      Progress.StepBy(SizeOf(Buffer));
      fOnlUpdate.Panel4.Refresh;
    end;
   until BufferLen = 0;
   CloseFile(f) ;
   result := True;
  finally
   InternetCloseHandle(hURL)
  end;
 finally
  InternetCloseHandle(hSession)
 end;
end;
welche ich mit hilfe Dieses Posts zusammengestellt habe.

Dann setzt man sich hin und gibt dem Button "Auf Updates prüfen" Folgende Onclick anweisung :

Delphi-Quellcode:
procedure TFOnlUpdate.CheckUpdateClick(Sender: TObject);
const updateURL = 'http://www.the-microborgs.de/download/update.xml';
      int_name = 'OwnPrgName';
      prg_ID = 1;
var Programme : IXMLDOMNodeList;
     updatepossible : IXMLDOMNodeList;
     tmpfile : string;
     Pos : Integer;
     i,j : Integer;
     RunUpdate : Boolean;
    tmpexefile : string;
    reg : TRegistry;
    f : File;
begin
  Label2.Caption := 'MyApp führt die gelisteten Aufgaben aus...';
  Panel1.Refresh;
  RunUpdate := false;
  with CheckVersionCheck do
  begin
    glyph := igRound;
    Checked := true;
    refresh;
    Glyph := igCheck;
    caption := 'Laufende Version Gefunden : v' + inttostr(Version.Hauptversion) + '.' + inttostr(Version.Nebenversion) + ' (Build '+ inttostr(Version.build) + ')';
    Refresh;
    sleep(20);
  end;
  with ConnServerCheck do
  begin
    glyph := igRound;
    Checked := true;
    Refresh;
    sleep(20);
  end;
  tmpfile := 'C:\updatetemp.xml'; // Man kann auch jeden anderen Pfad benutzen das ist egal.
  if GetInetFile(updateURL, tmpfile,NIL) then
  begin
    with ConnServerCheck do
    begin
      Glyph := igCheck;
      Caption := 'Verbindung zum Server Hergestellt';
      refresh;
    end;
    with CheckUpdatesExists do
    begin
      Glyph := igRound;
      Checked := true;
      refresh;
    end;
    xmlUpdateDoc := CoDOMDocument.Create;
    xmlUpdateDoc.load(tmpfile);
    if (xmlUpdateDoc <> nil) then
    begin
      Programme := xmlUpdateDoc.selectNodes('/programme/programm');
      if Programme.length > 0 then
      begin
        // Checken ob überhaupt einträge in der XML-Datei sind
        for I := 0 to Programme.Length - 1 do
        begin
          // Den internen Namen die ID und die Build version checken
          if (Programme.item[i].selectSingleNode('int-name').text = int_Name) and
             (strtoint(Programme.item[i].selectSingleNode('id').text) = prg_ID) and
             (strtoint(Programme.item[i].selectSingleNode('build').text) > Version.Build) then
          begin
            updatepossible := Programme.item[i].selectNodes('updatepossible/build');
            // Checken mit welchem Laufenden build man das Update runterladen darf
            for J := 0 to updatePossible.Length - 1 do
            begin
              if (updatepossible.item[j].nodeName = 'build') and (UpdatePossible.item[j].text = inttostr(Version.Build)) then
              begin
                with CheckUpdatesExists do
                begin
                  Glyph := igCheck;
                  Caption := 'Neue Version Gefunden : v' +
                      Programme.item[i].selectSingleNode('version').text + ' (Build ' +
                      Programme.item[i].selectSingleNode('build').text + ')';
                  refresh;
                end;
                RunUpdate := true;
                // Dateiname der heruntergeladen werden muss auslesen
                UpdateFileDownload := Programme.item[i].selectSingleNode('file').text;
              end else if not RunUpdate then
              begin
                if (j = (UpdatePossible.Length-1)) then
                with CheckUpdatesExists do
                begin
                  Glyph := igCross;
                  Caption := 'Es existieren keine Upates für die Version : v' + inttostr(Version.Hauptversion) + '.' + inttostr(Version.Nebenversion) + ' (Build '+ inttostr(Version.build) + ')';
                  refresh;
                end;
              end;
            end;
          end else if not RunUpdate then
          with CheckUpdatesExists do
          begin
            Glyph := igCross;
            Caption := 'Es existieren keine Upates für die Version : v' + inttostr(Version.Hauptversion) + '.' + inttostr(Version.Nebenversion) + ' (Build '+ inttostr(Version.build) + ')';
            refresh;
          end;
        end;
      end;
    end;

  // Update Procedure an sich ! Herunterladen und starten ! :)
  if RunUpdate then
  begin
    tmpexefile := 'C:\Programme\MyApp\update.exe';
    DownloadUpdates.Visible := true;
    DownloadUpdates.Glyph := igRound;
    DownloadUpdates.Caption := 'Download von update.exe...';
    DownloadUpdates.Checked := true;
    Panel4.Refresh;
    if GetInetFile(UpdateFileDownload, tmpexefile, ProgressBar1) then
    begin
      DownloadUpdates.Glyph := igCheck;
      DownloadUpdates.Caption := 'Download von update.exe...Abgeschlossen';
      Panel4.Refresh;
      tmpfile := 'C:\updatetemp.xml';
      if FileExists(tmpfile) then
      begin
        assignFile(f, tmpFile);
        erase(f);
      end;
      UpdateRun := TFileRun.Create(self);
      UpdateRun.Browse := false;
      UpdateRun.FileName := tmpexefile;
      UpdateRun.Execute;
    end;
  end;
  end else
  ShowMessage('Fehler beim Versuch nach updates zu schauen !!');
end;
Die sache mit der version läuft bei mir so, Eine Unit erstellen die dann so aussieht:

Delphi-Quellcode:
unit verInfo;
interface

uses windows, types, sysutils;

//Auslesen der Versionsnummer aus einer Datei
type
  T_Version = Record
    Hauptversion, Nebenversion, Ausgabe, Build : Integer;
  end;


  function GetVersion(Datei : String): T_Version;
implementation


function GetVersion(Datei : String): T_Version;
var
  VerInfoSize: DWORD;
  VerInfo: Pointer;
  VerValueSize: DWORD;
  VerValue: PVSFixedFileInfo;
  Dummy: DWORD;

begin
  Result.Hauptversion := 0;
  Result.Nebenversion := 0;
  Result.Ausgabe := 0;
  Result.Build := 0;

  If FileExists(Datei) Then begin
    VerInfoSize := GetFileVersionInfoSize(PChar(Datei), Dummy);
    if VerInfoSize = 0 then Exit;
    GetMem(VerInfo, VerInfoSize);
    GetFileVersionInfo(PChar(Datei), 0, VerInfoSize, VerInfo);
    VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
    with VerValue^ do
    begin
      Result.Hauptversion := (dwFileVersionMS shr 16);
      Result.Nebenversion := (dwFileVersionMS and $FFFF);
      Result.Ausgabe := (dwFileVersionLS shr 16);
      Result.Build := (dwFileVersionLS and $FFFF);
    end;
    FreeMem(VerInfo, VerInfoSize);
  end
  else begin
    Result.Hauptversion := 0;
    Result.Nebenversion := 0;
    Result.Ausgabe := 0;
    Result.Build := 0;
  end;
end;

end.
und das dann in der OnlUpdate.pas (Gehört zu unserem Formular in die uses anweisung setzen)
und dann noch Die version auslesen was dann so geht :

zuerst die Version Variable Deklarieren :
var Version : T_Version; Wo ? Am besten in der unit in der das Main Formular drinnen ist.

Bei der OnCreate Function des Formulars dann diese Funktion einsetzen :

Delphi-Quellcode:
procedure TFOnlUpdate.FormCreate(Sender: TObject);
begin
  Version := GetVersion(Paramstr(0));
end;
und schon ist die Versionsinfo drinnen

Nach dem alles fertig ist kommt der haken mit dem Externen setup, Denn wie man weiss kann man nicht ein Laufendes Programm überschreiben. Da kam ich dann auf die Idee das programm mit hilfe des erstellten Inno Setup Script zu beenden. Anfangs dachte ich dann das das Setup mit beendet würde wenn ich das Programm welches das setup ausführt beende. Aber weit gefehlt. Es ging. So habe ich dann den Inno Setup "code" teil aussehen lassen :

Delphi-Quellcode:
function InitializeSetup(): Boolean;
var WinID : Integer;
begin
Result :=not Erkennen('myApp.exe'); // Der dateiname der ausgeführt wird.
if not Result then
  if Msgbox('Das Programm läuft noch,' + #13 + 'Soll das Programm beendet werden ?' , mbConfirmation, MB_YESNO) = IDYES then
  begin
    Result := True;
    WinID := FindWindowByWindowName('My Application'); // Der Name der im Fenster steht.
    if WinID <> 0 then
     // Mit dem SendMessage befehl wird das Programm beendet !
    SendMessage(FindWindowByWindowName('My Application'),WM_CLOSE,0,0) else
    begin
      WinID := FindWindowByWindowName('My Application - [Daten erfassen]'); // Der Name der im Fenster steht.
      // für den fall das man
      //eine MDI anwenung gemacht hat und hinten dran noch etwas steht !

      if WinID <> 0 then SendMessage(FindWindowByWindowName('My Application - [Daten erfassen]'),WM_CLOSE,0,0) else
      MsgBox('My Application konnte nicht beendet werden,' + #13 + 'Bitte beenden sie Das Programm manuell oder Starten sie das Setup zu einem Späteren Zeitpunkt.', mbError, MB_OK);
    end;
  end else result := false;
end;
Hier ein Paar Links dazu :

Inno Setup Forum Beitrag (Erkennen und beenden des Programmes)
Inno Setup zum Download
Post zum download der Datei aus dem Internet

Wer Fragen zu diesem "Tutorial" hat kann gerne schreiben. Habe das nicht so in dieser form getestet. Sondern lediglich meinen code benutzt und Anwendungsname und Pfade geändert. Ansonsten geht das recht simpel. Ich hoffe ich habe nichts vergessen oder etwas zu wenig erklärt werde es gerne erklären wenn jemand Fragen hat.

Gruss Sascha
Man muss die Dinge nehmen wie sie kommen, man kann aber auch dafür sorgen das die dinge so kommen wie man sie nehmen möchte.
 
Benutzerbild von dor557
dor557

 
Delphi 10.1 Berlin Starter
 
#2
  Alt 18. Mär 2008, 19:44
Also ich habe festgestellt das ich vergessen habe zu sagen was UpdateRun ist !!

Sorry...

UpdateRun muss in der unit deklariert werden wo die Komponenten drauf sitzen !

ist eine TFileRun !!

Gruss Sascha
Sascha Nickel
  Mit Zitat antworten Zitat
hoika

 
Delphi 10.4 Sydney
 
#3
  Alt 18. Mär 2008, 20:12
Hallo,

nur leider fehlt der Hinweis,
dass das alles unter Vista nicht mehr geht (UAC).


Heiko
Heiko
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz