7

介绍

在 Windows 7 中,您有一些用于文档、图片和音乐等的特殊文件夹,称为库。

如果您不知道它们,基本上每个库文件夹都可以包含位置(路径),这些位置(路径)基本上是每个库的快捷方式。

一些例子:

Documents (Library)

  • E:\个人\文档(Location)
  • F:\备份\文档(Location)

Music (Library)

  • E:\媒体\音乐\专辑(Location)
  • E:\媒体\音乐\单曲(Location)

Pictures (Library)

  • E:\媒体\照片(Location)

当您从 Windows 资源管理器或开始菜单单击任何这些库文件夹时,Windows 资源管理器将显示该库中定义的位置。

任务

我需要做的是读取每种图书馆类型的位置,并能够用我自己的位置写回(更新)图书馆。我发现库存储在用户 AppData 文件夹中,如下所示:

C:\Users\SOMEUSER\AppData\Roaming\Microsoft\Windows\Libraries

这些库是这种文件类型:库 (.library-ms) - 如果您右键单击一个并选择属性,库选项卡您可以看到与该库关联的库位置。

我没有看到提取这些并将它们放入 TStringList 以在 Delphi 中进行编辑的方法。我想知道这些库位置是否真的存储在 Windows 注册表中,所以通过谷歌的一些研究,我发现了这些路径:

  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell 文件夹
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell 文件夹

但同样,我没有看到图书馆位置的实际列表。

那么,如何在 Delphi 中读取库文件中的位置列表,将它们添加到列表框或 TStringList,编辑条目然后写回更改?刚刚能够提取库位置路径将是一个开始。

我只是觉得这将是那些有一个我似乎找不到的简单答案的问题之一!

4

2 回答 2

6

使用其中一个SHLoadLibraryFrom...()函数,如SHLoadLibraryFromKnownFolder(),获取IShellLibrary接口,然后您可以使用它的方法来枚举和操作库,如IShellLibrary::GetFolders()IShellLibrary::AddFolder()IShellLibrary::RemoveFolder()等。

更新:例如:

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;

更新SHLoadLibraryFromKnownFolder()仅适用于已KNOWNFOLDERID定义值的 Microsoft 定义的库。如果要访问自定义库,则必须使用稍微修改的方法来获取IShellLibrary接口,例如:

// 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;
于 2012-09-18T22:06:39.007 回答
1

我刚刚在 Marco Cantu 的源代码存储库中找到了他的 Mastering Delphi 书籍,这是 Delphi 2010 的一个示例,它显示了一种获取图书馆内位置的方法。

存储库的链接在这里: http ://code.marcocantu.com/p/marcodelphibooks/source/tree/HEAD/

在里面delphi2010handbookchapter 05 (Win7Libraries)是示例源。

该演示中使用的方法基本上是使用已经提到的Windows API,该演示确认库文件确实是XML格式。


此外,我发现以下信息非常有用:

  • SHAddFolderPathToLibrary - 将文件夹添加到库中。
  • SHCreateLibrary IShellLibrary - 创建一个对象。
  • SHLoadLibraryFromItem - 创建 IShellLibrary 并将其加载到指定库定义文件中的对象。
  • SHLoadLibraryFromKnownFolder - 为指定的 KNOWNFOLDERID 创建和加载 IShellLibrary 对象。
  • SHLoadLibraryFromParsingName - 为指定路径创建和加载 IShellLibrary 对象。
  • SHRemoveFolderPathFromLibrary - 从库中删除文件夹。
  • SHResolveFolderPathInLibrary - 尝试解析已移动或重命名的库文件夹的目标位置。
  • SHResolveLibrary - 尝试查找库的位置。
  • SHSaveLibraryInFolderPath - 将 IShellLibrary 对象保存到磁盘。
  • SHShowManageLibraryUI - 显示库管理对话框,使用户能够管理库文件夹和默认保存位置。
于 2012-09-19T11:28:13.410 回答