Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Trennen von Pfad und Parameter (https://www.delphipraxis.net/125661-trennen-von-pfad-und-parameter.html)

almisoft 9. Dez 2008 20:07


Trennen von Pfad und Parameter
 
Ich schreibe gerade ein Tool, mit dem man Software deinstallieren kann.
Dazu lese ich die Schlüssel in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Curr entVersion\Uninstall aus.

Der Pfad zum Deinstallationsprogramm steht im Wert UninstallString. Beispiele:

a. MsiExec.exe /I{EC4455AB-F155-4CC1-A4C5-88F3777F9886}
b. C:\Windows\system32\Macromed\Flash\uninstall_plugi n.exe
c. D:\Programme\Avira\AntiVir PersonalEdition Classic\SETUP.EXE /REMOVE
d. "C:\Program Files\FRITZ!Box Monitor\install.exe" -d

Leider ist im Pfad auch ggf. ein Parameter mit angegeben.
Shellexecute oder Createprocess zum Ausführen des Deinstallationsprogramms erwartet aber den Pfad und die Parameter getrennt.

Frage:
1. Gibt es ggf. einen anderen Befehl neben Shellexecute oder Createprocess, dem ich den ganzen String übergeben kann?
2. Oder gibt es eine verlässliche Funktion, mit der ich Pfad und Parameter trennen kann?

freak4fun 9. Dez 2008 20:14

Re: Trennen von Pfad und Parameter
 
Sieht so aus als sind das alles Exen. Vielleicht kannste über diesen Weg da was machen. :gruebel:

Edit:
Und ggf. Klassifizieren:
a. Nach /{*} suchen
b. reine exe (ohne Parameter)
c. Nach /* suchen
d. Nach " am Anfang und Ende suchen + -*

* = beliebig viele zeichen

almisoft 9. Dez 2008 20:16

Re: Trennen von Pfad und Parameter
 
Hatte ich mir auch schon überlegt. Aber was ist, wenn einer die Endung weglässt?

freak4fun 9. Dez 2008 20:19

Re: Trennen von Pfad und Parameter
 
Zitat:

Zitat von almisoft
Hatte ich mir auch schon überlegt. Aber was ist, wenn einer die Endung weglässt?

Schauen ob das überhaupt auftreten kann. Ansonsten vielleicht die Möglichkeit einbauen, unbekannte Einträge an dich schicken zu können. (Button: "Unbekannten EIntrag einreichen") Dann kannste das Nachrüsten. Oder eine Konfigurationsdatei. :gruebel:

almisoft 9. Dez 2008 20:20

Re: Trennen von Pfad und Parameter
 
ich wäre mehr für eine elegante Lösung, alles andere scheint eher Flickwerk zu sein.
Habe gerade einen Eintrag ohne Endung gefunden ...

Sir Rufo 9. Dez 2008 20:22

Re: Trennen von Pfad und Parameter
 
Eigentlich ist es doch ganz einfach, mach es so wie Windows das macht:

Der Programmname (Laufwerk, Pfad, Datei) darf keine Leerzeichen enthalten, also ist das erste Leerzeichen der Trenner zwischen Programmname und Parameter.
Ausnahme: Der Programmname muß mit Anführungsstrichen umgeben werden, wenn er doch Leerzeichen enthält.

gelle ;)

EDIT: Obwohl dein Beispiel c da schon wieder abweicht ... aber ob das auch wirklich so in der Registry steht?

Matze 9. Dez 2008 20:23

Re: Trennen von Pfad und Parameter
 
Das würde hier aber nicht funktionieren:
Zitat:

Zitat von almisoft
D:\Programme\Avira\AntiVir PersonalEdition Classic\SETUP.EXE /REMOVE


himitsu 9. Dez 2008 20:24

Re: Trennen von Pfad und Parameter
 
C entspricht leider keiner Konvention und da wird es schwieriger, aber für A+B+D ... hast du die Delphi-Sourcen?

schau dir mal in der System-Unit die Funktion ParamStr (bzw. GetParamStr) an.


notfalls haben die JEDIs dafür auch was (hab da irgendwo mal die Unicodeversionen gesehn ... läßt sich ja nach ANSI umwandeln)


und den Fall von C ... da gibt's eigentlich nur eine Lösung
(ja, ich weiß, Windows läßt sowas leider zu ... ist halt blöd, wenn es viele Fehler einfach übergeht, anstatt sie als Fehler zu behandeln)

erstes Leerzeichen(oder Stringende) suchen
prüfen ob alles vorm Leerzeichen einer Datei entspricht (z.B. mit Funktion FileExists)
wenn nicht, dann nächstes Leerzeichen suchen und wieder wegleichen .... und solange wiederholen, bis der String abgearbeitet ist

almisoft 9. Dez 2008 20:27

Re: Trennen von Pfad und Parameter
 
Zitat:

1. Gibt es ggf. einen anderen Befehl neben Shellexecute oder Createprocess, dem ich den ganzen String übergeben kann?
Mit WinExec ging das ganz gut, weil WinExec alles frisst, aber unter Vista mit aktivierter UAC klappte es dann wieder nicht...

Sir Rufo 9. Dez 2008 20:27

Re: Trennen von Pfad und Parameter
 
Zitat:

Zitat von himitsu
C entspricht leider keiner Konvention und da wird es schwieriger, aber für A+B+D ... hat du die Delphi-Sourcen?

schau dir mal in der System-Unit die Funktionen ParamStr (bzw. GetParamStr) an.


notfalls haben die JEDIs dafür auch was (hab da irgendwo mal die Unicodeversionen gesehn ... läßt sich ja nach ANSI umwandeln)


und den Fall von C ... da gibt's eigentlich nur eine Lösung
(ja, ich weiß, Windows läßt sowas leider zu ... ist halt blöd, wenn es viele Fehler einfach übergeht, anstatt sie als Fehler zu behandeln)

erstes Leerzeichen(oder Stringende) suchen
prüfen ob alles vorm Leerzeichen einer Datei entspricht (z.B. mit Funktion FileExists)
wenn nicht, dann nächstes Leerzeichen suchen und wieder wegleichen .... und solange wiederholen, bis der String abgearbeitet ist

irgendwie fühlte ich eine hand in meinem mund ... so war es doch himitsu der mir das wort aus selbigen nahm :mrgreen:

Apollonius 9. Dez 2008 20:29

Re: Trennen von Pfad und Parameter
 
Lest doch bitte die ganze Dokumentation.
Das PSDK hat zu CreateProcess folgendes geschrieben:

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe

himitsu 9. Dez 2008 20:47

Re: Trennen von Pfad und Parameter
 
ungetestet
Delphi-Quellcode:
Procedure Split(Const S: String; Var Datei, Parameter: String);
  Var B: Boolean;
    i:  Integer;

  Begin
    B := False;
    i := 0;
    Repeat
      Inc(i);
      While (i <= Length(S)) and (S[i] <> ' ') or B do Begin
        If S[i] = '"' Then B := not B;
        Inc(i);
      End;
      Datei := StringReplace(Copy(S, 1, i - 1), '"', '', [rfReplaceAll]);
    Until FileExists(Datei) or (i > Length(S));
    Parameter := Trim(Copy(S, i, Length(S)));
  End;
Für FileExists würde ich aber 'ne Version empfehlen, welche Suchpfade (z.B. aus %PATH%) mit durchtestet und als Standardverzeichnis bei C:\Windows oder doch C:\Windows\System32 (müßte man mal ausprobieren, wo Windows anfängt mit suchen)


@Sir Rufo: hast leider geschrieben, wärend ich schrieb und ich hab nich alles gelesen :stupid:
Aber Windows läß leider sowas wie C zu ... drum machen es viele noch so ... würden die endlich mal strikt ihre Konventionen durchsetzen, gäb's sowas wie C nicht (OK, 90% der Programme würden nicht mehr laufen)

almisoft 9. Dez 2008 21:27

Re: Trennen von Pfad und Parameter
 
Ich habe inzwischen eine Lösung gefunden, wenn auch nur speziell für den UninstallString:

Delphi-Quellcode:
procedure SplitPathAndParameter(Command:string; var Path,Param:string);
const AnzUninstaller=10;
const Uninstaller:array[1..AnzUninstaller] of string=
            ('RUNDLL32.DLL"','RUNDLL32"','MSIEXEC.EXE"','MSIEXEC"','.EXE"',
            'RUNDLL32.DLL','RUNDLL32','MSIEXEC.EXE','MSIEXEC','.EXE');
var p,i:integer;
begin
  for i:=1 to AnzUninstaller do begin
    p:=Pos(Uninstaller[i],UpperCase(Command));
    if p>0 then begin
      Inc(p,Length(Uninstaller[i]));
      Path:=Copy(Command,1,p-1);
      Param:=Copy(Command,p+1,Length(Command)-p);
      Break;
    end;
  end;
end;

almisoft 9. Dez 2008 21:35

Re: Trennen von Pfad und Parameter
 
In diesem Fall greift der Pattern .EXE, der Parameter ist dann leer

himitsu 9. Dez 2008 21:38

Re: Trennen von Pfad und Parameter
 
und ich hab bei einem meiner Programme 'nen Befehlsscript als Uninstaller eingetragen (wird so auch nicht erkannt)

[add]
du willst nicht wissen, was passiert, wenn ich dir mal 'nen Verzeichnisnamen unterschmuggl, welcher z.B. MSIEXEC oder .EXE in Pfadnamen hat :angel2:

almisoft 9. Dez 2008 21:59

Re: Trennen von Pfad und Parameter
 
ich frage mich, wie Windows den UninstallString ausführt.

Zitat:

Lest doch bitte die ganze Dokumentation.
Das PSDK hat zu CreateProcess folgendes geschrieben:

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe

Mit CreateProcess hat es auch nicht geklappt: "Der angeforderte Vorgang erfolg höhere Rechte"
Bei der Ausführung per ShellExecute poppt wie gewünscht die UAC auf ... aber ShellExecute will eben den Parameter separat.

Hat noch jemand ne Idee für eine elegante Lösung?

himitsu 11. Dez 2008 15:52

Re: Trennen von Pfad und Parameter
 
Mit einem "schönerem" FileExists kannst'e eigentlich meine Variante verwenden.

Das FileExists von Delphi sucht nur an genau dem angegebenem Pfad ... aber da in diesem Fall Dateien ohne Pfadangebe auch über Suchpfade wie in %PATH% angegeben gesucht werden, muß da auch entsprechend geprüft werden.
Eventuell könnte man auch einfach satt mit FileExists zu prüfen direkt versuchen ShellExecute aufzurufen und bei einem Fehler (ERROR_FILE_NOT_FOUND) den nächsten Durchgang versuchen.


Willst du die Trennung erst, um es z.B. irgendwo anzuzeigen, oder willst du es einfach nur direkt aufrufen? (für Letzteres siehe Code)

Delphi-Quellcode:
Function Call(Const S: String): HINSTANCE;
  Var B: Boolean;
    i:  Integer;
    S, Datei, Parameter: String;

  Begin
    SetLength(S, GetSystemDirectory(nil, 0) - 1);
    GetSystemDirectory(PChar(S), Length(S) + 1);
    SetCurrentDirectory(PChar(S));

    B := False;
    i := 0;
    Repeat
      Inc(i);
      While (i <= Length(S)) and (S[i] <> ' ') or B do Begin
        If S[i] = '"' Then B := not B;
        Inc(i);
      End;
      Datei := StringReplace(Copy(S, 1, i - 1), '"', '', [rfReplaceAll]);
      Parameter := Trim(Copy(S, i, Length(S)));
      Result := ShellExecute(Handle, nil, PChar(Datei), PChar(Parameter), nil, SW_SHOW);
    Until not (Result in [ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND]) or (i > Length(S));
  End;
(einfach so dahingeschrieben und ungetestet)

almisoft 11. Dez 2008 23:55

Re: Trennen von Pfad und Parameter
 
Ich habe es inzwischen doch mit CreateProcess geschafft. An CreateProcess kann man ja die ganze Befehlszeile übergeben. Den Parameter setzt man auf nil. Man muss nur beachten, dass man unter Vista die ganze Anwendung elevaten muss, sonst bricht CreateProcess ab. Oder man kapselt das CreateProcess in einer dll (so wie ich es gemacht habe), die dann elevated wird.

almisoft 13. Dez 2008 16:53

Re: Trennen von Pfad und Parameter
 
Liste der Anhänge anzeigen (Anzahl: 1)
na, so ganz doll war die Sache mit CreateProcess dann doch nicht, denn unter Vista (bei einem anderen Vista auch nicht) startet der Prozess im Hintergrund, was natürlich sehr unschön ist.
Wird unter demselben Vista der Prozess mit ShellExecute aufgerufen, erscheint er im Vordergrund und auch die UAC poppt sauber auf. Also nehme ich zum Aufrufen der Deinstallation-Programme doch ShellExecute. Da muss dann doch der Dateiname vom Parameter getrennt werden, was mir aber jetzt dank himitsu sauber gelungen ist.

Ich habe es aber dann doch etwas anders gemacht und ganz so einfach war es auch nicht. Aber es funzt. Das ganze Programm habe ich angehängt. Der interessante Teil ist hier:
Delphi-Quellcode:
// Kommandozeile in Dateinamen und Parameter Splitten
procedure SplitFileAndParam(const Commandline:string; var Filename,Param:string);
const AnzSuffixe=3;
         Suffixe:array[1..AnzSuffixe] of string=('com','exe','bat');
var L,Pathes:TStringList;
    i,j,k,p:integer;
    FilenameConcat,FilenamePath,FilenameSuffix:string;
    Found:boolean;
begin
  // Commandline an Leerzeichen splitten
  L:=Split(CommandLine,' ',true,false);

  // Pfadvariable auslesen und bei ; splitten
  Pathes:=Split(GetEnvironmentVariable('PATH'),';',true,false);
  Pathes.Insert(0,'');

  // Dateiname Stueck fuer Stueck wieder zusammensetzen bis er existiert
  Filename:='';
  Found:=false;
  for i:=0 to L.Count-1 do if not Found then begin
    FilenameConcat:=RemoveQuotes(Trim(FilenameConcat+' '+L[i]));

    // Existiert die bis jetzt zusammengesetzte Datei?
    if FileExists(FilenameConcat) then begin
      Found:=true;
      Break;
    end;

    // mit vorgesetzten Pfaden aus Umgebungsvariablen probieren
    if not Found and (ExtractFileDrive(FilenameConcat)='') then begin
      for j:=0 to Pathes.Count-1 do if not Found then begin
        FilenamePath:=AddBacklash(Trim(Pathes[j]))+FilenameConcat;
        if FileExists(FilenamePath) then begin
          Found:=true;
          Break;
        end;

        // Falls nicht, mit angefuegter Endung COM,EXE,BAT probieren
        if not Found and (ExtractFileExt(FilenamePath)='') then begin
          for k:=1 to AnzSuffixe do begin
            FilenameSuffix:=FilenamePath+'.'+Suffixe[k];
            if FileExists(FilenameSuffix) then begin
              Found:=true;
              Break;
            end;
          end;
        end;

      end;
    end;
  end;

  if Found then begin
    p:=Pos(FilenameConcat,Commandline)+Length(FilenameConcat);
    while (Copy(Commandline,p,1)<>' ') and (p<Length(CommandLine)) do Inc(p);
    Filename:=Trim(Copy(CommandLine,1,p));
    Param:=Trim(Copy(CommandLine,p+1,Length(CommandLine)));
  end else begin
    Filename:='';
    Param:='';
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:02 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz