using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
using System.Text;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedParameter.Global
// ReSharper disable UnusedMember.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
// ReSharper disable InconsistentNaming
// ReSharper disable MemberHidesStaticFromOuterClass
// ReSharper disable UnusedMethodReturnValue.Global
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(Guid))
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 object 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 WIN32_FIND_DATA fd;
private long fileId;
private Guid clsidJunction;
public IntFileSysBindData() { }
public void SetFindData(in WIN32_FIND_DATA pfd) => fd = pfd;
public void GetFindData(out WIN32_FIND_DATA pfd) => pfd = fd;
public void SetFileID(long liFileID) => fileId = liFileID;
public long GetFileID() => fileId;
public void SetJunctionCLSID(in Guid clsid) => clsidJunction = clsid;
[return: MarshalAs(UnmanagedType.LPStruct)]
public Guid GetJunctionCLSID() => clsidJunction != CLSID_UnknownJunction ? clsidJunction : throw new COMException("Unable to handle junctions", unchecked((int)HRESULT.E_FAIL));
}
}
}
}