Intro
In Windows 7 you have some special folders for documents, pictures and music etc called Libraries.
If you are not aware of them, basic
I have just found in Marco Cantu's source code repository for his Mastering Delphi books, an example for Delphi 2010 which shows a way of getting the locations inside a library.
The link to the repository is here: http://code.marcocantu.com/p/marcodelphibooks/source/tree/HEAD/
In the delphi2010handbook
, chapter 05 (Win7Libraries)
is the example source.
The method used in that demo is basically the use of the Windows API that has already been mentioned, the demo confirms that the Library files are indeed of XML format.
Additionally I found the following information which is quite useful:
Use one of the SHLoadLibraryFrom...()
functions, like SHLoadLibraryFromKnownFolder()
, to get an IShellLibrary
interface, then you can use its methods to enumerate and manipulate the Library, such as IShellLibrary::GetFolders()
, IShellLibrary::AddFolder()
, IShellLibrary::RemoveFolder()
, etc.
Update: For example:
uses
..., ActiveX, KnownFolders, ShlObj;
// The SHLoadLibraryFrom...() functions are implemented inline in the Win32 SDK
// shobjidl.h header file, so you have to implement them manually in your
// code if you you are not using a version of Delphi that already implements
// them in the RTL's ShlObj.pas unit for you...
// SHLoadLibraryFromKnownFolder() is defined wrong in ShlObj.pas!!! See QC #109306
function My_SHLoadLibraryFromKnownFolder(const kfidLibrary: TGUID; grfMode: DWORD; riid: TIID; out ppv): HRESULT;
var
plib: IShellLibrary;
begin
Result := CoCreateInstance(CLSID_ShellLibrary, nil, CLSCTX_INPROC_SERVER, IShellLibrary, plib);
if SUCCEEDED(Result) then
begin
Result := plib.LoadLibraryFromKnownFolder(kfidLibrary, grfMode);
if SUCCEEDED(Result) then
Result := plib.QueryInterface(riid, ppv);
end;
end;
function GetLibraryFileSystemFolders(FolderID: TGUID; Folders: TStrings): Boolean;
var
SL: IShellLibrary;
Arr: IShellItemArray;
Enum: IEnumShellItems;
Item: IShellItem;
Path: LPWSTR;
begin
Result := False;
if FAILED(My_SHLoadLibraryFromKnownFolder(FolderID, STGM_READ, IShellLibrary, SL)) then
Exit;
if FAILED(SL.GetFolders(LFF_FORCEFILESYSTEM, IShellItemArray, Arr)) then
Exit;
if FAILED(Arr.EnumItems(Enum)) then
Exit;
while Enum.Next(1, Item, nil) = S_OK then
begin
if FAILED(Item.GetDisplayName(SIGDN_FILESYSPATH, Path)) then
Exit;
try
Folders.Add(Path);
finally
CoTaskMemFree(Path);
end;
Item := nil;
end;
Result := True;
end;
.
var
Folders: TStringList;
begin
Folders := TStringList.Create;
try
if GetLibraryFileSystemFolders(FOLDERID_DocumentsLibrary, Folders) then
begin
//...
end;
finally
Folders.Free;
end;
end;
Update: SHLoadLibraryFromKnownFolder()
only works for Microsoft-defined Libraries that have KNOWNFOLDERID
values defined. If you want to access custom Libraries, you have to use a slightly modified approach to obtaining the IShellLibrary
interface, eg:
// SHLoadLibraryFromItem() is defined wrong in ShlObj.pas!!! See QC #109306
function My_SHLoadLibraryFromItem(const psiLibrary: IShellItem; grfMode: DWORD; const riid: TIID; out ppv): HResult;
var
plib: IShellLibrary;
begin
Result := CoCreateInstance(CLSID_ShellLibrary, nil, CLSCTX_INPROC_SERVER, IID_IShellLibrary, plib);
if Succeeded(Result) then
begin
Result := plib.LoadLibraryFromItem(psiLibrary, grfMode);
if Succeeded(Result) then
Result := plib.QueryInterface(riid, ppv);
end;
end;
function GetShellLibraryforLibrary(const LibraryName: String; grfMode: DWORD; var ppv: IShellLibrary): Boolean;
var
SL: IShellLibrary;
Enum: IEnumShellItems;
Item: IShellItem;
DisplayName: LPWSTR;
hr: HRESULT;
begin
Result := False;
ppv := nil;
if FAILED(SHGetKnownFolderItem(FOLDERID_Libraries, 0, 0, IShellItem, PPointer(@Item)^) then
Exit;
hr := Item.BindToHandler(nil, BHID_EnumItems, IEnumShellItems, Enum);
if FAILED(hr) then
Exit;
Item := nil;
while Enum.Next(1, Item, nil) = S_OK do
begin
if FAILED(Item.GetDisplayName(SIGDN_NORMALDISPLAY, DisplayName)) then
Exit;
try
if AnsiSameText(DisplayName, LibraryName) then
begin
Result := SUCCEEDED(My_SHLoadLibraryFromItem(Item, grfMode, IShellLibrary, ppv));
Break;
end;
finally
CoTaskMemFree(DisplayName);
end;
Item := nil;
end;
end;
function GetLibraryFileSystemFolders(const LibraryName: String; Folders: TStrings): Boolean;
var
SL: IShellLibrary;
Arr: IShellItemArray;
Enum: IEnumShellItems;
Item: IShellItem;
Path: LPWSTR;
begin
Result := False;
if not GetShellLibraryforLibrary(LibraryName, STGM_READ, SL) then
Exit;
if FAILED(SL.GetFolders(LFF_FORCEFILESYSTEM, IShellItemArray, Arr)) then
Exit;
if FAILED(Arr.EnumItems(Enum)) then
Exit;
while Enum.Next(1, Item, nil) = S_OK then
begin
if FAILED(Item.GetDisplayName(SIGDN_FILESYSPATH, Path)) then
Exit;
try
Folders.Add(Path);
finally
CoTaskMemFree(Path);
end;
Item := nil;
end;
Result := True;
end;
.
var
Folders: TStringList;
begin
Folders := TStringList.Create;
try
if GetLibraryFileSystemFolders('MyLibrary', Folders) then
begin
//...
end;
finally
Folders.Free;
end;
end;