AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

PIDL und der Font-Ordner - geht nicht

Ein Thema von MicMic · begonnen am 11. Mär 2020 · letzter Beitrag vom 16. Mär 2020
Antwort Antwort
Seite 1 von 2  1 2      
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#1

PIDL und der Font-Ordner - geht nicht

  Alt 11. Mär 2020, 13:48
Hallo,
für manche Operationen konvertiere ich ein Pfad+Dateiname zu ein PIDL Dingsbums.
Delphi-Quellcode:
function PathToPIDL(APath: WideString): PItemIDList;
var
  Desktop: IShellFolder;
  pchEaten, dwAttributes: ULONG;
begin
  Result := nil;
  SHGetDesktopFolder(Desktop);
  dwAttributes := 0;
  if Assigned(Desktop) then
  begin
    if Desktop.ParseDisplayName(0, nil, PWideChar(APath), pchEaten, Result, dwAttributes) <> NOERROR then
      Result := nil;
  end
end;
Dies geht soweit aber im Font-Ordner (C:\Windows\Fonts). Also wenn ich dort im Ordner eine Schriftartdatei auf die Funktion feuere, bekomme ich bei "ParseDisplayName" einen Fehlercode (E_INVALIDARG) zurück. Schlimmer noch, dass "ParseDisplayName" hier dann noch zu lange braucht und meine Routine abbremst. Der Ordner wird auch von Windows irgendwie speziell behandelt. Auf eine Schriftartdatei kann man z.B. kein Eigenschaftsdialog anzeigen lassen. Dies geht erst, wenn man eine Datei herauskopiert. Alles irgendwie mal wieder nicht zu verstehen. Hat jemand Rat?

Gruß Mike
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: PIDL und der Font-Ordner - geht nicht

  Alt 11. Mär 2020, 14:00
SHGetKnownFolderPath mit FOLDERID_Fonts sollte klappen.


/edit
upps, sorry, hab jetzt erst verstanden was du vorhast, vergiss das obige, tut mir leid!
Gruß vom KodeZwerg

Geändert von KodeZwerg (11. Mär 2020 um 14:04 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: PIDL und der Font-Ordner - geht nicht

  Alt 11. Mär 2020, 14:29
Hab vielleicht doch noch was passendes... ILCreateFromPath

Delphi-Quellcode:
// falls das Windows.pas nicht hat:
function ILCreateFromPath(pszPath: LPCWSTR): PItemIDList; stdcall
external shell32 name 'ILCreateFromPathW';

// der eigentliche aufruf:
PathPIDL := ILCreateFromPath(pWideChar(Path));
Zitat:
Call ILFree to release the ITEMIDLIST when you are finished with it.
Gruß vom KodeZwerg

Geändert von KodeZwerg (11. Mär 2020 um 14:33 Uhr)
  Mit Zitat antworten Zitat
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: PIDL und der Font-Ordner - geht nicht

  Alt 11. Mär 2020, 23:13
"ILCreateFromPath" ist vorhanden aber funktioniert leider nicht.
Ich bekomme auch NIL zurück. Was nicht unbedingt das schlimmste wäre*, aber die Funktion bremst dann alles aus. Das ist dann nicht so toll.

Es geht mir jedenfalls um folgendes.
Ich prüfe mit "ShellFolder.GetAttributesOf" auf die Werte "SFGAO_LINK" und "SFGAO_SHARE".

SFGAO_SHARE nur auf Ordner (ist das richtig?).
SFGAO_LINK kann auch eine Datei sein (z.B. mit MKLINK symdatei.txt richtigedatei.txt). Kann man sogar im besagtem Font-Order (c:\windows\Fonts) erstellen.

So prüfe ich:
Delphi-Quellcode:
function IsLink(aPIDL: PItemIDList): Boolean;
var
  Attrs: DWord;
  ItemIDList: PItemIDList;
  ShellFolder: IShellFolder;
begin
  Result := False;
  if fjLinkOverlay = False then Exit;
  if Succeeded(SHBindToParent(aPidl, IID_IShellFolder, Pointer(ShellFolder), ItemIDList)) then
  begin
    attrs := SFGAO_LINK;
    ShellFolder.GetAttributesOf(1, ItemIDList, Attrs);
    if Attrs and SFGAO_LINK <> 0 then result := true else result := false;
  end else result := false;
end;
Also brauche ich ja ein PathToPidl. Und in diesem Font-Ordner geht das nicht.

*Ich will jetzt auch nicht anfangen mit "if path<>'fontordner'" zu arbeiten. Evtl. gibt es ja noch mehrere Windows-Ordner die einem das leben schwer machen. Oder es kommen irgendwann Ordner dazu, die irgendwelche Sonderwünsche beanspruchen und mein PathToPidl (ob meine Funktion oder die "ILCreateFromPath") die Routine bzw. mein Programm ausbremst. Also eine IF-Prüfung wäre nur der richtige weg, wenn ich den Ordner selbst identifizieren könnte, sprich ob's ein normaler Ordner ist oder ein Ordner mit extrawünschen

Der Ordner "Downloaded Program Files" in (c:\Windows) geht z.B. auch nicht, wie ich gerade festgestellt habe. Also beides System-Ordner. Dachte schon die Lösung gefunden zu haben, warum es nicht geht. Jedoch ist "C:\windows\media" auch ein System-Ordner aber hier geht es wieder, ein Pfad+Datei ins PIDL zu bekommen. Also eine IF-Prüfung auf dieses System Attribut kann ich hier auch nicht machen.
  Mit Zitat antworten Zitat
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#5

AW: PIDL und der Font-Ordner - geht nicht

  Alt 11. Mär 2020, 23:30
Ich kann zum Glück eine mit MKLINK Symdatei anders prüfen.
Mit dem "FILE_ATTRIBUTE_REPARSE_POINT" kann ich ohne PIDL in solchen Ordnern (die mit PIDL mein Zeug ausbremsen) die Dateien identifizieren.

Trotzdem brauche ich eigentlich auch für SHGetFileInfo ein PIDL. Also das Problem besteht eigentlich weiterhin in diesen Ordnern. Leider bekommt man manchmal ein falsches IconIndex von SHGetFileInfo (ohne PIDL). Hier und da fehlen die Doppelpfeile bei komprimierten Dateien. Selten aber manchmal fehlen die einfach. Dagegen bekomme ich immer das richtige IconIndex (bei komprimierten Dateien) wenn ich SHGetFileInfo mit PIDL nutze.

Also ich muss irgendwie an ein PathToPidl ran. Auch in diesen komischen Ordnern.
  Mit Zitat antworten Zitat
Alt 12. Mär 2020, 02:22     Erstellt von Frühlingsrolle
Dieser Beitrag wurde von Daniel gelöscht. - Grund: Verdacht auf SPAM und den damit verbundenen verschwenderischen Umgang von wertvollen Bits und Bytes
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: PIDL und der Font-Ordner - geht nicht

  Alt 12. Mär 2020, 08:14
Ich habe gestern rumprobiert. Vieeeel rumprobiert.
Das phänomen tritt nur auf wenn du es auf dateien loslässt, nicht auf den ordner wie die topic es benennt.
Das ausbremsen konnt ich nicht verhindern, nichts desto trotz hab ich 'ne mini "verschlimmbesserung" eingebaut.
Delphi-Quellcode:
uses
  System.IOUtils, Winapi.ShlObj, Winapi.ActiveX;

function PathToPidl(const Path: String; out Fallback: Boolean): PItemIdList;
var
  DesktopFolder: IShellFolder;
  dummy: Cardinal;
begin
  Fallback := False;
  Result := nil;
  if (TDirectory.Exists(path, False) or TFile.Exists(path, False)) then
    if Succeeded(SHGetDesktopFolder(DesktopFolder)) then
      if DesktopFolder.ParseDisplayName(0, nil, PChar(Path), dummy, Result, dummy) <> NOERROR then
        if DesktopFolder.ParseDisplayName(0, nil, PChar(ExtractFilePath(Path)), dummy, Result, dummy) = NOERROR then
          Fallback := True;
end;
Aufruf dann so:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
   PIDL: PItemIDList;
   PathName: array[0..MAX_PATH - 1] of Char;
   checker: Boolean;
   path: String;
begin
  path := 'c:\windows\fonts\arial.ttf';
  Memo1.Clear;

  Memo1.Lines.Add('Führe "PathToPIDL(path);" aus.');
  PIDL := PathToPIDL(path, checker);
  if (Assigned(PIDL)) then
    begin
      if SHGetPathFromIDList(PIDL, @PathName) then
        begin
          Memo1.Lines.Add('PathToPIDL: ' + PathName);
          if checker then
            Memo1.Lines.Add('Fallback zum Ordnernamen wurde genutzt.');
         Memo1.Lines.Add('PathToPIDL war ok.');
        end;
      ILFree(PIDL);
    end
    else
      Memo1.Lines.Add('PathToPIDL hat nicht geklappt.');
end;
hier meine anderen versuche, mit ordner klappt alles, mit dateien im fonts ordner versagen alle...
Delphi-Quellcode:
// der klassiker
function PathToPIDL(const Path: String): PItemIDList;
var
  Attrs: DWORD;
begin
  Result := nil;
  try
    CoInitialize(nil);
(*    if (SHParseDisplayName(PChar(Path), nil, Result, 0, Attrs) = S_OK) then
      if not Assigned(Result) then
        Result := nil;*)

    SHParseDisplayName(PChar(Path), nil, Result, 0, Attrs);
  finally
    CoUnInitialize();
  end;
end;

// das was ich oben beschrieben hatte
function PathToPIDL(const Path: String): PItemIDList;
begin
  Result := ILCreateFromPath(PChar(Path));
end;

// deine version etwas entschlackt
function PathToPIDL(const Path: String): PItemIdList;
var
  DesktopFolder: IShellFolder;
  dummy: Cardinal;
begin
  if Succeeded(SHGetDesktopFolder(DesktopFolder)) then
    if DesktopFolder.ParseDisplayName(0, nil, PChar(Path), dummy, Result, dummy) <> NOERROR then
      Result := nil
end;
Ich werd noch bissl rumprob'sen... bye
Gruß vom KodeZwerg

Geändert von KodeZwerg (12. Mär 2020 um 10:45 Uhr)
  Mit Zitat antworten Zitat
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#7

AW: PIDL und der Font-Ordner - geht nicht

  Alt 12. Mär 2020, 13:14
Danke für die Mühe
Wie du siehst, ganz und gar nicht einfach zu lösen.
Naja, einfach ist es, wenn man weiß wie *lach

Für "ParseDisplayName" ist ja noch beschrieben (mit Google Übersetzer):

LPWSTR
Da jeder Shell-Ordner seine eigene Analysesyntax definiert, kann die Form, die diese Zeichenfolge annehmen kann, variieren.

Unter Bemerkungen noch:
Einige Shell-Ordner implementieren möglicherweise nicht IShellFolder : ParseDisplayName. Jeder Ordner, der dies tut, definiert seine eigene Analysesyntax.

Hört sich irgendwie an, als ob man da mit dem Parameter "IBindCtx" was machen muss?

Eines habe ich mal getestet:
Anstatt "C:\Windows\Fonts\fontname.ttf" habe ich "\\COMPUTERNAME\Windows\Fonts\fontname.ttf" genommen. Der erste Zugriff dauert lange (wegen dem Computernamen) aber danach macht "ParseDisplayName" oder auch "ILCreateFromPath" keine Bremse mehr. Ist jetzt zwar auch nicht die Lösung, da weiterhin kein PIDL erzeugt wird und "ParseDisplayName" z.B. hier auch "E_INVALIDARG" zurück liefert.

Das Problem werden wohl viele haben, die mit PIdl/SHGetFileInfo etc. arbeiten. Aber es nicht unbedingt merken. Wer kommt schon auf die Idee, dass manche Dateizugriffe in speziellen Verzeichnissen Probleme machen, wenn es sonst fast überall funktioniert. Doofe Sache aber auch *schnief*
  Mit Zitat antworten Zitat
Alt 12. Mär 2020, 21:15     Erstellt von Frühlingsrolle
Dieser Beitrag wurde von Daniel gelöscht. - Grund: Verdacht auf SPAM und den damit verbundenen verschwenderischen Umgang von wertvollen Bits und Bytes
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#8

AW: PIDL und der Font-Ordner - geht nicht

  Alt 12. Mär 2020, 21:56
Was genau möchtest du vom Font-Ordner und einer beliebigen Font-Datei wissen?
Es geht weniger um den Font-Ordner. Eher geht's darum, dass ich diesen Inhalt genauso verarbeiten kann, wie andere Ordner auch. Und dazu brauche ich eigentlich ne PIDL zu den einzelnen Dateien in diesem Ordner. Es müssen dort ja nicht unbedingt nur Schriftdateien vorhanden sein. Jeder Benutzer kann hier alle mögliche Dateien ablegen. Deshalb muss ich diesen Ordner ganz normal betrachten und je nach Anwendung/Zweck normale Dateioperationen durchführen können. Mal ein Dateistatus, mal ein Symbol, mal zusätzliche Overlays, zusätzliche Dateiinfos... nicht Dateityp bezogen. Was inzwischen auch kein Problem ist, wenn es sich um ein normalen Ordner handelt. Aber auch der Ordner "Downloaded Program Files" im Windows Verzeichnis verhält sich genauso. Bestimmt gibt es noch weitere Ordner (noch nicht weiter nachgeschaut) die ne Extrawurst benötigen.

Der Explorer selbst behandelt die beiden genannten Ordner auch etwas anders. Im Font-Ordner kann z.B. zu einer Datei kein Eigenschafts-Dialog angezeigt werden und im "Downloaded Program Files" werden vom Explorer keine Inhalte (Dateien) angezeigt, auch wenn Dateien extern (mit anderer Software) dort hineinkopiert worden sind.

Wenn's virtuelle Ordner wären und hier Windows sein Ding macht, würde ich es ja verstehen aber es sind doch ganz normale Verzeichnisse.
  Mit Zitat antworten Zitat
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#9

AW: PIDL und der Font-Ordner - geht nicht

  Alt 12. Mär 2020, 23:15
Wenn ich nicht gerade falsch schauen, hab ich's hinbekommen.
Also hier (noch nicht verschönert/optimiert usw):
Delphi-Quellcode:
function PathToPIDL(APath: WideString;FA:Cardinal): PItemIDList;
var
  Desktop: IShellFolder;
  pchEaten, dwAttributes: ULONG;
  kk : hresult;
  pbc : IBindCtx;
  w32fd : TWin32FindData;
  ifs : TFileSystemBindData;
  r : HResult;
begin
  Result := nil;
  SHGetDesktopFolder(Desktop);
  dwAttributes := 0;
  ZeroMemory(@w32fd, Sizeof(TWin32FindData));
             w32fd.dwFileAttributes := FA;
             ifs := TFileSystemBindData.Create;
             ifs.SetFindData(w32fd);
             r := CreateBindCtx(0, pbc);
             r := pbc.RegisterObjectParam(STR_FILE_SYS_BIND_DATA, ifs);
  if Assigned(Desktop) then
  begin
     kk:= Desktop.ParseDisplayName(0, pbc, PWideChar(APath), pchEaten, Result, dwAttributes);
     if kk <> NOERROR then
    begin
      Result := nil;
      f.Caption := APath+' '+inttostr(kk);
    end
  end
end;
Ich übergebe Pfad+Datei + Dateiattribute der Datei.
Was ich da mache, ist mir nicht so ganz klar (noch nicht) aber habe aus dem Netz was zu diesem "IBindCtx" gefunden und dachte mir, ich probiere das mal aus. So scheint es wohl zu funktionieren und ich messe keine Bremse. Na bestimmt entdecke ich wieder andere Probleme *lol … mal schauen.

Jedoch kann ich mit diesem PIDL nicht auf SFGAO_LINK prüfen. SFGAO_SHARE geht dann wiederum (z.B. Ordner C:\Users).

Hier dazu zwei Funktionen, die recht ähnlich sind. Warum geht SFGAO_SHARE und SFGAO_LINK nicht?
Delphi-Quellcode:
function IsShare(aPIDL: PItemIDList): Boolean;
var
  Attrs: DWord;
  ItemIDList: PItemIDList;
  ShellFolder: IShellFolder;
begin
  Result := False;
  if fjShareOverlay = False then Exit;
  if Succeeded(SHBindToParent(aPidl, IID_IShellFolder, Pointer(ShellFolder), ItemIDList)) then
  begin
    attrs := SFGAO_SHARE;
    ShellFolder.GetAttributesOf(1, ItemIDList, Attrs);
    if Attrs and SFGAO_SHARE <> 0 then result := true else result := false;
  end else result := false;
end;

function IsLink(aPIDL: PItemIDList): Boolean;
var
  Attrs: DWord;
  ItemIDList: PItemIDList;
  ShellFolder: IShellFolder;
begin
  Result := False;
  if fjLinkOverlay = False then Exit;
  if Succeeded(SHBindToParent(aPidl, IID_IShellFolder, Pointer(ShellFolder), ItemIDList)) then
  begin
    attrs := SFGAO_LINK;
    ShellFolder.GetAttributesOf(1, ItemIDList, Attrs);
    if Attrs and SFGAO_LINK <> 0 then result := true else result := false;
  end else result := false;
end;
Für SFGAO_LINK kann ich stattdessen auf das Attribut "FILE_ATTRIBUTE_REPARSE_POINT" (TWin32FindData.dwFileAttributes) prüfen. Trotzdem verstehe ich noch nicht, warum die Funktion "IsLink" mit dem neuen PIDL nicht geht.
  Mit Zitat antworten Zitat
Alt 13. Mär 2020, 02:48     Erstellt von Frühlingsrolle
Dieser Beitrag wurde von Daniel gelöscht. - Grund: Verdacht auf SPAM und den damit verbundenen verschwenderischen Umgang von wertvollen Bits und Bytes
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: PIDL und der Font-Ordner - geht nicht

  Alt 13. Mär 2020, 08:08
Ich bin dem Problem einen Schritt näher gekommen indem ich mir einen auf PIDL's basierten Explorer nachgebastelt habe.
Das "Geheimnis" ist, das im Fonts Ordner abgelegte Dateien von Windows anders angesprochen werden.
Mein Anhang sagt mehr als tausend Worte, wie man allerdings von den Objekten wiederum einen Dateinamen zaubert bleibt mir noch verborgen.

Nun zu Deinem Eigenschaften-Dialog, hier ist ein getesteter Kode der den Standard Windows Eigenschaften Dialog provoziert.

Delphi-Quellcode:
procedure PropertiesDialog(const Path: string); overload;
var
  SEI: TShellExecuteInfo;
begin
  FillChar(SEI, SizeOf(SEI), 0);
  SEI.cbSize := SizeOf(SEI);
  SEI.lpFile := PChar(Path);
  SEI.lpVerb := 'properties';
  SEI.fMask := SEE_MASK_INVOKEIDLIST;
  ShellExecuteEx(@SEI);
end;

procedure PropertiesDialog(const PIDL: PItemIDList); overload;
var
  SEI: TShellExecuteInfo;
  Path: array[0..MAX_PATH - 1] of WideChar;
begin
  if SHGetPathFromIDList(PIDL, @Path) then
    begin
      FillChar(SEI, SizeOf(SEI), 0);
      SEI.cbSize := SizeOf(SEI);
      SEI.lpFile := PChar(String(Path));
      SEI.lpVerb := 'properties';
      SEI.fMask := SEE_MASK_INVOKEIDLIST;
      ShellExecuteEx(@SEI);
    end;
end;
Miniaturansicht angehängter Grafiken
screenshot-12_03.png  
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 14:18 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