如何读取/写入Windows 7库位置?

介绍

Windows 7中,您有一些文件,图片和音乐等特殊文件夹,称为库。

如果你不知道他们,基本上每个库文件夹可以包含位置(path),这基本上是每个库的快捷方式。

一些例子:

Documents (Library)

  • E:\个人\文件(Location)
  • F:\ Backups \ Documents (Location)

Music (Library)

  • E:\ Media \ Music \ Albums (Location)
  • E:\ Media \ Music \ Singles (Location)

Pictures (Library)

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

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

任务

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

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

这些库是这种文件types: 库(.library-ms) – 如果你右键点击一个,select属性,库选项卡,你可以看到与该库相关联的库位置。

我没有看到解压缩这些方法,并把它们放在一个TStringList中,以便在Delphi中进行编辑。 我想知道,如果这些库位置实际存储在Windowsregistry,所以从谷歌的一些研究,我发现这些path:

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

但是,我再次看不到实际的库位置列表。

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

我只是有一种感觉,这将是一个简单的答案,我似乎无法find的问题之一!

使用SHLoadLibraryFrom...()函数SHLoadLibraryFromKnownFolder()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; 

我刚刚在Marco Cantu的Mastering Delphi书籍的源代码库中找到了一个Delphi 2010的例子,它显示了一个在库中获取位置的方法。

到版本库的链接在这里: http : //code.marcocantu.com/p/marcodelphibooks/source/tree/HEAD/

chapter 05 (Win7Libraries)chapter 05 (Win7Libraries)就是示例源码。

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


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

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