Entwickler-Ecke

Windows API - Icons und Dateitypen ermitteln


schitho - Mo 30.06.03 22:16
Titel: Icons und Dateitypen ermitteln
Hi,


ich steh vor folgendem Problem:

Ich möchte ein kleines FTP-Programm schreiben, das 2 VirtualTreeViews verwendet:

Links sollen die Lokalen-Dateien und
rechts die Remote-Dateien angezeigt werden.

Die Anzeige soll in einer Baumstruktur erfolgen, in der neben dem Namen, die Dateigröße, das Datum auch noch der Dateityp und das Icon angezeigt werden soll.

Wie komm ich nun zu den Icons und den Dateitypen für die Lokalen- und die Remoten-Dateien. Ich weiß, dass ich über


Delphi-Quelltext
1:
2:
3:
4:
if SHGetFileInfo(PChar(Filename), 0, Info, SizeOf(Info), SHGFI_TYPENAME) <> 0 then
  Result := Info.szTypeName
else
  Result := '';


den Typ auslesen könnte. Allerdings lese ich hier nur den Typ der gerade angezeigten Datei aus.

Am Remote-Server geht das aber wohl nicht. :(

Daher wäre meine Idee, dass ich zuerst alle Dateitypen und Icons lokal auslese (also auch solche die ich gar nicht anzeige) und aufgrund dieses "Wissens", dann die Typen und Icons auch Remote zuordne.

Habt Ihr eine Idee wie ich sowas realisieren könnte???? :?

Danke für Eure Hilfe


ErnestoChe - Di 01.07.03 07:58

Hi,

schau mal hier [http://www.delphi-forum.de/viewtopic.php?t=13290] nach. Da ist im ersten Post von mir Code dabei, wie man das mit den Datei-Icons macht.

MFG

- Ernesto -


Delete - Di 01.07.03 10:29

Remote wird es nicht gehen, da du nicht weißt mit was die Programme verknüft sind. Wahrscheinlioch mit nichts, da es wohl Windows-Anwendungen sind und es wahrscheinlich bei dir Windows-Anwendungen sein werden, es sich aber bei dem Server bei 90% um ein Linux-System handeln wird.


schitho - Di 01.07.03 20:10

Es ist mir klar, dass es Remote nicht geht.

Trotzdem such ich eine Möglichkeit alle Dateitypen mit den dazugehörigen Icons auszulesen.

Im Explorer kann man sich ja auch unter Extras|Ordneroption|Dateitypen alle Dateitypen inkl. Icons anzeigen lassen. Diese würde ich gern mit Delphi auslesen, so dass ich zu den jeweiligen Dateitypen Lokal und Remote die passenden Icons und Dateitypen anzeigen kann.

Wäre ja blöd, wenn ich Lokal und Remot ich andere Icons verwenden würde, bei den gleichen Dateitypen.

Habt Ihr eine Idee, wie ich nun diese Dateitypen auslesen kann?


schitho - Di 01.07.03 22:48

Ich glaub ich hab selbst die Lösung fast gefunden (durch intensives Stöbern im Internet) :D

Zuerst lese alle Icons in eine ImageListe:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.FormCreate(Sender: TObject);
var
  SysIL : uint;
  SFI : TSHFileInfo;
begin
  SysIL := SHGetFileInfo(''0, SFI, SizeOf(SFI), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  if SysIL <> 0 then begin
    SmallImages.Handle := SysIL;
    SmallImages.ShareImages := TRUE;
  end;
  Form1.VST.Images:=SmallImages;
end;


Dann ermittle ich mittels


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function GetIconIndex(const AFileName: string;
  Attrs: DWORD): integer;
var
  SFI : TSHFileInfo;
begin
  SHGetFileInfo(PChar(AFileName), Attrs, SFI, SizeOf(TShFileInfo),
                SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES);
  Result := SFI.iIcon;
end;


für die jeweilige Datei den Index.

Einziger Nachteil: Für Ordner bekomm ich so scheinbar kein Icon geliefert.

Daher meine Frage: Wie bekomm ich das Icon von einem Ordner???


ErnestoChe - Mi 02.07.03 08:16

Hi,

hast Du meinen Post durchgelesen? Damit geht das.

MFG

- Ernesto -


schitho - Mi 02.07.03 21:25

Hi,

ähhhmm. Hab es schon gelesen, aber komm trotzdem nicht weiter. Oder ich seh den Wald vor lauter Bäume nicht :oops:

Ich gehe momentan wie folgt vor:


Ich lese alle Icons in eine ImageList ein:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.FormCreate(Sender: TObject);
var
  SysIL : uint;
  SFI : TSHFileInfo;
begin
  SysIL := SHGetFileInfo(''0, SFI, SizeOf(SFI), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  if SysIL <> 0 then begin
    SmallImages.Handle := SysIL;
    SmallImages.ShareImages := TRUE;
  end;  
  Form1.VST.Images:=SmallImages;
end;



Ich verwende eine Funktion zum Auslesen des IconIndex:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function GetIconIndex(const AFileName: string; Attrs: DWORD): integer;
var
  SFI : TSHFileInfo;
begin
  SHGetFileInfo(PChar(AFileName), Attrs, SFI, SizeOf(TShFileInfo),
                SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES);
  Result := SFI.iIcon;
end;



und zum Auslesen des DateiTyps:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function GetFileTyp(const AFileName: string): string;
var
  SFI : TSHFileInfo;
begin
    SHGetFileInfo(PChar(AFileName), 0, SFI, SizeOf(TShFileInfo),
         SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES);
    Result:= SFI.szTypeName
end;



Zum Einlesen des Verzeichnisses verwende ich folgende Prozedur:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
procedure VerzeichnisEinlesen(VerzName, filter:string);
var 
    Info    : TSHFileInfo;
    SR      : TSearchRec;
    TreeData: TTreeData;
    Node : PVirtualNode;
begin
  if VerzName[length(VerzName)]<>'\' then
    VerzName:=VerzName+'\';
  if filter='' then filter:='*.*';
  with Form1 do begin
    VST.BeginUpdate;
    VST.Clear;
    VST.NodeDataSize:=SizeOf(TTreeData);
    if FindFirst(VerzName+filter,faAnyFile  ,SR)=0 then begin
      repeat
        if (length(SR.Name)>0and ((SR.Name <> '.'and (SR.Name <> '..')) then begin
          if (LowerCase(SR.Name)<>'desktop.ini'and (LowerCase(SR.Name)<>'recycled'then
          begin
            TreeData.FCaption:=SR.Name;
            TreeData.FColumn1:='Bild-Index ' + IntToStr(GetIconIndex(SR.Name,FILE_ATTRIBUTE_NORMAL ));
            TreeData.Image:=GetIconIndex(SR.Name,FILE_ATTRIBUTE_NORMAL );
            TreeData.Typ:= GetFileTyp(SR.Name);
            Node:=VST.FocusedNode;
            AddVSTStructure(VST,Node,TreeData);
          end
        end;
      until FindNext(SR)<>0;
      FindClose(SR);
    end;
    VST.EndUpdate;
  end;
end;


Vollständigkeitshalber sei noch erwähnt, dass ich die Komponenten VirtualTreeView [http://www.delphi-gems.com/VirtualTreeview/] verwende. Zum Hinzufügen der Nodes gibt es folgende Funktion:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function AddVSTStructure(AVST: TCustomVirtualStringTree; ANode: PVirtualNode;
  ARecord: TTreeData): PVirtualNode;
var
  Data: PTreeData;
begin
  Result:=AVST.AddChild(ANode);
  Data:=AVST.GetNodeData(Result);
  Avst.ValidateNode(Result, False);
  Data^.FCaption:=ARecord.FCaption;
  Data^.FColumn1:=ARecord.FColumn1;
  Data^.Typ:=ARecord.Typ;
  Data^.Image:=ARecord.Image;
end;



Mit VerzeichnisEinlesen('c:','*.*') lese ich das Verzeichnis von c: ein.

Die Icons und Typen, werden für die Dateitypen richtig angezeigt. Allerdings erkennt er Ordner nicht richtig, da weder das richtige Icon noch der richtige Typ ermittelt wird.

Wie muss ich meinen Code ändern, dass auch Ordner richtig angezeigt werden?


schitho - Mi 02.07.03 22:57

Hab den Fehler selbst gefunden :P

Es lag an SHGFI_USEFILEATTRIBUTES :roll:

Nachdem ich dieses Attribut entfernt habe, hat er auch die Ordner angezeigt.

Der Nachteil darf natürlich auch nicht verschwiegen werden:

Durch SHGFI_USEFILEATTRIBUTES ist es möglich auch die Icons bzw. den Dateityp für nicht am PC vorhandene Dateien anzuzeigen. :roll:

Daher braucht man es nur, wenn man auch Dateien auf fremden Servern (z.B. FTP) anzeigen lassen möchte.


Tino - Do 03.07.03 07:57

schitho hat folgendes geschrieben:
Durch SHGFI_USEFILEATTRIBUTES ist es möglich auch die Icons bzw. den Dateityp für nicht am PC vorhandene Dateien anzuzeigen.

Wie soll denn das bitte funktionieren? Wenn bei mir kein Delphi installiert wäre woher sollte dann mein Windows wissen vorfür die Dateiendung PAS steht und welches Icon dafür angezeigt werden soll?

Gruß
Tino


schitho - Do 03.07.03 08:32

Hi,

verwendest Du

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function GetIconIndex(const AFileName: string; Attrs: DWORD): integer; 
var 
  SFI : TSHFileInfo; 
begin 
  SHGetFileInfo(PChar(AFileName), Attrs, SFI, SizeOf(TShFileInfo), 
                SHGFI_SYSICONINDEX); 
  Result := SFI.iIcon; 
end;


bekommst Du nur den Icon-Index, wenn es die Datei gibt.

Änderst Du die Funktion jedoch in


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function GetIconIndex(const AFileName: string; Attrs: DWORD): integer; 
var 
  SFI : TSHFileInfo; 
begin 
  SHGetFileInfo(PChar(AFileName), Attrs, SFI, SizeOf(TShFileInfo), 
                SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES); 
  Result := SFI.iIcon; 
end;


bekommst Du auch den Index zurück, wenn die Datei gar nicht auf der Platte vorhanden ist. Das funktioniert natürlich nur dann, wenn auf dem Rechner der Dateityp verknüpft ist.

Bspw. bekommst Du auch ein Ergebnis, wenn Du als Dateiname 'nichtvorhanden.gif' übergibst, weil die Funktion anhand der Dateiendung 'gif' das Iconindex zurodnen kann.

Der Nachteil von SHGFI_USEFILEATTRIBUTES ist jedoch, dass er dann bei vorhandenen lokalen Ordnern diese nicht also solche erkennt, sondern glaubt, dass es sich um einen unbekannte Datei ohne Dateiendung handelt und daher nicht den richtigen Iconindex zurückliefert.


Tino - Do 03.07.03 08:58

Ups, hab dich falsch verstanden.
schitho hat folgendes geschrieben:
Durch SHGFI_USEFILEATTRIBUTES ist es möglich auch die Icons bzw. den Dateityp für nicht am PC vorhandene Dateien anzuzeigen.

Ich hatte gedacht du hast [...]nicht am PC vorhandene Dateitypen[...] geschrieben. Sorry... mein Fehler!

Gruß
Tino