Files
better-genshin-impact/Build/MicaSetup/Natives/Shell/Dialogs/Common/ShellObjectFactory.cs

156 lines
4.9 KiB
C#

using MicaSetup.Helper;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace MicaSetup.Shell.Dialogs;
internal static class ShellObjectFactory
{
internal static ShellObject Create(IShellItem nativeShellItem)
{
Debug.Assert(nativeShellItem != null, "nativeShellItem should not be null");
if (!OsVersionHelper.IsWindowsVista_OrGreater)
{
throw new PlatformNotSupportedException(LocalizedMessages.ShellObjectFactoryPlatformNotSupported);
}
var nativeShellItem2 = nativeShellItem as IShellItem2;
var itemType = ShellHelper.GetItemType(nativeShellItem2!);
if (!string.IsNullOrEmpty(itemType)) { itemType = itemType.ToLowerInvariant(); }
nativeShellItem2!.GetAttributes(ShellFileGetAttributesOptions.FileSystem | ShellFileGetAttributesOptions.Folder, out var sfgao);
var isFileSystem = (sfgao & ShellFileGetAttributesOptions.FileSystem) != 0;
var isFolder = (sfgao & ShellFileGetAttributesOptions.Folder) != 0;
if (StringComparer.OrdinalIgnoreCase.Equals(itemType, ".lnk"))
{
return new ShellLink(nativeShellItem2);
}
else if (isFolder)
{
ShellLibrary shellLibrary;
if (itemType == ".library-ms" && (shellLibrary = ShellLibrary.FromShellItem(nativeShellItem2, true)) != null!)
{
return shellLibrary;
}
else if (itemType == ".searchconnector-ms")
{
return new ShellSearchConnector(nativeShellItem2);
}
else if (itemType == ".search-ms")
{
return new ShellSavedSearchCollection(nativeShellItem2);
}
if (isFileSystem)
{
if (!IsVirtualKnownFolder(nativeShellItem2))
{
var kf = new FileSystemKnownFolder(nativeShellItem2);
return kf;
}
return new ShellFileSystemFolder(nativeShellItem2);
}
if (IsVirtualKnownFolder(nativeShellItem2))
{
var kf = new NonFileSystemKnownFolder(nativeShellItem2);
return kf;
}
return new ShellNonFileSystemFolder(nativeShellItem2);
}
if (isFileSystem) { return new ShellFile(nativeShellItem2); }
return new ShellNonFileSystemItem(nativeShellItem2);
}
internal static ShellObject Create(string parsingName)
{
if (string.IsNullOrEmpty(parsingName))
{
throw new ArgumentNullException("parsingName");
}
var guid = new Guid(ShellIIDGuid.IShellItem2);
var retCode = Shell32.SHCreateItemFromParsingName(parsingName, 0, ref guid, out
IShellItem2 nativeShellItem);
if (!CoreErrorHelper.Succeeded(retCode))
{
throw new ShellException(LocalizedMessages.ShellObjectFactoryUnableToCreateItem, Marshal.GetExceptionForHR(retCode));
}
return ShellObjectFactory.Create(nativeShellItem);
}
internal static ShellObject Create(nint idListPtr)
{
OsVersionHelper.ThrowIfNotVista();
var guid = new Guid(ShellIIDGuid.IShellItem2);
var retCode = Shell32.SHCreateItemFromIDList(idListPtr, ref guid, out var nativeShellItem);
if (!CoreErrorHelper.Succeeded(retCode)) { return null!; }
return ShellObjectFactory.Create(nativeShellItem);
}
internal static ShellObject Create(nint idListPtr, ShellContainer parent)
{
var retCode = Shell32.SHCreateShellItem(
0,
parent.NativeShellFolder,
idListPtr, out var nativeShellItem);
if (!CoreErrorHelper.Succeeded(retCode)) { return null!; }
return ShellObjectFactory.Create(nativeShellItem);
}
private static bool IsVirtualKnownFolder(IShellItem2 nativeShellItem2)
{
nint pidl = 0;
try
{
IKnownFolderNative nativeFolder = null!;
var definition = new KnownFoldersSafeNativeMethods.NativeFolderDefinition();
var padlock = new object();
lock (padlock)
{
var unknown = Marshal.GetIUnknownForObject(nativeShellItem2);
ThreadPool.QueueUserWorkItem(obj =>
{
lock (padlock)
{
pidl = ShellHelper.PidlFromUnknown(unknown);
new KnownFolderManagerClass().FindFolderFromIDList(pidl, out nativeFolder);
nativeFolder?.GetFolderDefinition(out definition);
Monitor.Pulse(padlock);
}
});
Monitor.Wait(padlock);
}
return nativeFolder != null && definition.category == FolderCategory.Virtual;
}
finally
{
Shell32.ILFree(pidl);
}
}
}