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 Korrekten Dateinamen auslesen (https://www.delphipraxis.net/71281-korrekten-dateinamen-auslesen.html)

Martin K 12. Jun 2006 15:51


Korrekten Dateinamen auslesen
 
Hi,
ist es irgendwie möglich, den korrekten Dateinamen aus einem String (der z.B. per ShellExecute ausgeführt werden kann) auszulesen?

Mal ein paar Beispiele, was für Strings ich meine:
- Dateiname steht in "Anführungsstrichen"
- hinterm Dateinamen stehen noch Parameter
- Doppel-Slashes \\ sollen ignoriert werden

Gibt es so ne Funktion vielleicht schon :roll:

marabu 12. Jun 2006 19:03

Re: Korrekten Dateinamen auslesen
 
Hi Martin,

ich bin mir nicht sicher, was du mit dem Ignorieren von doppelten backslashes meinst, aber die folgende Funktion liefert dir die Zerlegung einer commandline in einer StringList:

Delphi-Quellcode:
uses
  Classes,
  StrUtils;

function CreateParamStrings(const CommandLine: String): TStrings;
var
  s: String;
  p, pNext: PAnsiChar;
begin
  Result := TStringList.Create;
  p := PChar(CommandLine);
  while p^ <> '' do
  begin
    if p^ <> ' ' then
    begin
      if p^ <> '"' then
      begin
        pNext := AnsiStrScan(p, ' ');
        SetLength(s, pNext - p);
        StrLCopy(PChar(s), p, Length(s));
        p := pNext;
      end else
        s := AnsiDequotedStr(AnsiExtractQuotedStr(p, '"'), '"');
      Result.Add(s);
    end;
    while (p^ <> '') and (p^ = ' ') do
      Inc(p);
  end;
end;
Testen kannst du so:

Delphi-Quellcode:
procedure TDemoForm.TestButtonClick(Sender: TObject);
begin
  with CreateParamStrings('"c:\programme\eigene programme\test.exe" /i /n=123 "a b c"') do
  begin
    ShowMessage(Text);
    Free;
  end;
end;
Grüße vom marabu

mkinzler 12. Jun 2006 19:05

Re: Korrekten Dateinamen auslesen
 
Zitat:

ich bin mir nicht sicher, was du mit dem Ignorieren von doppelten backslashes meinst
Ich glaube er spielt auf die Tatsache an das in c/c++ Backslashes als Steuerzeichen verwendet werden, un deshalb bei Ausgaben diese doppelt angegeben werden müßen:

z.b. c:\\Windows\\datei.txt

Martin K 12. Jun 2006 19:14

Re: Korrekten Dateinamen auslesen
 
Danke :thumb:
Werd wir den Code mal anschauen...

Aber ich dachte da, an irgendeine Funktion, die es vielleicht irgendwo in der ShellAPI oder Windows-Unit gibt...
Es gibt ja auch sowas wie z.B. ExtractFilePath (okay, ist in SysUtils) und da dachte ich, es gäbe vielleicht auch so was, was ich suche...

Wenn Windows einen Befehl zum Ausführen bekommt, muss es den doch irgendwie auch auseinandernehmen:
z.B. einmal die Datei und dann die Parameter, die der Datei übergeben werden...
Wie macht das denn Windows intern???
:gruebel:

Zitat:

Zitat von marabu
Hi Martin,

ich bin mir nicht sicher, was du mit dem Ignorieren von doppelten backslashes meinst, [...]

Naja, mir ist mal aufgefallen wenn ich z.B. in Start -> Ausführen
C:\WINDOWS\system32\\notepad.exe eingebe, dann funzt das ohne Probleme...

@mkinzler:
Keine Ahnung, wie das in c/c++ ist...
Da hab ich noch nie was mit Dateipfaden gemacht.

Edit:
Hab grad festgestellt, bei FileExists klappt's auch mit den Doppel-Slashes.
Allerdings klappt's nicht, wenn der Dateiname in "Anführungsstrichen" steht.
Parameter nach dem Dateinamen gehen natürlich auch nicht.

himitsu 12. Jun 2006 19:30

Re: Korrekten Dateinamen auslesen
 
Zitat:

Zitat von Martin K
Naja, mir ist mal aufgefallen wenn ich z.B. in Start -> Ausführen
C:\WINDOWS\system32\\notepad.exe eingebe, dann funzt das ohne Probleme...

WinNT (also auch XP, wobei anscheinend Win98 damit nicht lar kommmt) irnoriert dieses "\\" ... du kannst also auch einen Dateinamen mit "\\" an ShellExecute übergeben.
Genauso wie Windows auch mit "/" (aus der Linux-Welt) zurechtkommt.

Martin K 12. Jun 2006 19:44

Re: Korrekten Dateinamen auslesen
 
@himitsu:
Na schön, hilft mir aber auch nicht wirklich viel weiter.
Man könnte ja auch per StringReplace ganz einfach \\ durch \ ersetzen...

Aber mir geht es ja eigentlich darum, wie Windows Execute-Befehle verarbeitet.
Da muss es doch auch irgendwie eine fertige Funktion geben, hab aber bis jetzt keine gefunden :roll:

Vielleicht schreib ich mal mein eigentliches Ziel:
Ich will mir alle Autostart-Einträge aus der Registry auslesen und anzeigen lassen.
Damit das ganze schöner aussieht, soll auch zu jedem Programm was im Autostart steht das passende Icon angezeigt werden.
Da aber die Dateinamen der Programme meißtens noch mit irgendwelchen Parametern hinten dran oder mit Anführungsstrichen da stehen (bei einem waren noch die Doppelslashes), ist es doch schwierig den Eintrag aus der Registry einfach so als FileName für die Icons zu verwenden :?

himitsu 12. Jun 2006 20:09

Re: Korrekten Dateinamen auslesen
 
Na wenn es dir nur darum geht, dann sollte das schon ausreichen:
Delphi-Quellcode:
Var i: Integer;
  B: Boolean;
  S, Dateiname, Parameter: String;
Delphi-Quellcode:
S := ...

i := 1;
B := False;
While (i <= Length(S)) and ((S[i] <> ' ') or B) do Begin
  If S[i] = '"' Then B := not B;
  Inc(i);
End;
Dateiname := StringReplace(Trim(Copy(S, 1, i - 1)), '"', '', [rfReplaceAll]);
Parameter := Trim(Copy(S, i + 1, Length(S)));
Im Grunde ist das Leerzeichen das trennzeichen zwischen Dateiname und einzelnen Parametern.
Wobei innerhalb der "" das Leerzeichen mit zum Dateiname/Parameter gehört.

Hab das hier nur mal für den ersten Parameter (also den Dateinamen) verwirklicht ... die Parameter sind also immernoch in einem Gesamtstring enthalten.


So ähnlich wird es auch gemacht, wenn Delphi den übergebenen Parametersting für ParamStr aufteilt.

marabu 12. Jun 2006 20:18

Re: Korrekten Dateinamen auslesen
 
Nur der Vollständigkeit halber:

Delphi-Quellcode:
function CanonicalFileName(fn: TFileName): TFileName;
var
  buf: array [0..MAX_PATH] of Char;
  pc: PChar;
begin
  SetString(Result, PChar(@buf), GetFullPathName(PChar(fn), MAX_PATH, PChar(@buf), pc));
end;
Und weg sind die doppelten (back)slashes.

marabu

Hawkeye219 12. Jun 2006 20:36

Re: Korrekten Dateinamen auslesen
 
@marabu

Gibt es einen besonderen Grund dafür, die Eigenschaft TStringList.DelimitedText nicht zu verwenden?

Delphi-Quellcode:
with TStringList.Create do
begin
  DelimitedText := '"c:\programme\eigene programme\test.exe" /i /n=123 "a b c"';
  ShowMessage(Text);
  Free;
end;
Die von dir schon einmal beschriebene Design-Schwäche in TStringList stört doch nur in dem Fall, wo das Trennzeichen kein Blank ist.

Gruß Hawkeye

Martin K 12. Jun 2006 20:59

Re: Korrekten Dateinamen auslesen
 
Danke :thumb:
Ihr hat euch ja richtig viel Mühe gegeben, war doch nicht nötig gewesen :lol:

Schade, dass es sowas nicht schon fertig gibt, na egal...

Hab jetzt den QT von Hawkeye219 noch etwas ergänzt:
Delphi-Quellcode:
function StrToPath(const s: String): String;
var SL: TStringList;
begin
  if (s<>'') and (s[1]='"') then
  begin
    SL := TStringList.Create;
    try
      SL.DelimitedText := s;
      Result := SL[0];
    finally
      SL.Free;
    end;
  end
  else
    Result := s;
  Result := StringReplace(Result, '\\', '\', [rfReplaceAll]);
end;
@himitsu und marabu:
Hab jetzt von euch nix drin :pale: ,
gibt es evtl. Vorteile in euren Codes gegenüber meinem?

Edit:
Code verändert, dann meckert auch der Compiler nicht mehr.
Funzt übrigens 1A :thumb:

marabu 12. Jun 2006 21:16

Re: Korrekten Dateinamen auslesen
 
Hallo Hawkeye,

das einzige, was dagegen spricht, ist die Berufsehre - wir sollen weder Nebeneffekte erzeugen, noch sollen wir sie in unseren Programmen nutzen. Der Nebeneffekt hier ist, dass der Parser mehrfach aufeinander folgende Blanks wie eines betrachtet, wenn der Delimiter ein Blank ist.

Aber verführerisch einfach ist es schon ...

Gute Nacht

marabu

himitsu 12. Jun 2006 21:18

Re: Korrekten Dateinamen auslesen
 
Delphi-Quellcode:
if (s<>'') and (s[1]='"') then
begin
  SL.DelimitedText := s;
  Result := SL[0];
end
else
  Result := s;
Zitat:

Zitat von Martin K
gibt es evtl. Vorteile in euren Codes gegenüber meinem?

Ja ... der Dateiname muß nicht unbedingt zwischen "" stehen, wenn ein Parameter angehängt wurde,
dieses ist "nur" notwendig, wenn Leerzeichen im Dateinamen sind.

Bei dem Code bleibt der Parameter angehängt, wenn der Dateiname nicht in "" eingeschlossen ist.

Martin K 12. Jun 2006 21:27

Re: Korrekten Dateinamen auslesen
 
Zitat:

Zitat von himitsu
Ja ... der Dateiname muß nicht unbedingt zwischen "" stehen, wenn ein Parameter angehängt wurde,
dieses ist "nur" notwendig, wenn Leerzeichen im Dateinamen sind.

Bei dem Code bleibt der Parameter angehängt, wenn der Dateiname nicht in "" eingeschlossen ist.

Stimmt, Du hast recht :oops:
Mal gucken....

Zitat:

Zitat von marabu
wenn der Delimiter ein Blank ist

Was meint ihr eigentlich mit "blank"?

mkinzler 12. Jun 2006 21:34

Re: Korrekten Dateinamen auslesen
 
Zitat:

Was meint ihr eigentlich mit "blank"?
Das ist englisch für Leerzeichen

Martin K 12. Jun 2006 21:49

Re: Korrekten Dateinamen auslesen
 
@mkinzler:
Dankle!
...wusste ich nich :oops:

So, hier nun mein endgültiger Code, habe mich für himitsu's Methode entschieden:
Delphi-Quellcode:
function StrToPath(const s: String): String;
var i: Integer; b: Boolean;
begin
  i := 1;
  b := False;
  while (i <= Length(s)) and ((s[i] <> ' ') or b) do
  begin
    if s[i] = '"' then
      b := not b;
    Inc(i);
  end;
  Result := StringReplace(Trim(Copy(s, 1, i-1)), '"', '', [rfReplaceAll]);
  Result := StringReplace(Result, '/', '\', [rfReplaceAll]);
  Result := StringReplace(Result, '\\', '\', [rfReplaceAll]);
end;
Sieht ein bisschen komisch aus, mit den ganzen StringReplace's am Schluss.
Aber warum eigentlich nicht...
:)

Hmmm....
Ist doch ein Fehler drin :!:

@himitsu:
Wenn ich einen Dateinahmen ohne " " habe und auch ohne Parameter und der Dateinamen enthält Leertasten...

himitsu 13. Jun 2006 07:39

Re: Korrekten Dateinamen auslesen
 
[quote="Martin K"]Du kannst zwar alle StringReplace zusammensetzten, aber ersten kommes etwa auf's Selbe raus und zweitens ist das bestimmt nicht gerade übersichtlich.

Zitat:

Zitat von Martin K
Hmmm....
Ist doch ein Fehler drin :!:

Und wie äußert der sich?

Zitat:

Zitat von Martin K
@himitsu:
Wenn ich einen Dateinahmen ohne " " habe und auch ohne Parameter und der Dateinamen enthält Leertasten...

Das geht nicht, ein Dateiname/Pfad mit Leerzeichen muß in "" stehen, wennn er zusammen mit Parametern übergeben werden kann.

Denn nur zwischen zwei " ist das Leerzeichen ein Leerzichen ... außerhalb ist es ein Trennzeichen.

Also wenn du es ohne die " übergibst, dann wird er an den Leerzeichen getrennt,
- Übergabe: TestDatei mit Leerzeichen.irgendwas der Paramter Nocheiner
- Dateiname: TestDatei
- Parameter 1: mit
- Parameter 2: Leerzeichen.irgendwas
- Parameter 3: der
- Parameter 4: Paramter
- Parameter 5: Nocheiner
statt
- Übergabe: "TestDatei mit Leerzeichen.irgendwas" "der Paramter" Nocheiner
- Dateiname: TestDatei mit Leerzeichen.irgendwas
- Parameter 1: der Paramter
- Parameter 2: Nocheiner

Martin K 13. Jun 2006 13:03

Re: Korrekten Dateinamen auslesen
 
Zitat:

Zitat von himitsu
Das geht nicht, ein Dateiname/Pfad mit Leerzeichen muß in "" stehen, wennn er zusammen mit Parametern übergeben werden kann.

Ja, das ist mir schon klar.

Habe einen Dateinamen ohne " ", mit Leerzeichen aber auch:
Zitat:

Zitat von Martin K
Wenn ich einen Dateinahmen ohne " " habe und auch ohne Parameter und der Dateinamen enthält Leertasten...

Und da geht es!!!!

Beispiel:
C:\Programme\Intel\Intel Matrix Storage Manager\IAAnotif.exe

Das funktioniert :!:


Aber ich habe das schon anders gelöst:
Wie gesagt, es ging ja um die Icons der Dateien.
Ich prüfe einfach zuerst den Originaldateinamen, erst wenn mir der kein gültiges Icon zurückliefert (HICON = 0), dann wende ich den Code an.

Dazu habe ich die letzten beiden StringReplace aus Beitrag #15 noch vor den restlichen Code gesetzt und dann nochmals auf ein gültiges Icon überprüft, denn ein Dateiname ohne " " und ohne Parameter kann ja auch Doppelslashes \\ beinhalten :wink:

himitsu 13. Jun 2006 13:29

Re: Korrekten Dateinamen auslesen
 
Zitat:

Zitat von Martin K
Das funktioniert :!:

Das funktioniert eben nicht, oder doch ...

es kommt halt darauf an, wie dieser String definiert ist ... bei dem was in der Registry (Autostart) steht, muß jeder Dateiname, welcher Leerzeichen enthält, in " eingeschlossen sein.

Wärend andere Dinge (z.B. die Funktionen, womit man z.B. sich das Icon der Datei zurückgeben lassen kann, nur einen reinen Dateinamen haben wollen und das ohne die ".

Denn wenn in dem String nur der Name enthalten ist und dort Parameter "verboten" sind, dann braucht man diese " nicht, da sie nur in den Strings wo Parameter enthalten sein können zur Kennzeichnung diehnen, ob ein Leerzeichen ein Leerzeichen, oder ein Trennzeichen ist.

Martin K 13. Jun 2006 14:33

Re: Korrekten Dateinamen auslesen
 
Zitat:

Zitat von himitsu
Denn wenn in dem String nur der Name enthalten ist und dort Parameter "verboten" sind, dann braucht man diese " nicht, da sie nur in den Strings wo Parameter enthalten sein können zur Kennzeichnung diehnen, ob ein Leerzeichen ein Leerzeichen, oder ein Trennzeichen ist.

Aha.

Zitat:

Zitat von himitsu
es kommt halt darauf an, wie dieser String definiert ist ... bei dem was in der Registry (Autostart) steht, muß jeder Dateiname, welcher Leerzeichen enthält, in " eingeschlossen sein.

Das stimmt aber nicht :warn:
(s. erstes Zitat) :arrow: ist auch in der Registry bei den Autostart-Programmen möglich :!:

himitsu 13. Jun 2006 14:41

Re: Korrekten Dateinamen auslesen
 
Na ja, denn liegt es halt wohl daran, dat Windows hier mal wieder die Fehler der Pogrammierer behebt.
(wenn ich windows wäre, dann würde ich dann ganz einfach nichts machen)

Es ist dennoch nicht sehr gut, wenn man irreguläre "Fehler" ausnutzt ... erstens ist es nicht gerade schön und dann könnte M$ auch irgendwann mal diese "Fehlerkorrektur" weglassen ;)

Martin K 13. Jun 2006 14:54

Re: Korrekten Dateinamen auslesen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Naja, ich hab diese Einträge ja nicht selber in die Registry geschrieben ...
Kann ich ja nix dafür, wenn jedes Programm so seine eigene Spezial-Pfadangabe hat :lol:

Ich will halt nur, dass mein Programm mit möglichst allen Pfadangaben in der Registry klar kommt.

Hier mal ein Screenshot von meiner Registry: Die wenigsten sind mit "" versehen, aber es funktionieren ALLE Pfadangaben (getestet!)
Und dann noch ein Screeny, wie es dann in meinem Programm aussieht:

himitsu 13. Jun 2006 15:16

Re: Korrekten Dateinamen auslesen
 
Na bis auf IAAnotif und SiXPack halten sich ja eigentlich alle an die Konventionen.

Ich möchte jetzt aber nicht wissen, was dann in den Pogrammen noch so los ist, wenn die schon bei so'ner einfachen Sache Mist bauen.

(Mich wunder eigentlich nur der doppelte \ bei Nero :shock: )

Martin K 13. Jun 2006 15:29

Re: Korrekten Dateinamen auslesen
 
Zitat:

Zitat von himitsu
Na bis auf IAAnotif und SiXPack halten sich ja eigentlich alle an die Konventionen.

Ja, stimmt.

Das mit SiXPack ist sowieso merkwürdig:
Leertaste im Dateinem, ohne "" und dann noch Parameter?
Das ist von meiner Soundkarte, aber das Symbol wird bei jedem Start in der Taskleiste angezeigt.

Merkwürdig ist auch noch:
Die Datei gibt es gar nicht, sie heißt nur SiXPack.exe

Zitat:

Zitat von himitsu
Ich möchte jetzt aber nicht wissen, was dann in den Pogrammen noch so los ist, wenn die schon bei so'ner einfachen Sache Mist bauen.

Wie ist das denn jetzt gemeint?
Wie gesagt, dass eine ist von der Soundkarte und das andere - keine Ahnung, irgendwas von Intel. War schon von Anfang an drin.

Zitat:

Zitat von himitsu
(Mich wunder eigentlich nur der doppelte \ bei Nero :shock: )

Hmm...
Also ich hab den nicht da hin gemacht.
Funzt aber trotzdem!

Vielleicht stell ich mein Programm ja mal unter Freeware zur Verfügung.
Oder gibt's da schon so was?


//Edit:
Achso, jetzt verstehe ich das auch mit SiXPack:
Windows akzeptiert sogar, wenn ich .exe als Endung weglasse!
z.B.:
C:\WINDOWS\system32\notepad
oder:
C:\WINDOWS\system32\SiXPack

Das heißt, es wird SiXPack mit den Parametern 5.1+.exe /minimize gestartet!


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:07 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-2025 by Thomas Breitkreuz