2

Using Delphi and Windows API is possible from a PItemIDList to get if the file is a folder or not? With this snippet of code I can get the only the name of the file.

procedure TMain.FolderMonitorFileChange(aSender: TObject; aPIDL: PItemIDList);
var
  FileInfo : SHFILEINFOW;
begin
  SHGetFileInfo(LPCTSTR(aPIDL), 0 , FileInfo, SizeOf(FileInfo), SHGFI_PIDL or SHGFI_DISPLAYNAME or SHGFI_TYPENAME or SHGFI_ATTRIBUTES);
  ShowMessage('File change notification: ' + FileInfo.szDisplayName + ' ' + FileInfo.szTypeName );
end;

Thanks

Plebios
  • 835
  • 1
  • 7
  • 17

1 Answers1

4

For a relative PIDL, you can obtain the IShellFolder interface of the PIDL's parent folder, and then pass the PIDL to the IShellFolder::GetAttributesOf() method.

function IsFolder(Parent: IShellFolder; aChildPIDL: PItemIDList): Boolean;
var
  Attrs: SFGAOF;
begin
  Result := Succeeded(Parent.GetAttributesOf(1, @aChildPidl, @Attrs))
    and (Attrs and SFGAO_FOLDER <> 0);
end;

For an absolute PIDL, you have a few different options:

  • pass the PIDL to SHBindToParent() to convert it to a relative PIDL and retrieve its parent folder's IShellFolder, then call IShellFolder::GetAttributesOf().

    function IsFolder(aPIDL: PItemIDList): Boolean;
    var
      Parent: IShellFolder;
      Child: PItemIDList;
      Attrs: SFGAOF;
    begin
      Result := Succeeded(SHBindToParent(aPidl, IShellFolder, @Parent, @Child))
        and Succeeded(Parent.GetAttributesOf(1, @Child, @Attrs))
        and (Attrs and SFGAO_FOLDER <> 0);
    end;
    
  • pass the PIDL to SHGetFileInfo() using the SHGFI_PIDL flag. Enable the SHGFI_ATTRIBUTES flag to request the item's attributes.

    function IsFolder(aPIDL: PItemIDList): Boolean;
    var
      FileInfo : SHFILEINFO;
    begin
      Result := (SHGetFileInfo(LPCTSTR(aPIDL), 0, @FileInfo, SizeOf(FileInfo), SHGFI_PIDL or  SHGFI_ATTRIBUTES) <> 0)
        and (FileInfo.dwAttributes and SFGAO_FOLDER <> 0);
    end;
    
  • pass the PIDL to SHCreateItemFromIDList() to retrieve an IShellItem interface for it, and then call IShellItem::GetAttributes().

    function IsFolder(aPIDL: PItemIDList): Boolean;
    var
      Item: IShellItem;
      Attrs: SFGAOF;
    begin
      Result := Succeeded(SHCreateItemFromIDList(aPidl, IShellItem, @Item))
        and Succeeded(Item.GetAttributes(SFGAO_FOLDER, @Attrs))
        and (Attrs and SFGAO_FOLDER <> 0);
    end;
    
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks a lot for the help, but the code does not work for me because that event returns to me file changes of a monitorized folder, and when a file is modified all is ok but when i create a file it triggers that the folder that contains that has been changed and the attribute says that is a file, the typename says 'file' and the displayName is the name of the folder. – Plebios Jan 24 '17 at 18:00
  • 2
    You asked how to determine whether a PIDL represents a folder or a file. I answered that. The `SFGAO_FOLDER` attribute is specifically designed for that purpose. Now, you are describing a different issue. Whether the notification gives you a file PIDL or a folder PIDL depends on what you are actually monitoring and how you are monitoring it. But I highly doubt that a folder object would not report itself as a folder in attributes, which makes me think either there is a bug in your code, or an error is being reported that you are not handling. – Remy Lebeau Jan 24 '17 at 19:22
  • Yes I asked this because as you can see at the code I receive a 'PItemIDList' with the event, I thought that I do not know how to extract the data of that object. I am using a 'TLMDShellNotify' to monitor a folder and receive the changes using the 'FileChange' event of this object. – Plebios Jan 25 '17 at 08:09