How to Read/Write Windows 7 Library Locations?

后端 未结 2 1661
灰色年华
灰色年华 2020-12-09 22:33

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

2条回答
  •  生来不讨喜
    2020-12-09 22:58

    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;
    

提交回复
热议问题