如何读/写Windows 7库位置?

7 windows delphi registry

介绍

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

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

一些例子:

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注册表中,所以通过Google的一些研究我发现了这些路径:

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

但同样,我没有看到库位置的实际列表.

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

我只是觉得这将是一个有一个我无法找到的简单答案的问题之一!

Rem*_*eau 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;
Run Code Online (Sandbox Code Playgroud)

.

var
  Folders: TStringList;
begin
  Folders := TStringList.Create;
  try
    if GetLibraryFileSystemFolders(FOLDERID_DocumentsLibrary, Folders) then
    begin
      //...
    end;
  finally
    Folders.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

更新: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;
Run Code Online (Sandbox Code Playgroud)

.

var
  Folders: TStringList;
begin
  Folders := TStringList.Create;
  try
    if GetLibraryFileSystemFolders('MyLibrary', Folders) then
    begin
      //...
    end;
  finally
    Folders.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

  • Remy,你有Delphi这样做的例子吗? (3认同)
  • 我添加了一个加载库的文件系统路径的示例.我会把剩下的作为练习让你弄明白. (3认同)
  • @David,对不起,但你错了.绝大多数**WinAPI**基于C,并且该功能的示例是C.提供的接口(特别是Windows shell)是基于C++的,因为(虽然很难看)C++是比C.更友好的界面友好.我非常流利的C和其他一些语言,但界面的东西仍然很讨厌; 让Delphi的例子可以帮助理解它是非常有用的.一旦你开始学习曲线(我承认我还没有),Delphi也支持COM(如果不是更好),而不是C++. (2认同)