Wie bekomme ich den Pfad von "Special Folders" (Desktop, Favoriten etc.)?
1. Warum so kompliziert?
Die Pfade der angesprochenen "Special Folders" stehen zwar in der Registry, aber laut Microsoft könnten sich die Orte ändern. Daher soll man die Funktion
SHGetSpecialFolderLocation verwenden. Diese Funktion ist aber nicht ganz so einfach und um sie sauber auzuführen muss man sich etwas mit dem
COM-Interface IMalloc auseinandersetzen.
2. Die benötigten Units
Folgende Units werden benötigt:
Delphi-Quellcode:
uses
{ ... },
ActiveX,
// IMalloc
ShellAPI,
// SHGetSpecialFolderLocation() und SHGetPathFromIDList()
ShlObj;
// CSIDL_-Konstanten
3. IMalloc, SHGetMalloc()
Die Funktion
SHGetSpecialFolderLocation belegt Speicher um den Path in einer sogennanten ItemIDList zurückzugeben (eine Liste von PIDLs, den Bezeichnern für alle Objekte im Shell Namespace, dem baumförmig aufgebauten Dateisystem wie im Windows-Explorer links zu sehen). Da für diese Liste Speicher von dieser Funktion reserviert wurde, jedoch nicht freigegeben werden kann (weil ein Pointer auf die Liste ja an unser Programm weitergeben werden muss), sind wir für das freigeben des Speichers, wenn wir die Liste nicht mehr benötigen, zuständig. Normalerweise würde man das ja über FreeMem() machen, jedoch weist der Pointer, der auf die Liste zeigt, in einen
fremden Adressraum, wir können da also nicht so einfach herumpfuschen. Ein Freigeben mit FreeMem() würde in einer Schutzverletzung resultieren.
Microsoft bietet hier als Lösung das Speicherverwaltungsinterface
IMalloc an. Dessen Methode
IMalloc.Free() übergibt man den Pointer auf den freizugebenden Speicher und die Sache ist gegessen.
Um einen Pointer auf die VTable von IMalloc zu bekommen (damit wir die Methode Free() aufrufen können) benutzen wir die Funktion SHGetMalloc. Der folgende Code demonstriert, die man ein IMalloc-Interface zu "fassen" bekommt:
Delphi-Quellcode:
var
pMalloc: IMalloc;
// ...
// get IMalloc interface pointer
if (SHGetMalloc(pMalloc) <> S_OK) then
begin
MessageBox(hWindow, 'Couldn''t get pointer to IMalloc interface.',
'SHGetMalloc(pMalloc)', 16);
Exit;
end;
Nun kann man
IMalloc.Free() ganz einfach so aufrufen:
Delphi-Quellcode:
var
p: PChar;
// ...
pMalloc.Free(p);
4. SHGetSpecialFolderLocation() und SHGetPathFromIDList()
Jetzt kann man mit der Funktion
SHGetSpecialFolderLocation den Pfad zum herauszufindenen Ordner anfordern. Diese Funktion ist wie folgt deklariert:
(C/C++)
Code:
HRESULT SHGetSpecialFolderLocation(
HWND hwndOwner,
int nFolder,
LPITEMIDLIST* ppidl
);
(Object Pascal)
Delphi-Quellcode:
function SHGetSpecialFolderLocation(
hwndOwner: HWND;
nFolder: Integer;
var ppidl: PItemIDList
): HRESULT; stdcall;
Der erste Parameter spezifiziert das
Handle des aufrufenden Fensters, das dritte ist der Pointer auf die Item-ID-Liste. Ausschlaggeben für den Ordner, der zurückgegeben wird, ist nFolder. Hier wird eine der folgenden Konstanten übergeben:
Code:
CSIDL_COOKIES Cookies
CSIDL_DESKTOPDIRECTORY Desktop
CSIDL_FAVORITES Favoriten
CSIDL_HISTORY Internet-Verlauf
CSIDL_INTERNET_CACHE "Temporary Internet Files"
CSIDL_PERSONAL Eigene Dateien
CSIDL_PROGRAMS "Programme" im Startmenü
CSIDL_RECENT "Dokumente" im Startmenü
CSIDL_SENDTO "Senden an" im Kontextmenü
CSIDL_STARTMENU Startmenü
CSIDL_STARTUP Autostart
Interessant wären auch CSIDL_MYMUSIC, CSIDL_MYPICTURES, CSIDL_SYSTEM, CSIDL_WINDOWS und CSIDL_PROGRAM_FILES, aber diese scheinen in Delphi (noch) nicht deklariert zu sein. Es gibt noch ein paar andere Werte, die virtuelle Ordner spezifieren, aber diese haben keinen Pfad im Dateisystem (z.B. die Netzwerkumgebung).
Hinzu kommt jetzt noch die Funktion
SHGetPathFromIDList, die aus der zurückgebenen Item-ID-Liste den Pfad holt. Die Deklaration:
(C/C++)
Code:
BOOL SHGetPathFromIDList(
LPCITEMIDLIST pidl,
LPTSTR pszPath
);
(Object Pascal)
Delphi-Quellcode:
function SHGetPathFromIDList(
pidl: PItemIDList;
pszPath: PChar
): Boolean; stdcall;
Jetzt noch ein Anwendungsbeispiel:
Delphi-Quellcode:
var
pidl: PItemIDList;
Folder: Integer;
hWindow: HWND;
// ...
SHGetSpecialFolderLocation(hWindow, Folder, pidl);
GetMem(Path, MAX_PATH);
SHGetPathFromIDList(pidl, Path);
Result := Path;
FreeMem(Path);
5. Die fertige Funktion GetSpecialFolder()
Nun dürfte es relativ einfach sein, eine Funktion daraus zu basteln (weil ich den meisten Code schon oben einkopiert habe *g*):
Delphi-Quellcode:
function GetSpecialFolder(hWindow: HWND; Folder: Integer): String;
var
pMalloc: IMalloc;
pidl: PItemIDList;
Path: PChar;
begin
// get IMalloc interface pointer
if (SHGetMalloc(pMalloc) <> S_OK) then
begin
MessageBox(hWindow, 'Couldn''t get pointer to IMalloc interface.',
'SHGetMalloc(pMalloc)', 16);
Exit;
end;
// retrieve path
SHGetSpecialFolderLocation(hWindow, Folder, pidl);
GetMem(Path, MAX_PATH);
SHGetPathFromIDList(pidl, Path);
Result := Path;
FreeMem(Path);
// free memory allocated by SHGetSpecialFolderLocation
pMalloc.Free(pidl);
end;
Zum Schluss noch ein Anwendungsbeispiel:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(GetSpecialFolder(
Handle, CSIDL_RECENT));
end;
Fertig *g*.
MfG,
d3g
[edit=Chakotay1308][code]- durch [delphi]-Tags ersetzt. Mfg, Chakotay1308[/edit]
[edit=flomei]Wir "räumen auf", daher Titel geändert... Mfg, flomei[/edit]
[edit=Matze]Alte MSDN-Links entfernt und MSDN-Tags gesetzt. MfG, Matze[/edit]