using System; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Security; using System.Text; namespace Vanara.PInvoke { public static partial class Shell32 { /// Methods in this class will only work on Vista and above. public static class ShellUtil { /// Gets the KNOWNFOLDERID enum from a KNOWNFOLDERID Guid. /// The KNOWNFOLDERID Guid. /// The KNOWNFOLDERID enum. public static KNOWNFOLDERID GetKnownFolderFromGuid(Guid knownFolder) => Enum.GetValues(typeof(KNOWNFOLDERID)).Cast().Single(k => k.Guid() == knownFolder); /// Gets the KNOWNFOLDERID enum from a path. /// The folder path. /// The KNOWNFOLDERID enum. public static KNOWNFOLDERID GetKnownFolderFromPath(string path) { if (Environment.OSVersion.Version.Major < 6) return Enum.GetValues(typeof(KNOWNFOLDERID)).Cast().Single(k => string.Equals(k.FullPath(), path, StringComparison.InvariantCultureIgnoreCase)); var ikfm = new IKnownFolderManager(); return GetKnownFolderFromGuid(ikfm.FindFolderFromPath(path, FFFP_MODE.FFFP_EXACTMATCH).GetId()); } /// Gets the path for a KNOWNFOLDERID Guid. /// The KNOWNFOLDERID Guid. /// The file system path. [SecurityCritical] public static string GetPathForKnownFolder(Guid knownFolder) { if (knownFolder == default) return null; var pathBuilder = new StringBuilder(260); if (SHGetFolderPathEx(knownFolder, 0, HTOKEN.NULL, pathBuilder, (uint)pathBuilder.Capacity).Failed) return null; return pathBuilder.ToString(); } /// Gets the path from shell item. /// The shell item. /// The file system path. [SecurityCritical] public static string GetPathFromShellItem(IShellItem item) => item.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING); /// Gets the shell item for a file system path. /// The file system path. /// The corresponding IShellItem. [SecurityCritical] public static IShellItem GetShellItemForPath(string path) { if (string.IsNullOrEmpty(path)) return null; var hr = SHCreateItemFromParsingName(path, null, typeof(IShellItem).GUID, out var unk); if (hr == 0x80070002) { Ole32.CreateBindCtx(0, out var ibc).ThrowIfFailed(); using (var _ibc = new InteropServices.ComReleaser(ibc)) { var bd = new IntFileSysBindData(); ibc.RegisterObjectParam(STR_FILE_SYS_BIND_DATA, bd); hr = SHCreateItemFromParsingName(path, ibc, typeof(IShellItem).GUID, out unk); } } hr.ThrowIfFailed(); return (IShellItem)unk; } [ComVisible(true)] private class IntFileSysBindData : IFileSystemBindData2 { private static readonly Guid CLSID_UnknownJunction = new Guid("{fc0a77e6-9d70-4258-9783-6dab1d0fe31e}"); private Guid clsidJunction; private WIN32_FIND_DATA fd; private long fileId; public IntFileSysBindData() { } public long GetFileID() => fileId; public void GetFindData(out WIN32_FIND_DATA pfd) => pfd = fd; [return: MarshalAs(UnmanagedType.LPStruct)] public Guid GetJunctionCLSID() => clsidJunction != CLSID_UnknownJunction ? clsidJunction : throw new COMException("Unable to handle junctions", unchecked((int)HRESULT.E_FAIL)); public void SetFileID(long liFileID) => fileId = liFileID; public void SetFindData(in WIN32_FIND_DATA pfd) => fd = pfd; public void SetJunctionCLSID(in Guid clsid) => clsidJunction = clsid; } } } }