Re: Henne Ei Problem - eigene EXE löschen
Moin !
Delphi-Quellcode:
Ja, funktioniert nicht unter 98.
hat das mit dem MoveFileEx() denn irgendwelche Nachteile
Aber 98 brauchen wir (leider) noch. Zitat:
Zitat:
Aber ich gebe dir Recht. So eine Überprüfung könnte noch Sinn machen. Aber nicht bevor ich dieses Problem im Griff habe .. |
Re: Henne Ei Problem - eigene EXE löschen
Zitat:
Man bekommt dann immer die nette Meldung "Es konnte nicht alles gelöscht werden", womit der Ordner gemeint war, der nicht leer geworden ist. |
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.. |
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 |
Re: Henne Ei Problem - eigene EXE löschen
Zitat:
Zitat:
In einigen Zeilen Code hat man dann in Windeseile einen Wrapper geschrieben:
Delphi-Quellcode:
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:
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;
Delphi-Quellcode:
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.
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. 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. |
Re: Henne Ei Problem - eigene EXE löschen
Moin !
Danke für den Code. Werde ich doch gleich mal testen. Zitat:
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 |
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: |
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.
|
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. |
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. |
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