Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi [gelöst] Henne Ei Problem - eigene EXE löschen (https://www.delphipraxis.net/134972-%5Bgeloest%5D-henne-ei-problem-eigene-exe-loeschen.html)

moelski 2. Jun 2009 18:24

Re: Henne Ei Problem - eigene EXE löschen
 
Moin !

Delphi-Quellcode:
hat das mit dem MoveFileEx() denn irgendwelche Nachteile
Ja, funktioniert nicht unter 98.
Aber 98 brauchen wir (leider) noch.

Zitat:

das Grauen...
Os schon richtig, aber das Thema ist auch leider nicht so trivial :cry:

Zitat:

auf keinen Fall den Programm-Ordner einfach so löschen
Nuja ... Wenn User im Programmordner Dateien ablegen, dann sollte man nur noch das Beileid aussprechen :stupid:
Aber ich gebe dir Recht. So eine Überprüfung könnte noch Sinn machen. Aber nicht bevor ich dieses Problem im Griff habe ..

Satty67 2. Jun 2009 18:31

Re: Henne Ei Problem - eigene EXE löschen
 
Zitat:

Zitat von moelski
Wenn User im Programmordner Dateien ablegen, dann sollte man nur noch das Beileid aussprechen

Du verwendest Delphi7 und siehst ja daran, was früher gängige Praxis war. Aber sehe auch, das aktuelle Uninstaller nichts löschen, was deren Installationsprogramm nicht selber reinkopiert hat.

Man bekommt dann immer die nette Meldung "Es konnte nicht alles gelöscht werden", womit der Ordner gemeint war, der nicht leer geworden ist.

wicht 2. Jun 2009 19:37

Re: Henne Ei Problem - eigene EXE löschen
 
Alles klar, das mit Win98 ist ein Argument. Bin ich froh, damit nichts mehr am Hut haben zu müssen.


Und weil Win98 eh lumpig ist, kann man dann auch den Uninstaller einfach im Temp-Ordner rumliegen lassen..

hoika 2. Jun 2009 20:04

Re: Henne Ei Problem - eigene EXE löschen
 
Hallo,

der Link unten zeigt c++-Quellcode zum Löschen der eigenen Exe.
Inwiefern das auch unter Win98 schon geht, weiss ich nicht.

DeleteMe.cpp

Heiko

Fridolin Walther 3. Jun 2009 02:22

Re: Henne Ei Problem - eigene EXE löschen
 
Zitat:

Zitat von hoika
der Link unten zeigt c++-Quellcode zum Löschen der eigenen Exe.
Inwiefern das auch unter Win98 schon geht, weiss ich nicht.

Das geht nicht mal unter allen Windows NT Varianten ;).

Zitat:

Zitat von moelski
Delphi-Quellcode:
hat das mit dem MoveFileEx() denn irgendwelche Nachteile
Ja, funktioniert nicht unter 98.
Aber 98 brauchen wir (leider) noch.

Das ist nicht dein Ernst, oder? Stimmt zwar, daß MoveFileEx unter Windows 9x nicht den MOVEFILE_DELAY_UNTIL_REBOOT Parameter implementiert, aber es ist ja nicht so als würde es unter Windows 9x keinen Mechanismus dafür geben: Nämlich wininit.ini.

In einigen Zeilen Code hat man dann in Windeseile einen Wrapper geschrieben:
Delphi-Quellcode:
function GetWindowsFolder: string;
const
  MAX_PATH_NTFS = 32767;
var
  CharArray : array[0..MAX_PATH_NTFS] of char;
begin
  FillChar(CharArray, SizeOf(CharArray), 0);
  if GetWindowsDirectory(CharArray, MAX_PATH_NTFS) > 0
    then Result := IncludeTrailingPathDelimiter(CharArray)
    else Result := '';
end;

function IsWindowsNT : boolean; inline;
begin
  Result := GetVersion and $80000000 = 0;
end;

function GetShortFilename(Filename: string) : string;
var
  ShortFilename : array[0..MAX_PATH] of char ;
begin
  if GetShortPathName(PChar(Filename), @ShortFilename, MAX_PATH) > 0
    then Result := ShortFilename
    else Result := Filename;
end;

function DeleteFileOnReboot(Filename : string) : boolean;
begin
  if IsWindowsNT
    then Result := MoveFileEx(PChar(ParamStr(0)), nil, MOVEFILE_DELAY_UNTIL_REBOOT)
    {
     FIXME:
     Prinzipiell können mehrere NUL Werte existieren. WritePrivateProfileString würde dann den jeweils ersten immer wieder überschreiben.
     Entsprechend wäre der 100% saubere Weg einen eigenen kleinen Parser für die wininit.ini zu bauen, der die rename Section sucht
     und die eigenen Einträge hinten dran hängt.
    }
    else Result := WritePrivateProfileString('rename', 'nul', PChar(GetShortFilename(Filename)), PChar(GetWindowsFolder + 'wininit.ini'));
end;
Wenn man dann noch das Verzeichnis entfernen will, bietet sich der bereits oft zitierte Trick mit der temporären Datei an. Sowas könnte dann z.B. so aussehen:
Delphi-Quellcode:
program DeleteMe;

{$APPTYPE CONSOLE}

uses
  SysUtils, windows;

function GetWindowsFolder: string;
const
  MAX_PATH_NTFS = 32767;
var
  CharArray : array[0..MAX_PATH_NTFS] of char;
begin
  FillChar(CharArray, SizeOf(CharArray), 0);
  if GetWindowsDirectory(CharArray, MAX_PATH_NTFS) > 0
    then Result := IncludeTrailingPathDelimiter(CharArray)
    else Result := '';
end;

function GetTempFolder : string;
const
  MAX_PATH_NTFS = 32767;
var
  CharArray : array[0..MAX_PATH_NTFS] of char;
begin
  FillChar(CharArray, SizeOf(CharArray), 0);
  if GetTempPath(MAX_PATH_NTFS, @CharArray) > 0
    then Result := IncludeTrailingPathDelimiter(CharArray)
    else Result := '';
end;

function GetTemporaryFilename : string;
var
  CharArray : array[0..MAX_PATH] of char;
begin
  FillChar(CharArray, SizeOf(CharArray), 0);
  if GetTempFileName(PChar(GetTempFolder), 'Del', 0, @CharArray) <> 0
    then Result := CharArray
    else Result := '';
end;

function GetShortFilename(Filename: string) : string;
var
  ShortFilename : array[0..MAX_PATH] of char ;
begin
  if GetShortPathName(PChar(Filename), @ShortFilename, MAX_PATH) > 0
    then Result := ShortFilename
    else Result := Filename;
end;

function IsWindowsNT : boolean; inline;
begin
  Result := GetVersion and $80000000 = 0;
end;

function DeleteFileOnReboot(Filename : string) : boolean;
begin
  if IsWindowsNT
    then Result := MoveFileEx(PChar(ParamStr(0)), nil, MOVEFILE_DELAY_UNTIL_REBOOT)
    {
     FIXME:
     Prinzipiell können mehrere NUL Werte existieren. WritePrivateProfileString würde dann den jeweils ersten immer wieder überschreiben.
     Entsprechend wäre der 100% saubere Weg einen eigenen kleinen Parser für die wininit.ini zu bauen, der die rename Section sucht
     und die eigenen Einträge hinten dran hängt.
    }
    else Result := WritePrivateProfileString('rename', 'nul', PChar(GetShortFilename(Filename)), PChar(GetWindowsFolder + 'wininit.ini'));
end;

procedure ExecuteFile(Filename, Parameters : string);
var
  StartupInformation  : TStartupInfo;
  ProcessInformation  : TProcessInformation;
begin
  writeln('Temporaere Datei erstellt: ', Filename);
  FillChar(StartupInformation, SizeOf(TStartupInfo), 0);
  FillChar(ProcessInformation, SizeOf(TProcessInformation), 0);
  StartupInformation.cb := SizeOf(TStartupInfo);

  CreateProcess(nil, PChar('"' + Filename + '" ' + Parameters), nil, nil, false,
    CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInformation,
    ProcessInformation);
end;

procedure CreateAndRunCopyOfMyself();
var
  RandomFilename      : string;
begin
  RandomFileName := GetTemporaryFilename;
  if RandomFilename <> ''
    then
      if CopyFile(PChar(ParamStr(0)), PChar(RandomFilename), false)
        then ExecuteFile(RandomFilename, '"' + ParamStr(0) + '"')
        else DeleteFile(PChar(RandomFilename));
end;

procedure DeleteMyOldSelfAndMe();
begin
  if FileExists(ParamStr(1))
    then
      repeat
        writeln('Versuche alte Datei zu entfernen ...');
        Sleep(1000);
      until DeleteFile(PChar(ParamStr(1)));
  // Prinzipiell könnte man jetzt auch das Verzeichnis entfernen nur so nebenbei ...
  if DeleteFileOnReboot(ParamStr(0))
    then writeln('Alte Datei entfernt und mich selbst fuer Entfernung bei Reboot eingetragen.')
    else writeln('Alte Datei entfernt, aber ich selbst bin noch da: ', ParamStr(0));
end;

begin
  if ExtractFileExt(ParamStr(0)) = '.tmp'
    then DeleteMyOldSelfAndMe()
    else CreateAndRunCopyOfMyself;
  Writeln('Enter um die Anwendung zu beenden');
  Readln;
end.
Die Anwendung kopiert sich selbst in den Temp Ordner, ruft dann seine Kopie auf mit dem Originalnamen als Parameter. Danach versucht die Kopie das Original zu löschen. Sobald das geschehen ist, fügt es sich selbst zum Löschen bei Reboot hinzu. Prinzipiell kann man dann sobald die Original Datei gelöscht ist, auch das Verzeichnis entfernen indem man den Code in DeleteMyOldSelfAndMe an der Kommentarstelle erweitert.

Prinzipiell könnte man auch Code in eine fremde Anwendung injezieren um die eigene Anwendung zu löschen. Das käme komplett ohne Temporäre Dateien oder ähnliches aus. Allerdings ist es je nach System relativ schwer zu implementieren. Davon abgesehen kreischen die ganzen HIPS und Behaviour Blocker immer gleich rum, wenn man Code Injection durchführt. Weiß nicht ob das entsprechend für Dich eine Option wäre.

Achja: Ich behaupte übrigens, daß es keine Installationsaufgabe gibt, die man nicht mit einem der gängigen Installer Tools lösen kann. Entsprechend find ich es sinnbefreit einen womöglich dritt- oder viertklassigen Installer selbst zu bauen, wenns teilweise extrem leistungsfähige Open Source Projekte gibt (InnoSetup, NSIS um nur zwei zu nennen, von komerziellen Lösungen mag ich gar nicht erst anfangen).

Zu guter letzt weise ich darauf hin, daß ich der Übersicht halber nur rudimentäres Fehlerhandling implementiert hab. Bevor man den Code benutzt, sollte man ihn um entsprechendes Fehlerhandling erweitern.

moelski 3. Jun 2009 07:14

Re: Henne Ei Problem - eigene EXE löschen
 
Moin !

Danke für den Code. Werde ich doch gleich mal testen.

Zitat:

Ich behaupte übrigens, daß es keine Installationsaufgabe gibt, die man nicht mit einem der gängigen Installer Tools lösen kann
Habe ja nie etwas Gegenteiliges behauptet :wink:
Wir hatten zu Beginn Innosetup und danach AKInstallerMSI. Und du hast vollkommen Recht das wir damit alles lösen können.

OT ein
Wir wollten aber einen Installer der genau auf unsere Bedürfnisse zugeschnitten ist. Nämlich:
- Installation / Update über Web
- Installation / Update über Resourcen ZIP
- Installation direkt auf USB Stick (bedarf ein paar extra Schritte)
- sehr einfaches Handling

Ich denke das unser Installer genau das erfüllt :) Und wir haben einen Installer wo wir die Quellcodes von Anfang an kennen und nach unseren Vorstellungen anpassen können. Mag sein das diese Aufgaben mit anderen Installern ebenfalls lösbar sind, aber nun ist er eh bald fertig und wie gesagt er macht genau das was wir brauchen. Nicht mehr und nicht weniger.
OT aus

moelski 3. Jun 2009 08:48

Re: Henne Ei Problem - eigene EXE löschen
 
Moin !

So code mal getestet und funzt soweit ganz gut. Aber das Löschen des Verzeichnisses bereitet noch ein Problem.

Wenn ich die Anwendung absolut starte (aus dem Verzeichnis heraus oder per Link), dann wird das Verzeichnis nicht gelöscht.
Starte ich die Anwendung relativ also z.B. "Neuer Ordner\Project1.exe" dann klappt auch das Löschen des Verzeichnisses.

Finde ich etwas merkwürdig, denn erst wird das Verzeichnis geleert und dann versucht ja die zweite Instanz das Verzeichnis zu entfernen. Mir ist nicht ganz klar warum das in die Hose geht. :gruebel:

Satty67 3. Jun 2009 08:57

Re: Henne Ei Problem - eigene EXE löschen
 
Vielleicht vorm Ordner löschen auch noch etwas warten (auch wenn das im Vergleich zur funktionierenden Methode unlogisch wäre) und den Fehler beim Ornder löschen genauer auswerten (beschreiben)... wenn es denn einen gibt.

moelski 3. Jun 2009 09:07

Re: Henne Ei Problem - eigene EXE löschen
 
Moin !

"Warten" habe ich auch schon probiert. Bringt aber nichts.
Muss mal sehen ob ich das Problem näher eingrenzen kann.

hoika 3. Jun 2009 09:24

Re: Henne Ei Problem - eigene EXE löschen
 
Hallo,

vielleicht solltest du vor dem Löschen per

SetCurrentDirectory

mal aus deinem Exe-Verzeichnis rausgehen (z.B. ins Temp).


Heiko


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:10 Uhr.
Seite 3 von 4     123 4      

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