![]() |
SHGetFileInfo : Programmicon in Imagelist kopieren
Hallo,
Als Erstes möchte ich mich mal bedanken. Bin schon seit einiger Zeit regelmäßiger Besucher der DP und habe viel Hilfe gefunden. Um Anderen zu helfen, reichen meine Delphi-Kenntnisse leider noch nicht aus. Leider habe ich hier ein Problem, das ich nicht selbst lösen kann : Es handelt sich um eine Funktion, die die Icon eines Programmes zu einer ImageList hinzufügen soll. Die Sache ist etwas umständlich programmiert; ich hatte anfangs eine kompaktere Version, bin aber nach und nach mehr ins Detail gegangen, um den Fehler zu finden. Die Idee ist Folgende: 1) Eine ImageList (ImgLst, width und height = 32) im MainForm. 2) Die Funktion AddFileIconToImgList wird aufgerufen (Parameter ist der Programmname) und gibt als Ergebnis den ImageIndex de Icon in der ImageList zurück. Das Problem ist, dass das beim ersten Aufruf gut funktioniert, dann aber nicht mehr. z.B.:
Delphi-Quellcode:
Beim ersten Aufruf wird 0 als Index zurückgegeben, beim zweiten Aufruf 1. In der ImageList befinden sich auch zwei Bitmaps, das erste ist die Explorericon, das zweite Bitmap ist allerdings ‚leer’ (einfach nur weiss).
AddFileIconToImgList('c:\windows\expolorer.exe’);
AddFileIconToImgList('c:\windows\expolorer.exe’);
Delphi-Quellcode:
Hat jemand 'ne Idee, warum das nicht läuft ?
function TFrm_Main.AddFileIconToImgList(FName : string):integer;
var FileInfo : TSHFileInfo; tmpImgLst : TImageList; tmpBitmap : TBitmap; begin tmpBitmap := TBitmap.Create; tmpBitmap.Height := 32; tmpBitmap.Width := 32; tmpImgLst := TImageList.Create(self); tmpImgLst.Width := 32; tmpImgLst.Height := 32; tmpImgLst.Handle := SHGetFileInfo(PChar(FName),0,FileInfo,sizeof(FileInfo),SHGFI_SYSICONINDEX or SHGFI_ICON); tmpImgLst.GetBitmap(FileInfo.iIcon,tmpBitmap); tmpImgLst.Free; Result := ImgList.Add(tmpBitmap,nil); tmpBitmap.Free; end; Danke für Eure Hilfe. LM |
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Warum es nicht läuft, kann ich dir nicht sagen. Will ich auch nicht ;), denn du kommst besser weg, wenn du keine eigene Imageliste erzeugst, sondern gleich auf die Symbole aus dem System zugreifst. Es ist noch gar nicht solange her:
![]() Wenn nämlich in deiner Liste mehrere Dateien mit dem gleichen Symbol auftauchen, dann würdest du entsprechend oft das gleiche Symbol in der Imageliste haben. Nicht zu vergessen, dass wahrscheinlich auch die Performance bzw. die Ressourcen darunter leiden. Mit dem o.g. Weg greifst du stattdessen auf die Symbole zurück, die auch im Explorer angezeigt werden. Und statt Icons zu erzeugen, lässt du dir nur den Indexwert geben, und fertig. Bei der List-View musst du dann allerdings die Einstellung "ShareImages" im Objektinspektor auf true setzen. btw: Beim Tree-View ist es übrigens einfacher, da brauchst du überhaupt keine TImageList auf der Form. ;) |
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Zitat:
Na ja, habe mir den von Dir erwähnten Artikel durchgelesen und Deine dort angebotene Lösung übernommen. Funktioniert einwandfrei. Also noch mal vielen Dank für den Hinweis (hatte zwar vor dem posten gesucht, den angegebenen Artikel aber wohl übersehen :? ). |
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Moin Lume,
erst einmal herzlich willkommen hier in der Delphi-PRAXiS. Was mir als erstes aufgefallen ist: SHGetFileInfo liefert im gezeigten Zusammenhang nur 0 (Fehler) oder <> 0 (Erfolgreicher Aufruf) zurück. Den Rückgabewert an das ImageList Handle zu übergeben hat also keinen Sinn. Ausserdem fehlt ein Resourcenschutzblock (try/finally) für die Bitmap. Zudem solltest Du die Imagelist nicht in der Routine erzeugen, wenn Du sie auch ausserhalb verwenden willst. Wieso der erste Aufruf funktioniert hat ist mir allerdings ein Rätsel, denn mit
Delphi-Quellcode:
rufst Du ein Bild aus der Imagelist ab und kopierst es in die Bitmap. FileInfo.iIcon hat mit Deiner Imagelist aber nichts zu tun, sondern bezieht sich auf die Systemimagelist.
tmpImgLst.GetBitmap(FileInfo.iIcon,tmpBitmap);
|
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Endlich mal einer, der sich nicht mit einer Lösung zufrieden gibt, sondern wissen will warum seine nicht funktioniert hat. :)
Also, grundsätzlich ist dein Code schon in Ordnung, wenn für meinen Geschmack auch das try/finally fehlt. Das eigentliche Problem dürfte aber auch bei dir die Sache mit der System-Imageliste gewesen sein. Prinzipiell greifst du in dieser Zeile auf das Handle der System-Imageliste zu
Delphi-Quellcode:
und weil du die Imageliste danach freigibst
tmpImgLst.Handle := SHGetFileInfo(PChar(FName),0,
FileInfo,sizeof(FileInfo),SHGFI_SYSICONINDEX or SHGFI_ICON);
Delphi-Quellcode:
"zerstörst" du damit auch die Systemsymbole. Natürlich nur temporär, aber du müsstest doch eigentlich bemerkt haben, dass im Explorer und im Startmenü (bspw.) alle großen Icons fehlen. Zumindest hat mein Windows 98 recht pingelig reagiert.
tmpImgLst.Free;
Jedenfalls klappt dadurch der erste Aufruf immer, aber durch das Freigeben der Imageliste existieren beim zweiten Aufruf natürlich gar keine Symbole mehr, und du erhältst nur die leere, weiße Bitmap. Gereicht hätte ein kleines
Delphi-Quellcode:
nach dem Erzeugen der Imageliste. Im Prinzip das, was ich in meinem ersten Beitrag schon kurz ansprach
tmpImgLst.ShareImages := true;
Zitat:
Ich hätte deine Funktion bspw. so geschrieben:
Delphi-Quellcode:
aber wie gesagt: Wenn du stattdessen, wie empfohlen, direkt auf die System-Imageliste zugreifst, arbeitest du weitaus effizienter und sparst Ressourcen.
function TForm1.AddFileIconToImgList(FName : string):integer;
var FileInfo : TSHFileInfo; tmpImgLst : TImageList; tmpBitmap : TBitmap; begin tmpBitmap := TBitmap.Create; tmpImgLst := TImageList.Create(self); try tmpBitmap.Height := 32; tmpBitmap.Width := 32; tmpImgLst.Width := 32; tmpImgLst.Height := 32; tmpImgLst.ShareImages := true; tmpImgLst.Handle := SHGetFileInfo(PChar(FName),0, FileInfo,sizeof(FileInfo),SHGFI_SYSICONINDEX or SHGFI_ICON); tmpImgLst.GetBitmap(FileInfo.iIcon,tmpBitmap); Result := ImageList1.Add(tmpBitmap,nil); finally tmpImgLst.Free; tmpBitmap.Free; end; end; // und als Beispielaufruf --> procedure TForm1.FormCreate(Sender: TObject); const szFiles : array[1..3]of string = ('c:\windows\explorer.exe', 'c:\tools\smc.exe', 'c:\programme\VSHIK 2003\VSHIK_EULA.rtf'); var li : TListItem; i : integer; begin for i := low(szFiles) to high(szFiles) do begin li := ListView1.Items.Add; li.Caption := szFiles[i]; li.ImageIndex := AddFileIconToImgList(szFiles[i]); end; end; Deine Idee funktioniert zwar jetzt auch, aber du füllst eben (langsam aber sicher) deine Imageliste mit Symbolen, evtl. eben auch mehrfach mit den gleichen Symbolen. Und das wäre sowohl performance- als auch speichertechnisch irgendwann ein Nachteil. Edit: Upps, Kamerad Seehase, wo kommen Sie denn her? Immer diese Drängler. :mrgreen: |
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Zitat:
Zitat:
|
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Moin Mathias,
Zitat:
gemäss meinem PSDK nicht ;-) |
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Gemäß meinem schon. Nicht unbedingt auf den ersten Blick zu sehen, aber da steht´s:
s. PSDK zu SHGetFileInfo SHGFI_SYSICONINDEX Retrieve the index of a system image list icon. If successful, the index is copied to the iIcon member of psfi. The return value is a handle to the system image list. Only those images whose indices are successfully copied to iIcon are valid. Attempting to access other images in the system image list will result in undefined behavior. :mrgreen: Ich habe auch nur das vom Februar letzten Jahres. Was ist eigentlich bei Microsoft los? |
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Moin Mathias,
stimmt hast Du wahr :oops: :wall: :mrgreen: Ich les' in so einem Falle den Abschnitt Return Value ;-) Zitat:
|
Re: SHGetFileInfo : Programmicon in Imagelist kopieren
Mit dem try/finally ist schon klar, eigentlich baue ich die immer mit ein, sobald ich irgendwo ein "Create" benutze. In diesem Fall nicht, wird aber nachgeholt, versprochen.
Ich hatte mir die SHGetFileInfo in der Win32 Prog. Ref. angesehen und dort gelesen, dass ich das Handle der SystemImageList zurückbekomme, deshalb mein
Delphi-Quellcode:
Hatte natürlich völlig übersehen/nicht bedacht, dass ich durch mein
tmpImgLst.Handle := SHGetFileInfo(....);
Delphi-Quellcode:
die SystemimageList "zerstöre". Jetzt ist mir auch klar warum nach dem ersten Aufruf nichts mehr lief.
tmpImgLst.free;
Konnte allerdings auf meinem Rechner (XP SP1) keine Nebeneffekte feststellen (pb mit den Desktop-icons, etc...). Wie auch immer, danke für Zusatzinfos; bin doch ein stück schlauer als vorher. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:51 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