How to Read/Write Windows 7 Library Locations?

后端 未结 2 1653
灰色年华
灰色年华 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:39

    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:

    • SHAddFolderPathToLibrary - Adds a folder to a library.
    • SHCreateLibrary IShellLibrary - Creates an object.
    • SHLoadLibraryFromItem - Creates and loads IShellLibrary to object from a specified library definition file.
    • SHLoadLibraryFromKnownFolder - Creates and loads of IShellLibrary object for a specified KNOWNFOLDERID.
    • SHLoadLibraryFromParsingName - Creates and loads of IShellLibrary object for a specified path.
    • SHRemoveFolderPathFromLibrary - Removes a folder from a library.
    • SHResolveFolderPathInLibrary - Attempts to resolve the target location of a library folder that has been moved or renamed.
    • SHResolveLibrary - Attempts to find the location of a library.
    • SHSaveLibraryInFolderPath - Saves on IShellLibrary object to disk.
    • SHShowManageLibraryUI - Shows the library management dialog, Which Enables users to manage the library folders and default save location.
    0 讨论(0)
  • 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;
    
    0 讨论(0)
提交回复
热议问题