Ihre Anwendung soll wie der Explorer Dateien mit den zugehörigen
Symbolen anzeigen? Kein Problem - da gibt es doch... die
API-Funktion ExtractAssociatedIcon.
Halt, nein! Die Funktion ExtractAssociatedIcon extrahiert zwar
gemäß ihrem Namen zu einer gegebenen Datei das zugehörige
Dateisymbol entweder direkt aus der Datei oder aus der
Programmdatei, die mit dem Typ der Datei verknüpft ist. Doch darin
liegt gleichermaßen das Problem mit der
ExtractAssociatedIcon-Funktion. Denn falls es sich bei der
betreffenden Datei beispielsweise um ein Bitmap handelt, wird statt
eines Dateisymbols das Bitmap selbst angezeigt, wobei es auf die
Größe eines Symbols gestaucht wird. Ein vergleichbares Problem
tritt bei Programmbibliotheken zu Tage, die eigene Symbole
enthalten: Anstatt des erhofften Symbols für Programmbibliotheken
liefert Ihnen die ExtractAssociatedIcon-Funktion ein Symbol aus der
Programmbibliothek. Der Explorer zeigt statt dessen für Bitmaps
etwa das Symbol für MS Paint und für Programmbibliotheken das
entsprechende Standardsymbol an.
An Stelle der ExtractAssociatedIcon-Funktion verwendet der
Explorer die API-Funktion SHGetFileInfo.
Die SHGetFileInfo-Funktion liefert neben zahlreichen anderen
Datei-Informationen auch das mit der Datei tatsächlich assoziierte
Symbol. Außerdem erlaubt die SHGetFileInfo-Funktion bestimmte
Variationen dieses Dateisymbols. Ein Ordner lässt sich
beispielsweise geöffnet oder geschlossen darstellen, eine
Verknüpfung wird meist durch einen kleinen Pfeil in der linken
unteren Ecke des Symbols (das kann aber durchaus vom Anwender
geändert werden) von einer gewöhnlichen Datei unterschieden und
das Symbol einer selektierten Datei beziehungsweise Ordners wird in
der Markierungsfarbe des Systems eingefärbt. Ebenso lässt sich die
Größe des Dateisymbols mit Hilfe der SHGetFileInfo-Funktion
einstellen: Small (16x16 Pixels), Large (32x32
Pixels) oder Shell - das ist abhängig von den
Benutzereinstellungen.
Die kleine Beispiel- und Experimentieranwendung zu diesem Artikel
verwendet die ExtractAssociatedIcon- und die SHGetFileInfo-Funktion,
um den Unterschied zwischen den beiden Funktionen zu demonstrieren.
Hierfür geben Sie im Textfeld Dateiname einen Pfad auf eine
Bitmap-Datei ein (Sie können auch eine Date vom Desktop oder aus
einem Explorer-Fenster in das Textfeld ziehen). Sobald das Textfeld
ein gültigen Pfad auf eine existierende Datei enthält, wird in der
linken Picturebox das mit dem Bitmap vermeintlich assoziierte Symbol
eingeblendet. Tatsächlich wird jedoch das Bitmap selbst verkleinert
dargestellt. Das im Explorer sichtbare Dateisymbol wird dagegen in
der rechten Picturebox angezeigt.
Obwohl die ExtractAssociatedIcon-Funktion, wie gesagt, nur
bedingt brauchbar ist, lohnt es sich, einen Blick auf die
Deklaration und die Anwendung der Funktion zu werfen.
Private Declare Function ExtractAssociatedIcon Lib "shell32.dll" _
Alias "ExtractAssociatedIconA" (ByVal hInst As Long, _
ByVal lpIconPath As String, ByRef lpiIcon As Integer) As Long
Die Funktion erwartet drei Parameter: das Instanzen-Handle der
eigenen Anwendung, den Pfadnamen der betreffenden Datei sowie den
Index des Symbols, das extrahiert werden soll. Das Instanzen-Handle
der eigenen Anwendung erhalten Sie von der hInstance-Eigenschaft des
App-Objekts. Der Pfadname im zweiten Parameter kann entweder auf
eine Datei verweisen, die ihr Dateisymbol selbst bereitstellt, wie
es der Fall bei Programmdateien, Symboldateien oder Bitmapdateien
ist, oder auf eine Datei, die einer Programmdatei zugeordnet ist.
Bei der ersten Art von Dateien extrahiert die
ExtractAssociatedIcon-Funktion das Symbol direkt aus der
betreffenden Datei. Andernfalls muss sie den Umweg über die
Verknüpfung des Dateityps gehen und das Symbol aus der
Programmdatei extrahieren. Der letzte Parameter, der den Index des
Symbols angibt, ist nur dann von Relevanz, wenn die Datei mehrere
Symbole enthalten sollte. In diesem Fall sind die Symbole beginnend
bei Null durchnummeriert.
Als Rückgabewert erhalten Sie von der
ExtractAssociatedIcon-Funktion ein Handle für das Symbol. Mit Hilfe
der Funktion PictureFromHandle-Funktion (siehe "Vom
Handle zum Picture") lässt sich ein Symbol- oder ein
Bitmap-Handle in ein Picture-Objekt wandeln. Falls Sie diesen
Extra-Schritt einsparen wollen, bieten wir Ihnen mit der Funktion
GetAssociatedIcon eine fertige Lösung an. Sie übergeben ihr den
Pfadnamen der betreffenden Datei und erhalten als Rückgabewert ein
Picture-Objekt mit dem mit der Datei assoziierten Symbol zurück.
Public Function GetAssociatedIcon(ByRef strFilename As String) _
As StdPicture
Dim hicon As Long
If strFilename = Empty Then
Err.Raise 5
End If
hicon = ExtractAssociatedIcon(App.hInstance, strFilename, 0)
If hicon = 0 Then
Err.Raise 5
End If
Set GetAssociatedIcon = _
PictureFromHandle(hicon, vbPicTypeIcon, True)
End Function
Allerdings ist die Dokumentation zur
ExtractAssociatedIcon-Funktion einerseits fehlerhaft und
andererseits unvollständig. So sollte sie Funktion über den
zweiten Parameter den Pfad derjenigen Datei an den Aufrufer
zurückliefern, aus der das Symbol gewonnen wurde. Der tatsächliche
Index des Symbols sollte über den dritten Parameter zurückgegeben
werden. Doch die beiden Parameter funktionieren ausschließlich nur
in der einen Richtung, als In-Parameter. Undokumentiert ist hingegen
die Möglichkeit, im zweiten Parameter statt einem konkreten
Pfadnamen eine Dateimaske zu übergeben. Allerdings muss die
Dateimaske auf mindestens eine konkrete Datei passen. Folglich sind
Dateimasken der Form *.ext nicht zulässig. Ein
Beispiel für eine gültige Dateimaske wäre hingegen C:\Windows\*.bmp.
In diesem Fall liefert ExtractAssociatedIcon doch wie eigentlich
erwartet als ermitteltes Symbol nicht etwa ein verkleinertes Bitmap
an, sondern das tatsächliche mit Bitmap-Dateien verknüpfte
Dateisymbol. Ein vergleichbarer und ebenfalls undokumentierter Trick
besteht darin, bei Bitmap-Dateien einen Wert größer Null als Index
zu übergeben. Das Ergebnis ist auch hier wiederum das tatsächliche
Dateisymbol.
Schließlich sei an dieser Stelle noch auf einen Fehler im
API-Viewer hingewiesen. Der letzte Parameter der
ExtractAssociatedIcon-Funktion ist vom Typ LPWORD. LPWORD steht für
"Long Pointer to Word". Unter Visual Basic entspricht ein
Long Pointer einem Referenzparameter und ein Word dem Dateityp
Integer. Der Parameter ist also als ByRef lpiIcon As Integer zu
deklarieren. Der API-Viewer deklariert den Parameter hingegen mit
ByRef lpiIcon As Long. Selbstverständlich haben wir Ihnen oben die
korrekte Deklaration der ExtractAssociatedIcon-Funktion gezeigt.
Die Anwendung der SHGetFileInfo-Funktion als Alternative ist zwar
ein wenig komplizierter als die der ExtractAssociatedIcon-Funktion,
doch die SHGetFileInfo-Funktion ermittelt im Unterschied zur
ExtractAssociatedIcon-Funktion das Symbol, das auch vom Explorer
angezeigt wird. Und sie liefert darüber hinaus weitere
Informationen zu der betreffenden Datei. Neben der Deklaration der
Funktion benötigen Sie weiterhin die Deklarationen für den
benutzerdefinierten Typ SHFILEINFO und für die SHGFI-Konstanten.
Private Const SHGFI_ATTRIBUTES As Long = &H800
Private Const SHGFI_DISPLAYNAME As Long = &H200
Private Const SHGFI_EXETYPE As Long = &H2000
Private Const SHGFI_ICON As Long = &H100
Private Const SHGFI_ICONLOCATION As Long = &H1000
Private Const SHGFI_LARGEICON As Long = &H0
Private Const SHGFI_LINKOVERLAY As Long = 32768 '= &H8000
Private Const SHGFI_OPENICON As Long = &H2
Private Const SHGFI_PIDL As Long = &H8
Private Const SHGFI_SELECTED As Long = &H10000
Private Const SHGFI_SHELLICONSIZE As Long = &H4
Private Const SHGFI_SMALLICON As Long = &H1
Private Const SHGFI_SYSICONINDEX As Long = &H4000
Private Const SHGFI_TYPENAME As Long = &H400
Private Const SHGFI_USEFILEATTRIBUTES As Long = &H10
Private Const MAX_PATH = 260
Private Type SHFILEINFO
hicon As Long
iIcon As Long
dwAttributes As Long
szDisplayName As String * MAX_PATH
szTypeName As String * 80
End Type
Private Declare Function SHGetFileInfo Lib "shell32.dll" _
Alias "SHGetFileInfoA" (ByVal pszPath As String, _
ByVal dwFileAttributes As Long, psfi As SHFILEINFO, _
ByVal cbFileInfo As Long, ByVal uFlags As Long) As Long
In der Struktur SHFILEINFO legt die SHGetFileInfo-Funktion die
Datei-Informationen ab. Welche Informationen über die Datei
ermittelt werden sollen, legen die genannten SHGFI-Konstanten fest.
Des weiteren erwartet die SHGetFileInfo-Funktion den Pfadnamen der
Datei sowie optional Attribute, die die Datei eindeutig
identifizieren. Die SHFILEINFO-Struktur setzt sich zusammen aus dem
Handle des Dateisymbols, dem Index des Symbols in der System Image
List, den Dateiattributen, dem angezeigten Namen für die Datei und
dem Typnamen der Datei. Indem wir der SHGetFileInfo-Funktion die
Konstante SHGFI_ICON übergeben, teilen wir der Funktion mit, dass
wir ausschließlich an dem Eintrag hIcon der SHFILEINFO-Struktur
interessiert sind, da hier das Handle das Dateisymbols abgelegt
wird. Die Konstante SHGFI_ICON lässt sich mittels Or-Operator mit
den folgenden Konstanten kombinieren: SHGFI_LARGEICON,
SHGFI_LINKOVERLAY, SHGFI_OPENICON, SHGFI_SELECTED,
SHGFI_SHELLICONSIZE und SHGFI_SMALLICON.
Das Modul modAssocIcon.bas stellt Ihnen für diese Konstanten die
Enumeration shgfiFlags zur Verfügung, die entsprechende Konstanten
enthält und Ihnen die Wahl der gewünschten Konstante bei der
Eingabe erleichtert.
Public Enum shgfiFlags
shgfiLarge = SHGFI_LARGEICON
shgfiLink = SHGFI_LINKOVERLAY
shgfiOpen = SHGFI_OPENICON
shgfiSelected = SHGFI_SELECTED
shgfiShell = SHGFI_SHELLICONSIZE
shgfiSmall = SHGFI_SMALLICON
End Enum
Am Beispiel der Konstanten SHGFI_LINKOVERLAY offenbart sich
übrigens eine weitere Unzulänglichkeit des API-Viewers. Die
Konstanten SHGFI sind ursprünglich als DWORD-Werte deklariert,
jedoch kennt Visual Basic keinen Typ für ganzzahlige, positive
Werte. Folglich muss der Long-Typ als Ersatz erhalten. Der Wert der
SHGFI_LINKOVERLAY-Konstante in hexadezimaler Schreibweise lautet
0x8000. Der Wert 0x8000 entspricht als DWORD
interpretiert der Zahl 32768. In VB würde man hierfür
&H8000 schreiben, was allerdings der Zahl -32768
entspricht, da bei &H8000 das oberste Bit gesetzt
ist. Das oberste Bit wird bei Long-Werten als Vorzeichenbit
"missbraucht". Folglich wird der hexadezimale Wert
&H8000 als negative Ganzzahl interpretiert. Doch da ein
Großteil der WIN32API.TXT automatisch anhand von C++-Headerdateien
generiert wurde, liefert der API-Viewer für die Konstante
SHGFI_LINKOVERLAY die irrtümliche Deklaration:
Public Const SHGFI_LINKOVERLAY = &H8000
Richtigerweise muss sie jedoch lauten:
Private Const SHGFI_LINKOVERLAY As Long = 32768
Um den Aufruf der SHGetFileInfo-Funktion zu vereinfachen, haben
wir diesen in die Funktion GetDisplayedIcon gepackt. In deren erstem
Parameter übergeben Sie den Pfadnamen einer Datei bzw. eines
Ordners. Es sind sowohl absolute als auch relative Pfade erlaubt
sowie konkrete Dateimasken (zum Beispiel: C:\Windows\*.bmp).
Im zweiten, optionalen Parameter lässt sich eine Bitmaske bestehend
aus den eben genannten shgfiFlags-Konstanten übergeben. Die
Kombination shgfiOpen Or shgfiSelected sorgt beispielsweise dafür,
dass ein Ordner als geöffnet und selektiert dargestellt wird. Als
Rückgabewert erhalten Sie ein Picture-Objekt mit dem gewünschten
Dateisymbol.
Die Struktur der GetDisplayedIcon-Funktion ist ähnlich der der
ExtractAssociatedIcon-Funktion. Als erstes wird die Bitmaske mit den
shgfiFlags-Konstanten um die Konstante SHGFI_ICON erweitert. Dann
erfolgt bereits der Aufruf der SHGetFileInfo-Funktion. Im ersten
Parameter wird der SHGetFileInfo-Funktion der Pfadname der Datei
übergeben. Im zweiten Parameter könnten die weitere Attribute
abgelegt werden, die die Datei gegebenenfalls näher spezifizieren.
Die GetDisplayedIcon-Funktion übergibt hier einfach Null, da wir
diese bei dieser Verwendungsart der Funktion nicht benötigen und
auch gar nicht ur Verfügung haben. Der dritte Parameter wird mit
der SHFILEINFO-Struktur belegt und der vierte Parameter mit der
Größe dieser Struktur. Im fünften und letzten Parameter finden
sich schließlich die shgfiFlags-Konstanten.
Public Function GetDisplayedIcon( _
ByRef strFilename As String, _
Optional ByVal lngFlags As shgfiFlags = shgfiLarge) _
As StdPicture
Dim fi As SHFILEINFO
Dim lngReturn As Long
lngFlags = lngFlags Or SHGFI_ICON
lngReturn = SHGetFileInfo(strFilename, 0, fi, Len(fi), lngFlags)
If lngReturn = 0 Then
Err.Raise 5
End If
Set GetDisplayedIcon = _
PictureFromHandle(fi.hicon, vbPicTypeIcon, True)
End Function
Falls die SHGetFileInfo-Funktion einen Rückgabewert gleich Null
liefert, war der Aufruf der SHGetFileInfo-Funktion nicht erfolgreich
und die GetDisplayedIcon-Funktion löst daher einen Laufzeitfehler
aus. Andernfalls wird das Handle des Symbols an die PictureFromHandle-Funktion
überreicht, die im Austausch ein Picture-Objekt liefert. Dieses
Picture-Objekt gibt die GetDisplayedIcon-Funktion an ihren eigenen
Aufrufer zurück.
|