public ShellItem(Pidl pidl, ShellItem parentShellItem) : this(pidl, parentShellItem, true)
 {
 }
        public ShellItem(Pidl pidl, ShellItem parentShellItem, bool relativePidl)
        {
            int hResult;

            _rootItem = parentShellItem._rootItem;
            try
            {
                IntPtr tempPidl;
                if (relativePidl)
                {
                    _pidl    = new Pidl(parentShellItem.Pidl, pidl);
                    tempPidl = (IntPtr)pidl;                      // use the relative one from parameters
                }
                else
                {
                    _pidl    = pidl.Clone();
                    tempPidl = (IntPtr)_pidl;                      // use the absolute one that we constructed just now
                }

                const Native.SHGFI flags = Native.SHGFI.SHGFI_PIDL                 // indicates that we're specifying the item by PIDL
                                           | Native.SHGFI.SHGFI_DISPLAYNAME        // indicates that we want the item's display name
                                           | Native.SHGFI.SHGFI_SYSICONINDEX       // indicates that we want the item's icon's index in the system image list
                                           | Native.SHGFI.SHGFI_ATTRIBUTES         // indicates that we want the item's attributes
                                           | Native.SHGFI.SHGFI_TYPENAME;          // indicates that we want the item's type name
                Native.SHFILEINFO shInfo = new Native.SHFILEINFO();
                Native.Shell32.SHGetFileInfo((IntPtr)_pidl, 0, out shInfo, (uint)Marshal.SizeOf(shInfo), flags);

                // read item attributes
                Native.SFGAO attributeFlags = (Native.SFGAO)shInfo.dwAttributes;

                // create the item's IShellFolder interface
                if ((attributeFlags & Native.SFGAO.SFGAO_FOLDER) != 0)
                {
                    Guid iidIShellFolder = new Guid(IID.IID_IShellFolder);
                    if (_pidl == _rootItem._pidl)
                    {
                        // if the requested PIDL is the root namespace (the desktop) we can't use the the BindToObject method, so get it directly
                        hResult = Native.Shell32.SHGetDesktopFolder(ref _shellFolder);
                    }
                    else
                    {
                        if (relativePidl)
                        {
                            hResult = (int)parentShellItem._shellFolder.BindToObject(tempPidl, IntPtr.Zero, ref iidIShellFolder, out _shellFolder);
                        }
                        else
                        {
                            hResult = (int)_rootItem._shellFolder.BindToObject(tempPidl, IntPtr.Zero, ref iidIShellFolder, out _shellFolder);
                        }
                    }

                    if (hResult != 0)
                    {
                        // some objects are marked as folders, but really aren't and thus cannot be bound to an IShellFolder
                        // log these events for future study, but it's not exactly something to be concerned about in isolated cases.
                        // Marshal.ThrowExceptionForHR(hResult);
                        if ((attributeFlags & Native.SFGAO.SFGAO_HASSUBFOLDER) == 0)
                        {
                            attributeFlags = attributeFlags & ~Native.SFGAO.SFGAO_FOLDER;
                        }
                    }
                }

                _displayName   = shInfo.szDisplayName;
                _typeName      = shInfo.szTypeName;
                _iconIndex     = shInfo.iIcon;
                _isFolder      = (attributeFlags & Native.SFGAO.SFGAO_FOLDER) != 0;
                _isVirtual     = (attributeFlags & Native.SFGAO.SFGAO_FILESYSTEM) == 0;
                _hasSubFolders = (attributeFlags & Native.SFGAO.SFGAO_HASSUBFOLDER) != 0;
            }
            catch (UnauthorizedAccessException ex)
            {
                // if an exception happens during construction, we must release the PIDL now (remember, it's a pointer!)
                var path = string.Empty;
                if (_pidl != null)
                {
                    path = _pidl.Path;
                    _pidl.Dispose();
                }
                throw new PathAccessException(path, ex);
            }
            catch (Exception ex)
            {
                // if an exception happens during construction, we must release the PIDL now (remember, it's a pointer!)
                if (_pidl != null)
                {
                    _pidl.Dispose();
                }
                throw new Exception("Creation of the specified shell item failed.", ex);
            }

#if DEBUG
            _instanceCount++;
#endif
        }