mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-27 23:19:13 +08:00
[Peek] Fix selecting files from the correct focused opened File Explorer tab & from Desktop (#23489)
* Get file based on active tab handle instead of window title * Refactor code to get active tab * Getting all items from the shell API working again, except for desktop * Refactor and cleanup com & native code * Add back removed peek xaml assets in Product.wxs * Remove some dependencies that do not seem necessary in Product.wxs
This commit is contained in:
parent
7105802831
commit
4fe3e27fa4
@ -126,7 +126,7 @@
|
||||
|
||||
<?define FileLocksmithAssetsFiles=Icon.ico?>
|
||||
|
||||
<?define PeekFiles=CommunityToolkit.Mvvm.dll;Microsoft.InteractiveExperiences.Projection.dll;WinRT.Runtime.dll;Ijwhost.dll;Microsoft.Win32.SystemEvents.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;Powertoys.Interop.dll;Peek.Common.dll;Peek.FilePreviewer.dll;Powertoys.Peek.UI.dll;Powertoys.Peek.UI.exe;Powertoys.Peek.UI.deps.json;Powertoys.Peek.UI.runtimeconfig.json;resources.pri;System.CodeDom.dll;System.Drawing.Common.dll;System.Management.dll;WIC.dll;WinUIEx.dll;System.IO.Abstractions.dll;System.Text.Json.dll;WindowsBase.dll;PowerToys.Settings.UI.Lib.dll;Microsoft.Graphics.Display.dll;Microsoft.Windows.AppNotifications.Builder.Projection.dll;Microsoft.Windows.Security.AccessControl.Projection.dll;Microsoft.Windows.Widgets.dll;Microsoft.Windows.Widgets.Projection.dll?>
|
||||
<?define PeekFiles=CommunityToolkit.Mvvm.dll;Microsoft.InteractiveExperiences.Projection.dll;WinRT.Runtime.dll;Ijwhost.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;Powertoys.Interop.dll;Peek.Common.dll;Peek.FilePreviewer.dll;Powertoys.Peek.UI.dll;Powertoys.Peek.UI.exe;Powertoys.Peek.UI.deps.json;Powertoys.Peek.UI.runtimeconfig.json;resources.pri;System.CodeDom.dll;System.Drawing.Common.dll;System.Management.dll;WIC.dll;WinUIEx.dll;System.IO.Abstractions.dll;PowerToys.Settings.UI.Lib.dll?>
|
||||
|
||||
<?define PeekAssetsFiles=Icon.ico?>
|
||||
|
||||
@ -147,6 +147,8 @@
|
||||
<?define MeasureToolMicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
|
||||
|
||||
<?define HostsMicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
|
||||
|
||||
<?define PeekMicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
|
||||
|
||||
<?define PowerAccentFiles=ControlzEx.dll;Ijwhost.dll;Microsoft.Xaml.Behaviors.dll;PowerAccent.Core.dll;PowerToys.PowerAccentModuleInterface.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerAccent.deps.json;PowerToys.PowerAccent.dll;PowerToys.PowerAccent.exe;PowerToys.PowerAccent.runtimeconfig.json;PowerToys.Common.UI.dll;PowerToys.Settings.UI.Lib.dll;System.IO.Abstractions.dll;Vanara.Core.dll;Vanara.PInvoke.ComCtl32.dll;Vanara.PInvoke.Cryptography.dll;Vanara.PInvoke.Gdi32.dll;Vanara.PInvoke.Kernel32.dll;Vanara.PInvoke.Ole.dll;Vanara.PInvoke.Rpc.dll;Vanara.PInvoke.Security.dll;Vanara.PInvoke.Shared.dll;Vanara.PInvoke.Shell32.dll;Vanara.PInvoke.ShlwApi.dll;Vanara.PInvoke.User32.dll;PowerToys.PowerAccentKeyboardService.dll;Microsoft.Windows.SDK.NET.dll;WinRT.Runtime.dll;PowerToys.GPOWrapper.dll;UnicodeInformation.dll;ModernWpf.dll;ModernWpf.Controls.dll?>
|
||||
|
||||
|
@ -0,0 +1,122 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Peek.Common.Models;
|
||||
|
||||
namespace Peek.Common.Extensions
|
||||
{
|
||||
public static class IPropertyStoreExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper method that retrieves a uint value from the given property store.
|
||||
/// Returns 0 if the value is not a VT_UI4 (4-byte unsigned integer in little-endian order).
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">The pkey</param>
|
||||
/// <returns>The uint value</returns>
|
||||
public static uint GetUInt(this IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
if (propertyStore == null)
|
||||
{
|
||||
throw new ArgumentNullException("propertyStore");
|
||||
}
|
||||
|
||||
PropVariant propVar;
|
||||
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
// VT_UI4 Indicates a 4-byte unsigned integer formatted in little-endian byte order.
|
||||
if ((VarEnum)propVar.Vt == VarEnum.VT_UI4)
|
||||
{
|
||||
return propVar.UlVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves a ulong value from the given property store.
|
||||
/// Returns 0 if the value is not a VT_UI8 (8-byte unsigned integer in little-endian order).
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">the pkey</param>
|
||||
/// <returns>the ulong value</returns>
|
||||
public static ulong GetULong(this IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
if (propertyStore == null)
|
||||
{
|
||||
throw new ArgumentNullException("propertyStore");
|
||||
}
|
||||
|
||||
PropVariant propVar;
|
||||
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
// VT_UI8 Indicates an 8-byte unsigned integer formatted in little-endian byte order.
|
||||
if ((VarEnum)propVar.Vt == VarEnum.VT_UI8)
|
||||
{
|
||||
return propVar.UhVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves a string value from the given property store.
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">The pkey</param>
|
||||
/// <returns>The string value</returns>
|
||||
public static string GetString(this IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
PropVariant propVar;
|
||||
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
if ((VarEnum)propVar.Vt == VarEnum.VT_LPWSTR)
|
||||
{
|
||||
return Marshal.PtrToStringUni(propVar.P) ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves an array of string values from the given property store.
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">The pkey</param>
|
||||
/// <returns>The array of string values</returns>
|
||||
public static string[] GetStringArray(this IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
PropVariant propVar;
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
List<string> values = new List<string>();
|
||||
|
||||
if ((VarEnum)propVar.Vt == (VarEnum.VT_LPWSTR | VarEnum.VT_VECTOR))
|
||||
{
|
||||
for (int elementIndex = 0; elementIndex < propVar.Calpwstr.CElems; elementIndex++)
|
||||
{
|
||||
var stringVal = Marshal.PtrToStringUni(Marshal.ReadIntPtr(propVar.Calpwstr.PElems, elementIndex));
|
||||
if (stringVal != null)
|
||||
{
|
||||
values.Add(stringVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return values.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
65
src/modules/peek/Peek.Common/Helpers/PropertyStoreHelper.cs
Normal file
65
src/modules/peek/Peek.Common/Helpers/PropertyStoreHelper.cs
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Peek.Common.Models;
|
||||
using Windows.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
namespace Peek.Common.Helpers
|
||||
{
|
||||
public static partial class PropertyStoreHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a IPropertyStore interface from the given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The file/folder path</param>
|
||||
/// <param name="flags">The property store flags</param>
|
||||
/// <returns>an IPropertyStroe interface</returns>
|
||||
public static IPropertyStore GetPropertyStoreFromPath(string path, GETPROPERTYSTOREFLAGS flags = GETPROPERTYSTOREFLAGS.GPS_EXTRINSICPROPERTIES)
|
||||
{
|
||||
IShellItem2? shellItem2 = null;
|
||||
IntPtr ppPropertyStore = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
SHCreateItemFromParsingName(path, IntPtr.Zero, typeof(IShellItem2).GUID, out shellItem2);
|
||||
|
||||
if (shellItem2 == null)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Unable to get an IShellItem2 reference from file {0}.", path));
|
||||
}
|
||||
|
||||
int hr = shellItem2.GetPropertyStore((int)flags, typeof(IPropertyStore).GUID, out ppPropertyStore);
|
||||
|
||||
if (hr != 0)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("GetPropertyStore retunred hresult={0}", hr));
|
||||
}
|
||||
|
||||
return (IPropertyStore)Marshal.GetObjectForIUnknown(ppPropertyStore);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ppPropertyStore != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(ppPropertyStore);
|
||||
}
|
||||
|
||||
if (shellItem2 != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(shellItem2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
|
||||
private static extern void SHCreateItemFromParsingName(
|
||||
[In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
|
||||
[In] IntPtr pbc,
|
||||
[In][MarshalAs(UnmanagedType.LPStruct)] Guid riid,
|
||||
[Out][MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem2 ppv);
|
||||
}
|
||||
}
|
16
src/modules/peek/Peek.Common/Models/Blob.cs
Normal file
16
src/modules/peek/Peek.Common/Models/Blob.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Blob
|
||||
{
|
||||
public int CbSize;
|
||||
public IntPtr PBlobData;
|
||||
}
|
||||
}
|
16
src/modules/peek/Peek.Common/Models/CALPWSTR.cs
Normal file
16
src/modules/peek/Peek.Common/Models/CALPWSTR.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CALPWSTR
|
||||
{
|
||||
public uint CElems;
|
||||
public IntPtr PElems;
|
||||
}
|
||||
}
|
15
src/modules/peek/Peek.Common/Models/FileTime.cs
Normal file
15
src/modules/peek/Peek.Common/Models/FileTime.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FileTime
|
||||
{
|
||||
public int DWHighDateTime;
|
||||
public int DWLowDateTime;
|
||||
}
|
||||
}
|
27
src/modules/peek/Peek.Common/Models/IEnumIDList.cs
Normal file
27
src/modules/peek/Peek.Common/Models/IEnumIDList.cs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("000214F2-0000-0000-C000-000000000046")]
|
||||
public interface IEnumIDList
|
||||
{
|
||||
[PreserveSig]
|
||||
int Next(int celt, out IntPtr rgelt, out int pceltFetched);
|
||||
|
||||
[PreserveSig]
|
||||
int Skip(int celt);
|
||||
|
||||
[PreserveSig]
|
||||
int Reset();
|
||||
|
||||
[PreserveSig]
|
||||
int Clone(out IEnumIDList ppenum);
|
||||
}
|
||||
}
|
46
src/modules/peek/Peek.Common/Models/IFolderView.cs
Normal file
46
src/modules/peek/Peek.Common/Models/IFolderView.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("cde725b0-ccc9-4519-917e-325d72fab4ce")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
public interface IFolderView
|
||||
{
|
||||
void GetCurrentViewMode([Out] out uint pViewMode);
|
||||
|
||||
void SetCurrentViewMode([In] uint viewMode);
|
||||
|
||||
void GetFolder([In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv);
|
||||
|
||||
void Item([In] int iItemIndex, [Out] out IntPtr ppidl);
|
||||
|
||||
void ItemCount([In] uint uFlags, [Out] out int pcItems);
|
||||
|
||||
void Items([In] uint uFlags, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv);
|
||||
|
||||
void GetSelectionMarkedItem([Out] out int piItem);
|
||||
|
||||
void GetFocusedItem([Out] out int piItem);
|
||||
|
||||
void GetItemPosition([In] IntPtr pidl, [Out] out Point ppt);
|
||||
|
||||
void GetSpacing([In, Out] ref Point ppt);
|
||||
|
||||
void GetDefaultSpacing([Out] out Point ppt);
|
||||
|
||||
void GetAutoArrange();
|
||||
|
||||
void SelectItem([In] int iItem, [In] uint dwFlags);
|
||||
|
||||
void SelectAndPositionItems([In] uint cidl, [In] IntPtr apidl, [In] IntPtr apt, [In] uint dwFlags);
|
||||
}
|
||||
}
|
26
src/modules/peek/Peek.Common/Models/IPropertyStore.cs
Normal file
26
src/modules/peek/Peek.Common/Models/IPropertyStore.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Peek.Common.Helpers.PropertyStoreHelper;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IPropertyStore
|
||||
{
|
||||
void GetCount(out uint propertyCount);
|
||||
|
||||
void GetAt(uint iProp, out PropertyKey pkey);
|
||||
|
||||
void GetValue(ref PropertyKey key, out PropVariant pv);
|
||||
|
||||
void SetValue(ref PropertyKey key, ref PropVariant pv);
|
||||
|
||||
void Commit();
|
||||
}
|
||||
}
|
17
src/modules/peek/Peek.Common/Models/IServiceProvider.cs
Normal file
17
src/modules/peek/Peek.Common/Models/IServiceProvider.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IServiceProvider
|
||||
{
|
||||
[return: MarshalAs(UnmanagedType.IUnknown)]
|
||||
object QueryService([MarshalAs(UnmanagedType.LPStruct)] Guid service, [MarshalAs(UnmanagedType.LPStruct)] Guid riid);
|
||||
}
|
||||
}
|
46
src/modules/peek/Peek.Common/Models/IShellBrowser.cs
Normal file
46
src/modules/peek/Peek.Common/Models/IShellBrowser.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("000214E2-0000-0000-C000-000000000046")]
|
||||
public interface IShellBrowser
|
||||
{
|
||||
void GetWindow(out IntPtr phwnd);
|
||||
|
||||
void ContextSensitiveHelp(bool fEnterMode);
|
||||
|
||||
void InsertMenusSB(IntPtr hmenuShared, IntPtr lpMenuWidths);
|
||||
|
||||
void SetMenuSB(IntPtr hmenuShared, IntPtr holemenuRes, IntPtr hwndActiveObject);
|
||||
|
||||
void RemoveMenusSB(IntPtr hmenuShared);
|
||||
|
||||
void SetStatusTextSB(IntPtr pszStatusText);
|
||||
|
||||
void EnableModelessSB(bool fEnable);
|
||||
|
||||
void TranslateAcceleratorSB(IntPtr pmsg, ushort wID);
|
||||
|
||||
void BrowseObject(IntPtr pidl, uint wFlags);
|
||||
|
||||
void GetViewStateStream(uint grfMode, IntPtr ppStrm);
|
||||
|
||||
void GetControlWindow(uint id, out IntPtr lpIntPtr);
|
||||
|
||||
void SendControlMsg(uint id, uint uMsg, uint wParam, uint lParam, IntPtr pret);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.IUnknown)]
|
||||
object QueryActiveShellView();
|
||||
|
||||
void OnViewWindowActive(IShellView ppshv);
|
||||
|
||||
void SetToolbarItems(IntPtr lpButtons, uint nButtons, uint uFlags);
|
||||
}
|
||||
}
|
67
src/modules/peek/Peek.Common/Models/IShellFolder2.cs
Normal file
67
src/modules/peek/Peek.Common/Models/IShellFolder2.cs
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("93F2F68C-1D1B-11D3-A30E-00C04F79ABD1")]
|
||||
public interface IShellFolder2
|
||||
{
|
||||
[PreserveSig]
|
||||
int ParseDisplayName(IntPtr hwnd, IntPtr pbc, [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, ref int pchEaten, out IntPtr ppidl, ref int pdwAttributes);
|
||||
|
||||
[PreserveSig]
|
||||
int EnumObjects(IntPtr hwnd, _SHCONTF grfFlags, out IntPtr enumIDList);
|
||||
|
||||
[PreserveSig]
|
||||
int BindToObject(IntPtr pidl, IntPtr pbc, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int BindToStorage(IntPtr pidl, IntPtr pbc, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);
|
||||
|
||||
[PreserveSig]
|
||||
int CreateViewObject(IntPtr hwndOwner, Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetAttributesOf(int cidl, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, ref IntPtr rgfInOut);
|
||||
|
||||
[PreserveSig]
|
||||
int GetUIObjectOf(IntPtr hwndOwner, int cidl, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, ref Guid riid, IntPtr rgfReserved, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDisplayNameOf(IntPtr pidl, SHGDNF uFlags, out Strret lpName);
|
||||
|
||||
[PreserveSig]
|
||||
int SetNameOf(IntPtr hwnd, IntPtr pidl, [MarshalAs(UnmanagedType.LPWStr)] string pszName, int uFlags, out IntPtr ppidlOut);
|
||||
|
||||
[PreserveSig]
|
||||
int EnumSearches(out IntPtr ppenum);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDefaultColumn(int dwReserved, ref IntPtr pSort, out IntPtr pDisplay);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDefaultColumnState(int iColumn, out IntPtr pcsFlags);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDefaultSearchGUID(out IntPtr guid);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDetailsEx(IntPtr pidl, IntPtr pscid, out IntPtr pv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDetailsOf(IntPtr pidl, int iColumn, ref SHELLDETAILS psd);
|
||||
|
||||
[PreserveSig]
|
||||
int MapColumnToSCID(int icolumn, IntPtr pscid);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
@ -20,22 +21,11 @@ namespace Peek.Common.Models
|
||||
|
||||
void GetParent(out IShellItem ppsi);
|
||||
|
||||
void GetDisplayName(Sigdn sigdnName, out IntPtr ppszName);
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
string GetDisplayName(SIGDN sigdnName);
|
||||
|
||||
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
|
||||
|
||||
void Compare(IShellItem psi, uint hint, out int piOrder);
|
||||
}
|
||||
|
||||
public enum Sigdn : uint
|
||||
{
|
||||
NormalDisplay = 0,
|
||||
ParentRelativeParsing = 0x80018001,
|
||||
ParentRelativeForAddressBar = 0x8001c001,
|
||||
DesktopAbsoluteParsing = 0x80028000,
|
||||
ParentRelativeEditing = 0x80031001,
|
||||
DesktopAbsoluteEditing = 0x8004c000,
|
||||
FileSysPath = 0x80058000,
|
||||
Url = 0x80068000,
|
||||
}
|
||||
}
|
||||
|
71
src/modules/peek/Peek.Common/Models/IShellItem2.cs
Normal file
71
src/modules/peek/Peek.Common/Models/IShellItem2.cs
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("7E9FB0D3-919F-4307-AB2E-9B1860310C93")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IShellItem2 : IShellItem
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public void BindToHandler(IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public int GetDisplayName([In] int sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public void GetAttributes([In] int sfgaoMask, out int psfgaoAttribs);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetPropertyStore(int flags, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
internal int GetPropertyStoreWithCreateObject(ref GETPROPERTYSTOREFLAGS flags, ref IntPtr punkFactory, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
internal int GetPropertyStoreForKeys(ref PropertyKey keys, uint cKeys, ref GETPROPERTYSTOREFLAGS flags, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetPropertyDescriptionList(ref PropertyKey key, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
public int Update(ref IntPtr pbc);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetProperty(ref PropertyKey key, out PropVariant pPropVar);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetCLSID(ref PropertyKey key, out Guid clsid);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetFileTime(ref PropertyKey key, out FileTime pft);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetInt32(ref PropertyKey key, out int pi);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetString(ref PropertyKey key, [MarshalAs(UnmanagedType.LPWStr)] string ppsz);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetUint32(ref PropertyKey key, out uint pui);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetUint64(ref PropertyKey key, out uint pull);
|
||||
|
||||
[PreserveSig]
|
||||
public int GetBool(ref PropertyKey key, bool pf);
|
||||
}
|
||||
}
|
38
src/modules/peek/Peek.Common/Models/IShellItemArray.cs
Normal file
38
src/modules/peek/Peek.Common/Models/IShellItemArray.cs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("B63EA76D-1F85-456F-A19C-48159EFA858B")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IShellItemArray
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, out IntPtr ppvOut);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetPropertyStore([In] int flags, [In] ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetPropertyDescriptionList([In] ref PropertyKey keyType, [In] ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetAttributes([In] SIATTRIBFLAGS dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int GetCount();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
Common.Models.IShellItem GetItemAt(int dwIndex);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems);
|
||||
}
|
||||
}
|
18
src/modules/peek/Peek.Common/Models/IShellView.cs
Normal file
18
src/modules/peek/Peek.Common/Models/IShellView.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("000214E3-0000-0000-C000-000000000046")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
public interface IShellView
|
||||
{
|
||||
}
|
||||
}
|
60
src/modules/peek/Peek.Common/Models/PropVariant.cs
Normal file
60
src/modules/peek/Peek.Common/Models/PropVariant.cs
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct PropVariant
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public short Vt;
|
||||
[FieldOffset(2)]
|
||||
public short WReserved1;
|
||||
[FieldOffset(4)]
|
||||
public short WReserved2;
|
||||
[FieldOffset(6)]
|
||||
public short WReserved3;
|
||||
[FieldOffset(8)]
|
||||
public sbyte CVal;
|
||||
[FieldOffset(8)]
|
||||
public byte BVal;
|
||||
[FieldOffset(8)]
|
||||
public short IVal;
|
||||
[FieldOffset(8)]
|
||||
public ushort UiVal;
|
||||
[FieldOffset(8)]
|
||||
public int LVal;
|
||||
[FieldOffset(8)]
|
||||
public uint UlVal;
|
||||
[FieldOffset(8)]
|
||||
public int IntVal;
|
||||
[FieldOffset(8)]
|
||||
public uint UintVal;
|
||||
[FieldOffset(8)]
|
||||
public long HVal;
|
||||
[FieldOffset(8)]
|
||||
public ulong UhVal;
|
||||
[FieldOffset(8)]
|
||||
public float FltVal;
|
||||
[FieldOffset(8)]
|
||||
public double DblVal;
|
||||
[FieldOffset(8)]
|
||||
public bool BoolVal;
|
||||
[FieldOffset(8)]
|
||||
public int Scode;
|
||||
[FieldOffset(8)]
|
||||
public DateTime Date;
|
||||
[FieldOffset(8)]
|
||||
public FileTime Filetime;
|
||||
[FieldOffset(8)]
|
||||
public Blob Blob;
|
||||
[FieldOffset(8)]
|
||||
public IntPtr P;
|
||||
[FieldOffset(8)]
|
||||
public CALPWSTR Calpwstr;
|
||||
}
|
||||
}
|
65
src/modules/peek/Peek.Common/Models/PropertyKey.cs
Normal file
65
src/modules/peek/Peek.Common/Models/PropertyKey.cs
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct PropertyKey
|
||||
{
|
||||
public Guid FormatId;
|
||||
public int PropertyId;
|
||||
|
||||
public PropertyKey(Guid guid, int propertyId)
|
||||
{
|
||||
this.FormatId = guid;
|
||||
this.PropertyId = propertyId;
|
||||
}
|
||||
|
||||
public PropertyKey(uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h, uint i, uint j, uint k, int propertyId)
|
||||
: this(new Guid((uint)a, (ushort)b, (ushort)c, (byte)d, (byte)e, (byte)f, (byte)g, (byte)h, (byte)i, (byte)j, (byte)k), propertyId)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if ((obj == null) || !(obj is PropertyKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyKey pk = (PropertyKey)obj;
|
||||
|
||||
return FormatId.Equals(pk.FormatId) && (PropertyId == pk.PropertyId);
|
||||
}
|
||||
|
||||
public static bool operator ==(PropertyKey a, PropertyKey b)
|
||||
{
|
||||
if (((object)a == null) || ((object)b == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.FormatId == b.FormatId && a.PropertyId == b.PropertyId;
|
||||
}
|
||||
|
||||
public static bool operator !=(PropertyKey a, PropertyKey b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return FormatId.GetHashCode() ^ PropertyId;
|
||||
}
|
||||
|
||||
// File properties: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wsp/2dbe759c-c955-4770-a545-e46d7f6332ed
|
||||
public static readonly PropertyKey ImageHorizontalSize = new PropertyKey(new Guid(0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 3);
|
||||
public static readonly PropertyKey ImageVerticalSize = new PropertyKey(new Guid(0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 4);
|
||||
public static readonly PropertyKey FileSizeBytes = new PropertyKey(new Guid(0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac), 12);
|
||||
public static readonly PropertyKey FileType = new PropertyKey(new Guid(0xd5cdd502, 0x2e9c, 0x101b, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae), 26);
|
||||
}
|
||||
}
|
@ -1,650 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
public static class PropertyStoreShellApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the path to the given known folder.
|
||||
/// </summary>
|
||||
/// <param name="knownFolderId">Guid for given known folder</param>
|
||||
/// <returns>The path to the known folder.</returns>
|
||||
public static string GetKnownFolderPath(Guid knownFolderId)
|
||||
{
|
||||
string path;
|
||||
int hResult = SHGetKnownFolderPath(knownFolderId, 0, IntPtr.Zero, out path);
|
||||
Marshal.ThrowExceptionForHR(hResult);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a IPropertyStore interface from the given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The file/folder path</param>
|
||||
/// <param name="flags">The property store flags</param>
|
||||
/// <returns>an IPropertyStroe interface</returns>
|
||||
public static IPropertyStore GetPropertyStoreFromPath(string path, PropertyStoreFlags flags = PropertyStoreFlags.EXTRINSICPROPERTIES)
|
||||
{
|
||||
PropertyStoreShellApi.IShellItem2? shellItem2 = null;
|
||||
IntPtr ppPropertyStore = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
PropertyStoreShellApi.SHCreateItemFromParsingName(path, IntPtr.Zero, typeof(PropertyStoreShellApi.IShellItem2).GUID, out shellItem2);
|
||||
|
||||
if (shellItem2 == null)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Unable to get an IShellItem2 reference from file {0}.", path));
|
||||
}
|
||||
|
||||
int hr = shellItem2.GetPropertyStore((int)flags, typeof(PropertyStoreShellApi.IPropertyStore).GUID, out ppPropertyStore);
|
||||
|
||||
if (hr != 0)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("GetPropertyStore retunred hresult={0}", hr));
|
||||
}
|
||||
|
||||
return (PropertyStoreShellApi.IPropertyStore)Marshal.GetObjectForIUnknown(ppPropertyStore);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ppPropertyStore != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(ppPropertyStore);
|
||||
}
|
||||
|
||||
if (shellItem2 != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(shellItem2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves a uint value from the given property store.
|
||||
/// Returns 0 if the value is not a VT_UI4 (4-byte unsigned integer in little-endian order).
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">The pkey</param>
|
||||
/// <returns>The uint value</returns>
|
||||
public static uint GetUIntFromPropertyStore(IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
if (propertyStore == null)
|
||||
{
|
||||
throw new ArgumentNullException("propertyStore");
|
||||
}
|
||||
|
||||
PropVariant propVar;
|
||||
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
// VT_UI4 Indicates a 4-byte unsigned integer formatted in little-endian byte order.
|
||||
if ((VarEnum)propVar.Vt == VarEnum.VT_UI4)
|
||||
{
|
||||
return propVar.UlVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves a ulong value from the given property store.
|
||||
/// Returns 0 if the value is not a VT_UI8 (8-byte unsigned integer in little-endian order).
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">the pkey</param>
|
||||
/// <returns>the ulong value</returns>
|
||||
public static ulong GetULongFromPropertyStore(IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
if (propertyStore == null)
|
||||
{
|
||||
throw new ArgumentNullException("propertyStore");
|
||||
}
|
||||
|
||||
PropVariant propVar;
|
||||
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
// VT_UI8 Indicates an 8-byte unsigned integer formatted in little-endian byte order.
|
||||
if ((VarEnum)propVar.Vt == VarEnum.VT_UI8)
|
||||
{
|
||||
return propVar.UhVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves a string value from the given property store.
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">The pkey</param>
|
||||
/// <returns>The string value</returns>
|
||||
public static string GetStringFromPropertyStore(IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
PropVariant propVar;
|
||||
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
if ((VarEnum)propVar.Vt == VarEnum.VT_LPWSTR)
|
||||
{
|
||||
return Marshal.PtrToStringUni(propVar.P) ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that retrieves an array of string values from the given property store.
|
||||
/// </summary>
|
||||
/// <param name="propertyStore">The property store</param>
|
||||
/// <param name="key">The pkey</param>
|
||||
/// <returns>The array of string values</returns>
|
||||
public static string[] GetStringArrayFromPropertyStore(IPropertyStore propertyStore, PropertyKey key)
|
||||
{
|
||||
PropVariant propVar;
|
||||
propertyStore.GetValue(ref key, out propVar);
|
||||
|
||||
List<string> values = new List<string>();
|
||||
|
||||
if ((VarEnum)propVar.Vt == (VarEnum.VT_LPWSTR | VarEnum.VT_VECTOR))
|
||||
{
|
||||
for (int elementIndex = 0; elementIndex < propVar.Calpwstr.CElems; elementIndex++)
|
||||
{
|
||||
var stringVal = Marshal.PtrToStringUni(Marshal.ReadIntPtr(propVar.Calpwstr.PElems, elementIndex));
|
||||
if (stringVal != null)
|
||||
{
|
||||
values.Add(stringVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return values.ToArray();
|
||||
}
|
||||
|
||||
private const string IIDIShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE";
|
||||
private const string IIDIShellFolder2 = "93F2F68C-1D1B-11D3-A30E-00C04F79ABD1";
|
||||
private const string IIDIEnumIDList = "000214F2-0000-0000-C000-000000000046";
|
||||
private const string BHIDSFObject = "3981e224-f559-11d3-8e3a-00c04f6837d5";
|
||||
private const int KfFlagDefaultPath = 0x00000400;
|
||||
private const int SigdnNormalDisplay = 0;
|
||||
|
||||
[Flags]
|
||||
public enum Shcontf : int
|
||||
{
|
||||
Folders = 0x0020,
|
||||
NonFolders = 0x0040,
|
||||
IncludeHidden = 0x0080,
|
||||
InitOnFirstNext = 0x0100,
|
||||
NetPrinterSearch = 0x0200,
|
||||
Shareable = 0x0400,
|
||||
Storage = 0x0800,
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", Justification = "Targeting Windows (X86/AMD64/ARM) only")]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct Strret
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int UType;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public IntPtr POleStr;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public IntPtr PStr;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public int UOffset;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public IntPtr CStr;
|
||||
}
|
||||
|
||||
public enum Shgno
|
||||
{
|
||||
Normal = 0x0000,
|
||||
InFolder = 0x0001,
|
||||
ForEditing = 0x1000,
|
||||
ForAddressBar = 0x4000,
|
||||
ForParsing = 0x8000,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct SHELLDETAILS
|
||||
{
|
||||
public int Fmt;
|
||||
public int CxChar;
|
||||
public Strret Str;
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid(IIDIShellFolder2)]
|
||||
public interface IShellFolder2
|
||||
{
|
||||
[PreserveSig]
|
||||
int ParseDisplayName(IntPtr hwnd, IntPtr pbc, [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, ref int pchEaten, out IntPtr ppidl, ref int pdwAttributes);
|
||||
|
||||
[PreserveSig]
|
||||
int EnumObjects(IntPtr hwnd, Shcontf grfFlags, out IntPtr enumIDList);
|
||||
|
||||
[PreserveSig]
|
||||
int BindToObject(IntPtr pidl, IntPtr pbc, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int BindToStorage(IntPtr pidl, IntPtr pbc, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);
|
||||
|
||||
[PreserveSig]
|
||||
int CreateViewObject(IntPtr hwndOwner, Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetAttributesOf(int cidl, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, ref IntPtr rgfInOut);
|
||||
|
||||
[PreserveSig]
|
||||
int GetUIObjectOf(IntPtr hwndOwner, int cidl, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, ref Guid riid, IntPtr rgfReserved, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDisplayNameOf(IntPtr pidl, Shgno uFlags, out Strret lpName);
|
||||
|
||||
[PreserveSig]
|
||||
int SetNameOf(IntPtr hwnd, IntPtr pidl, [MarshalAs(UnmanagedType.LPWStr)] string pszName, int uFlags, out IntPtr ppidlOut);
|
||||
|
||||
[PreserveSig]
|
||||
int EnumSearches(out IntPtr ppenum);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDefaultColumn(int dwReserved, ref IntPtr pSort, out IntPtr pDisplay);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDefaultColumnState(int iColumn, out IntPtr pcsFlags);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDefaultSearchGUID(out IntPtr guid);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDetailsEx(IntPtr pidl, IntPtr pscid, out IntPtr pv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetDetailsOf(IntPtr pidl, int iColumn, ref SHELLDETAILS psd);
|
||||
|
||||
[PreserveSig]
|
||||
int MapColumnToSCID(int icolumn, IntPtr pscid);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid(IIDIEnumIDList)]
|
||||
public interface IEnumIDList
|
||||
{
|
||||
[PreserveSig]
|
||||
int Next(int celt, out IntPtr rgelt, out int pceltFetched);
|
||||
|
||||
[PreserveSig]
|
||||
int Skip(int celt);
|
||||
|
||||
[PreserveSig]
|
||||
int Reset();
|
||||
|
||||
[PreserveSig]
|
||||
int Clone(out IEnumIDList ppenum);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid(IIDIShellItem)]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IShellItem
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BindToHandler(IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int GetDisplayName([In] int sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetAttributes([In] int sfgaoMask, out int psfgaoAttribs);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SHFILEINFO
|
||||
{
|
||||
public IntPtr HIcon;
|
||||
public int IIcon;
|
||||
public uint DwAttributes;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
public string SzDisplayName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
|
||||
public string SzTypeName;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Blob
|
||||
{
|
||||
public int CbSize;
|
||||
public IntPtr PBlobData;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct PropVariant
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public short Vt;
|
||||
[FieldOffset(2)]
|
||||
public short WReserved1;
|
||||
[FieldOffset(4)]
|
||||
public short WReserved2;
|
||||
[FieldOffset(6)]
|
||||
public short WReserved3;
|
||||
[FieldOffset(8)]
|
||||
public sbyte CVal;
|
||||
[FieldOffset(8)]
|
||||
public byte BVal;
|
||||
[FieldOffset(8)]
|
||||
public short IVal;
|
||||
[FieldOffset(8)]
|
||||
public ushort UiVal;
|
||||
[FieldOffset(8)]
|
||||
public int LVal;
|
||||
[FieldOffset(8)]
|
||||
public uint UlVal;
|
||||
[FieldOffset(8)]
|
||||
public int IntVal;
|
||||
[FieldOffset(8)]
|
||||
public uint UintVal;
|
||||
[FieldOffset(8)]
|
||||
public long HVal;
|
||||
[FieldOffset(8)]
|
||||
public ulong UhVal;
|
||||
[FieldOffset(8)]
|
||||
public float FltVal;
|
||||
[FieldOffset(8)]
|
||||
public double DblVal;
|
||||
[FieldOffset(8)]
|
||||
public bool BoolVal;
|
||||
[FieldOffset(8)]
|
||||
public int Scode;
|
||||
[FieldOffset(8)]
|
||||
public DateTime Date;
|
||||
[FieldOffset(8)]
|
||||
public FileTime Filetime;
|
||||
[FieldOffset(8)]
|
||||
public Blob Blob;
|
||||
[FieldOffset(8)]
|
||||
public IntPtr P;
|
||||
[FieldOffset(8)]
|
||||
public CALPWSTR Calpwstr;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CALPWSTR
|
||||
{
|
||||
public uint CElems;
|
||||
public IntPtr PElems;
|
||||
}
|
||||
|
||||
public enum SIGDN : uint
|
||||
{
|
||||
NORMALDISPLAY = 0,
|
||||
PARENTRELATIVEPARSING = 0x80018001,
|
||||
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
|
||||
DESKTOPABSOLUTEPARSING = 0x80028000,
|
||||
PARENTRELATIVEEDITING = 0x80031001,
|
||||
DESKTOPABSOLUTEEDITING = 0x8004c000,
|
||||
FILESYSPATH = 0x80058000,
|
||||
URL = 0x80068000,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SYSTEMTIME
|
||||
{
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Year;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Month;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short DayOfWeek;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Day;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Hour;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Minute;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Second;
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public short Milliseconds;
|
||||
|
||||
public SYSTEMTIME(DateTime dt)
|
||||
{
|
||||
dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
|
||||
Year = (short)dt.Year;
|
||||
Month = (short)dt.Month;
|
||||
DayOfWeek = (short)dt.DayOfWeek;
|
||||
Day = (short)dt.Day;
|
||||
Hour = (short)dt.Hour;
|
||||
Minute = (short)dt.Minute;
|
||||
Second = (short)dt.Second;
|
||||
Milliseconds = (short)dt.Millisecond;
|
||||
}
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("7E9FB0D3-919F-4307-AB2E-9B1860310C93")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IShellItem2 : IShellItem
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new void BindToHandler(IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new int GetDisplayName([In] int sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new void GetAttributes([In] int sfgaoMask, out int psfgaoAttribs);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
new void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
|
||||
|
||||
[PreserveSig]
|
||||
int GetPropertyStore(int flags, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetPropertyStoreWithCreateObject(ref PropertyStoreFlags flags, ref IntPtr punkFactory, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetPropertyStoreForKeys(ref PropertyKey keys, uint cKeys, ref PropertyStoreFlags flags, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int GetPropertyDescriptionList(ref PropertyKey key, ref Guid riid, out IntPtr ppv);
|
||||
|
||||
[PreserveSig]
|
||||
int Update(ref IntPtr pbc);
|
||||
|
||||
[PreserveSig]
|
||||
int GetProperty(ref PropertyKey key, out PropVariant pPropVar);
|
||||
|
||||
[PreserveSig]
|
||||
int GetCLSID(ref PropertyKey key, out Guid clsid);
|
||||
|
||||
[PreserveSig]
|
||||
int GetFileTime(ref PropertyKey key, out FileTime pft);
|
||||
|
||||
[PreserveSig]
|
||||
int GetInt32(ref PropertyKey key, out int pi);
|
||||
|
||||
[PreserveSig]
|
||||
int GetString(ref PropertyKey key, [MarshalAs(UnmanagedType.LPWStr)] string ppsz);
|
||||
|
||||
[PreserveSig]
|
||||
int GetUint32(ref PropertyKey key, out uint pui);
|
||||
|
||||
[PreserveSig]
|
||||
int GetUint64(ref PropertyKey key, out uint pull);
|
||||
|
||||
[PreserveSig]
|
||||
int GetBool(ref PropertyKey key, bool pf);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FileTime
|
||||
{
|
||||
public int DWHighDateTime;
|
||||
public int DWLowDateTime;
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IPropertyStore
|
||||
{
|
||||
void GetCount(out uint propertyCount);
|
||||
|
||||
void GetAt(uint iProp, out PropertyKey pkey);
|
||||
|
||||
void GetValue(ref PropertyKey key, out PropVariant pv);
|
||||
|
||||
void SetValue(ref PropertyKey key, ref PropVariant pv);
|
||||
|
||||
void Commit();
|
||||
}
|
||||
|
||||
public enum PropertyStoreFlags
|
||||
{
|
||||
DEFAULT = 0x00000000,
|
||||
HANDLERPROPERTIESONLY = 0x00000001,
|
||||
READWRITE = 0x00000002,
|
||||
TEMPORARY = 0x00000004,
|
||||
FASTPROPERTIESONLY = 0x00000008,
|
||||
OPENSLOWITEM = 0x00000010,
|
||||
DELAYCREATION = 0x00000020,
|
||||
BESTEFFORT = 0x00000040,
|
||||
NO_OPLOCK = 0x00000080,
|
||||
PREFERQUERYPROPERTIES = 0x00000100,
|
||||
EXTRINSICPROPERTIES = 0x00000200,
|
||||
EXTRINSICPROPERTIESONLY = 0x00000400,
|
||||
MASK_VALID = 0x000007ff,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct PropertyKey
|
||||
{
|
||||
public Guid FormatId;
|
||||
public int PropertyId;
|
||||
|
||||
public PropertyKey(Guid guid, int propertyId)
|
||||
{
|
||||
this.FormatId = guid;
|
||||
this.PropertyId = propertyId;
|
||||
}
|
||||
|
||||
public PropertyKey(uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h, uint i, uint j, uint k, int propertyId)
|
||||
: this(new Guid((uint)a, (ushort)b, (ushort)c, (byte)d, (byte)e, (byte)f, (byte)g, (byte)h, (byte)i, (byte)j, (byte)k), propertyId)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if ((obj == null) || !(obj is PropertyKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyKey pk = (PropertyKey)obj;
|
||||
|
||||
return FormatId.Equals(pk.FormatId) && (PropertyId == pk.PropertyId);
|
||||
}
|
||||
|
||||
public static bool operator ==(PropertyKey a, PropertyKey b)
|
||||
{
|
||||
if (((object)a == null) || ((object)b == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.FormatId == b.FormatId && a.PropertyId == b.PropertyId;
|
||||
}
|
||||
|
||||
public static bool operator !=(PropertyKey a, PropertyKey b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return FormatId.GetHashCode() ^ PropertyId;
|
||||
}
|
||||
|
||||
// File properties: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wsp/2dbe759c-c955-4770-a545-e46d7f6332ed
|
||||
public static readonly PropertyKey ImageHorizontalSize = new PropertyKey(new Guid(0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 3);
|
||||
public static readonly PropertyKey ImageVerticalSize = new PropertyKey(new Guid(0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 4);
|
||||
public static readonly PropertyKey FileSizeBytes = new PropertyKey(new Guid(0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac), 12);
|
||||
public static readonly PropertyKey FileType = new PropertyKey(new Guid(0xd5cdd502, 0x2e9c, 0x101b, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae), 26);
|
||||
}
|
||||
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern int StrRetToBuf(ref Strret pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts a specified string from a specified resource via an indirect string
|
||||
/// </summary>
|
||||
/// <param name="pszSource">An indirect string representing the desired string from a specified resource file</param>
|
||||
/// <param name="pszOutBuf">An output string, which receives the native function's outputted resource string</param>
|
||||
/// <param name="cchOutBuf">The buffer size to hold the output string, in characters</param>
|
||||
/// <param name="ppvReserved">A reserved pointer (void**)</param>
|
||||
/// <returns>Returns an HRESULT representing the success/failure of the native function</returns>
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern uint SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved);
|
||||
|
||||
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out string pszPath);
|
||||
|
||||
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern int SHGetKnownFolderItem([In] ref Guid rfid, [In] int dwFlags, [In] IntPtr hToken, [In] ref Guid riid, [Out] out IntPtr ppv);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
|
||||
|
||||
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern int SHGetPropertyStoreFromParsingName(
|
||||
string pszPath,
|
||||
IntPtr zeroWorks,
|
||||
PropertyStoreFlags flags,
|
||||
ref Guid iIdPropStore,
|
||||
[Out] out IPropertyStore propertyStore);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
|
||||
private static extern void SHCreateItemFromParsingName(
|
||||
[In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
|
||||
[In] IntPtr pbc,
|
||||
[In][MarshalAs(UnmanagedType.LPStruct)] Guid riid,
|
||||
[Out][MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem2 ppv);
|
||||
}
|
||||
}
|
17
src/modules/peek/Peek.Common/Models/SHELLDETAILS.cs
Normal file
17
src/modules/peek/Peek.Common/Models/SHELLDETAILS.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using static Peek.Common.Helpers.PropertyStoreHelper;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct SHELLDETAILS
|
||||
{
|
||||
public int Fmt;
|
||||
public int CxChar;
|
||||
public Strret Str;
|
||||
}
|
||||
}
|
21
src/modules/peek/Peek.Common/Models/SHFILEINFO.cs
Normal file
21
src/modules/peek/Peek.Common/Models/SHFILEINFO.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SHFILEINFO
|
||||
{
|
||||
public IntPtr HIcon;
|
||||
public int IIcon;
|
||||
public uint DwAttributes;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
public string SzDisplayName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
|
||||
public string SzTypeName;
|
||||
}
|
||||
}
|
30
src/modules/peek/Peek.Common/Models/Strret.cs
Normal file
30
src/modules/peek/Peek.Common/Models/Strret.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.Common.Models
|
||||
{
|
||||
[SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", Justification = "Targeting Windows (X86/AMD64/ARM) only")]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct Strret
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int UType;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public IntPtr POleStr;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public IntPtr PStr;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public int UOffset;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public IntPtr CStr;
|
||||
}
|
||||
}
|
4
src/modules/peek/Peek.Common/NativeMethods.json
Normal file
4
src/modules/peek/Peek.Common/NativeMethods.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||
"public": true
|
||||
}
|
5
src/modules/peek/Peek.Common/NativeMethods.txt
Normal file
5
src/modules/peek/Peek.Common/NativeMethods.txt
Normal file
@ -0,0 +1,5 @@
|
||||
GETPROPERTYSTOREFLAGS
|
||||
_SHCONTF
|
||||
SIGDN
|
||||
SHGDNF
|
||||
SIATTRIBFLAGS
|
@ -10,6 +10,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.221116.1" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" />
|
||||
</ItemGroup>
|
||||
|
@ -27,8 +27,8 @@
|
||||
<controls:BrowserControl
|
||||
x:Name="BrowserPreview"
|
||||
x:Load="True"
|
||||
NavigationCompleted="PreviewBrowser_NavigationCompleted"
|
||||
DOMContentLoaded="BrowserPreview_DOMContentLoaded"
|
||||
NavigationCompleted="PreviewBrowser_NavigationCompleted"
|
||||
Source="{x:Bind BrowserPreviewer.Preview, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsPreviewVisible(BrowserPreviewer, Previewer.State), Mode=OneWay, FallbackValue=Collapsed}" />
|
||||
|
||||
|
@ -2,11 +2,13 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Peek.Common.Extensions;
|
||||
using Peek.Common.Helpers;
|
||||
using Peek.Common.Models;
|
||||
using Windows.Foundation;
|
||||
using Windows.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
namespace Peek.FilePreviewer.Previewers
|
||||
{
|
||||
@ -16,11 +18,11 @@ namespace Peek.FilePreviewer.Previewers
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var propertyStore = PropertyStoreShellApi.GetPropertyStoreFromPath(filePath, PropertyStoreShellApi.PropertyStoreFlags.OPENSLOWITEM);
|
||||
var propertyStore = PropertyStoreHelper.GetPropertyStoreFromPath(filePath, GETPROPERTYSTOREFLAGS.GPS_OPENSLOWITEM);
|
||||
if (propertyStore != null)
|
||||
{
|
||||
var width = (int)PropertyStoreShellApi.GetUIntFromPropertyStore(propertyStore, PropertyStoreShellApi.PropertyKey.ImageHorizontalSize);
|
||||
var height = (int)PropertyStoreShellApi.GetUIntFromPropertyStore(propertyStore, PropertyStoreShellApi.PropertyKey.ImageVerticalSize);
|
||||
var width = (int)propertyStore.GetUInt(PropertyKey.ImageHorizontalSize);
|
||||
var height = (int)propertyStore.GetUInt(PropertyKey.ImageVerticalSize);
|
||||
|
||||
Marshal.ReleaseComObject(propertyStore);
|
||||
return new Size(width, height);
|
||||
@ -33,10 +35,10 @@ namespace Peek.FilePreviewer.Previewers
|
||||
public static Task<ulong> GetFileSizeInBytes(string filePath)
|
||||
{
|
||||
ulong bytes = 0;
|
||||
var propertyStore = PropertyStoreShellApi.GetPropertyStoreFromPath(filePath, PropertyStoreShellApi.PropertyStoreFlags.OPENSLOWITEM);
|
||||
var propertyStore = PropertyStoreHelper.GetPropertyStoreFromPath(filePath, GETPROPERTYSTOREFLAGS.GPS_OPENSLOWITEM);
|
||||
if (propertyStore != null)
|
||||
{
|
||||
bytes = PropertyStoreShellApi.GetULongFromPropertyStore(propertyStore, PropertyStoreShellApi.PropertyKey.FileSizeBytes);
|
||||
bytes = propertyStore.GetULong(PropertyKey.FileSizeBytes);
|
||||
|
||||
Marshal.ReleaseComObject(propertyStore);
|
||||
}
|
||||
@ -47,11 +49,11 @@ namespace Peek.FilePreviewer.Previewers
|
||||
public static Task<string> GetFileType(string filePath)
|
||||
{
|
||||
var type = string.Empty;
|
||||
var propertyStore = PropertyStoreShellApi.GetPropertyStoreFromPath(filePath, PropertyStoreShellApi.PropertyStoreFlags.OPENSLOWITEM);
|
||||
var propertyStore = PropertyStoreHelper.GetPropertyStoreFromPath(filePath, GETPROPERTYSTOREFLAGS.GPS_OPENSLOWITEM);
|
||||
if (propertyStore != null)
|
||||
{
|
||||
// TODO: find a way to get user friendly description
|
||||
type = PropertyStoreShellApi.GetStringFromPropertyStore(propertyStore, PropertyStoreShellApi.PropertyKey.FileType);
|
||||
type = propertyStore.GetString(PropertyKey.FileType);
|
||||
|
||||
Marshal.ReleaseComObject(propertyStore);
|
||||
}
|
||||
|
45
src/modules/peek/Peek.UI/Extensions/HWNDExtensions.cs
Normal file
45
src/modules/peek/Peek.UI/Extensions/HWNDExtensions.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text;
|
||||
using Peek.UI.Native;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace Peek.UI.Extensions
|
||||
{
|
||||
public static class HWNDExtensions
|
||||
{
|
||||
internal static HWND GetActiveTab(this HWND windowHandle)
|
||||
{
|
||||
var activeTab = windowHandle.FindChildWindow("ShellTabWindowClass");
|
||||
if (activeTab == HWND.Null)
|
||||
{
|
||||
activeTab = windowHandle.FindChildWindow("TabWindowClass");
|
||||
}
|
||||
|
||||
return activeTab;
|
||||
}
|
||||
|
||||
internal static bool IsDesktopWindow(this HWND windowHandle)
|
||||
{
|
||||
StringBuilder strClassName = new StringBuilder(256);
|
||||
NativeMethods.GetClassName(windowHandle, strClassName, 256);
|
||||
|
||||
var className = strClassName.ToString();
|
||||
|
||||
if (className != "Progman" && className != "WorkerW")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return windowHandle.FindChildWindow("SHELLDLL_DefView") != HWND.Null;
|
||||
}
|
||||
|
||||
internal static HWND FindChildWindow(this HWND windowHandle, string className)
|
||||
{
|
||||
return PInvoke.FindWindowEx(windowHandle, HWND.Null, className, null);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
@ -36,18 +37,6 @@ namespace Peek.UI
|
||||
|
||||
private Task? InitializeFilesTask { get; set; } = null;
|
||||
|
||||
public static File? GetFileExplorerSelectedFile()
|
||||
{
|
||||
var shellItems = FileExplorerHelper.GetSelectedItems();
|
||||
var firstSelectedItem = shellItems?.Item(0);
|
||||
if (shellItems == null || firstSelectedItem == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new File(firstSelectedItem.Path);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
CurrentFile = null;
|
||||
@ -94,25 +83,21 @@ namespace Peek.UI
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var folderView = FileExplorerHelper.GetCurrentFolderView();
|
||||
if (folderView == null)
|
||||
var selectedItems = FileExplorerHelper.GetSelectedItems();
|
||||
if (!selectedItems.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Shell32.FolderItems selectedItems = folderView.SelectedItems();
|
||||
if (selectedItems == null || selectedItems.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsMultiSelection = selectedItems.Count > 1;
|
||||
bool hasMoreThanOneItem = selectedItems.Skip(1).Any();
|
||||
IsMultiSelection = hasMoreThanOneItem;
|
||||
|
||||
// Prioritize setting CurrentFile, which notifies UI
|
||||
var firstSelectedItem = selectedItems.Item(0);
|
||||
CurrentFile = new File(firstSelectedItem.Path);
|
||||
var firstSelectedItem = selectedItems.First();
|
||||
CurrentFile = firstSelectedItem;
|
||||
|
||||
var items = selectedItems.Count > 1 ? selectedItems : folderView.Folder?.Items();
|
||||
// TODO: we shouldn't get all files from the SHell API, we should query them
|
||||
var items = hasMoreThanOneItem ? selectedItems : FileExplorerHelper.GetItems();
|
||||
if (items == null)
|
||||
{
|
||||
return;
|
||||
@ -148,32 +133,14 @@ namespace Peek.UI
|
||||
// the entire folder. We can then avoid iterating through all items here, and maintain a dynamic window of
|
||||
// loaded items around the current item index.
|
||||
private void InitializeFiles(
|
||||
Shell32.FolderItems items,
|
||||
Shell32.FolderItem firstSelectedItem,
|
||||
IEnumerable<File> items,
|
||||
File firstSelectedItem,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tempFiles = new List<File>(items.Count);
|
||||
var tempCurIndex = UninitializedItemIndex;
|
||||
var listOfItems = items.ToList();
|
||||
var currentItemIndex = listOfItems.FindIndex(item => item.Path == firstSelectedItem.Path);
|
||||
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var item = items.Item(i);
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.Name == firstSelectedItem.Name)
|
||||
{
|
||||
tempCurIndex = i;
|
||||
}
|
||||
|
||||
tempFiles.Add(new File(item.Path));
|
||||
}
|
||||
|
||||
if (tempCurIndex == UninitializedItemIndex)
|
||||
if (currentItemIndex < 0)
|
||||
{
|
||||
Debug.WriteLine("File query initialization: selectedItem index not found. Navigation remains disabled.");
|
||||
return;
|
||||
@ -187,8 +154,8 @@ namespace Peek.UI
|
||||
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
Files = tempFiles;
|
||||
CurrentItemIndex = tempCurIndex;
|
||||
Files = listOfItems;
|
||||
CurrentItemIndex = currentItemIndex;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,58 +2,111 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Peek.UI.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Peek.Common.Models;
|
||||
using Peek.UI.Extensions;
|
||||
using SHDocVw;
|
||||
using Shell32;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using IServiceProvider = Peek.Common.Models.IServiceProvider;
|
||||
|
||||
namespace Peek.UI.Helpers
|
||||
{
|
||||
public static class FileExplorerHelper
|
||||
{
|
||||
public static Shell32.FolderItems? GetSelectedItems()
|
||||
public static IEnumerable<File> GetSelectedItems()
|
||||
{
|
||||
var folderView = GetCurrentFolderView();
|
||||
if (folderView == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Shell32.FolderItems selectedItems = folderView.SelectedItems();
|
||||
if (selectedItems == null || selectedItems.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return selectedItems;
|
||||
return GetItemsInternal(onlySelectedFiles: true);
|
||||
}
|
||||
|
||||
public static Shell32.IShellFolderViewDual2? GetCurrentFolderView()
|
||||
public static IEnumerable<File> GetItems()
|
||||
{
|
||||
var foregroundWindowHandle = NativeMethods.GetForegroundWindow();
|
||||
return GetItemsInternal(onlySelectedFiles: false);
|
||||
}
|
||||
|
||||
int capacity = PInvoke.GetWindowTextLength(new HWND(foregroundWindowHandle)) * 2;
|
||||
StringBuilder foregroundWindowTitleBuffer = new StringBuilder(capacity);
|
||||
NativeMethods.GetWindowText(new HWND(foregroundWindowHandle), foregroundWindowTitleBuffer, foregroundWindowTitleBuffer.Capacity);
|
||||
|
||||
string foregroundWindowTitle = foregroundWindowTitleBuffer.ToString();
|
||||
var directoryInfo = new DirectoryInfo(foregroundWindowTitle);
|
||||
string windowFolderName = directoryInfo.Name;
|
||||
|
||||
var shell = new Shell32.Shell();
|
||||
foreach (SHDocVw.InternetExplorer window in shell.Windows())
|
||||
private static IEnumerable<File> GetItemsInternal(bool onlySelectedFiles)
|
||||
{
|
||||
var foregroundWindowHandle = PInvoke.GetForegroundWindow();
|
||||
if (foregroundWindowHandle.IsDesktopWindow())
|
||||
{
|
||||
var shellFolderView = (Shell32.IShellFolderViewDual2)window.Document;
|
||||
return GetItemsFromDesktop(foregroundWindowHandle, onlySelectedFiles);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetItemsFromFileExplorer(foregroundWindowHandle, onlySelectedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<File> GetItemsFromDesktop(HWND foregroundWindowHandle, bool onlySelectedFiles)
|
||||
{
|
||||
const int SWC_DESKTOP = 8;
|
||||
const int SWFO_NEEDDISPATCH = 1;
|
||||
|
||||
var shell = new Shell();
|
||||
ShellWindows shellWindows = shell.Windows();
|
||||
object? oNull1 = null;
|
||||
object? oNull2 = null;
|
||||
var serviceProvider = (IServiceProvider)shellWindows.FindWindowSW(ref oNull1, ref oNull2, SWC_DESKTOP, out int pHWND, SWFO_NEEDDISPATCH);
|
||||
var shellBrowser = (IShellBrowser)serviceProvider.QueryService(PInvoke.SID_STopLevelBrowser, typeof(IShellBrowser).GUID);
|
||||
var shellView = (IFolderView)shellBrowser.QueryActiveShellView();
|
||||
|
||||
var selectionFlag = onlySelectedFiles ? (uint)_SVGIO.SVGIO_SELECTION : (uint)_SVGIO.SVGIO_ALLVIEW;
|
||||
shellView.Items(selectionFlag, typeof(IShellItemArray).GUID, out var items);
|
||||
if (items is IShellItemArray array)
|
||||
{
|
||||
return array.ToFilesEnumerable();
|
||||
}
|
||||
|
||||
return new List<File>();
|
||||
}
|
||||
|
||||
private static IEnumerable<File> GetItemsFromFileExplorer(HWND foregroundWindowHandle, bool onlySelectedFiles)
|
||||
{
|
||||
var activeTab = foregroundWindowHandle.GetActiveTab();
|
||||
|
||||
var shell = new Shell();
|
||||
ShellWindows shellWindows = shell.Windows();
|
||||
foreach (IWebBrowserApp webBrowserApp in shell.Windows())
|
||||
{
|
||||
var shellFolderView = (IShellFolderViewDual2)webBrowserApp.Document;
|
||||
var folderTitle = shellFolderView.Folder.Title;
|
||||
|
||||
if (window.HWND == (int)foregroundWindowHandle && folderTitle == windowFolderName)
|
||||
if (webBrowserApp.HWND == foregroundWindowHandle)
|
||||
{
|
||||
return shellFolderView;
|
||||
var serviceProvider = (IServiceProvider)webBrowserApp;
|
||||
var shellBrowser = (IShellBrowser)serviceProvider.QueryService(PInvoke.SID_STopLevelBrowser, typeof(IShellBrowser).GUID);
|
||||
shellBrowser.GetWindow(out IntPtr shellBrowserHandle);
|
||||
|
||||
if (activeTab == shellBrowserHandle)
|
||||
{
|
||||
var items = onlySelectedFiles ? shellFolderView.SelectedItems() : shellFolderView.Folder?.Items();
|
||||
return items != null ? items.ToFilesEnumerable() : new List<File>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return new List<File>();
|
||||
}
|
||||
|
||||
private static IEnumerable<File> ToFilesEnumerable(this IShellItemArray array)
|
||||
{
|
||||
for (var i = 0; i < array.GetCount(); i++)
|
||||
{
|
||||
var item = array.GetItemAt(i);
|
||||
var path = item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH);
|
||||
yield return new File(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<File> ToFilesEnumerable(this FolderItems folderItems)
|
||||
{
|
||||
foreach (FolderItem item in folderItems)
|
||||
{
|
||||
yield return new File(item.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using interop;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
@ -152,19 +153,13 @@ namespace Peek.UI
|
||||
|
||||
private bool IsNewSingleSelectedItem()
|
||||
{
|
||||
var folderView = FileExplorerHelper.GetCurrentFolderView();
|
||||
if (folderView == null)
|
||||
var selectedItems = FileExplorerHelper.GetSelectedItems();
|
||||
if (!selectedItems.Any() || selectedItems.Skip(1).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Shell32.FolderItems selectedItems = folderView.SelectedItems();
|
||||
if (selectedItems.Count > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fileExplorerSelectedItemPath = selectedItems.Item(0)?.Path;
|
||||
var fileExplorerSelectedItemPath = selectedItems.First().Path;
|
||||
var currentFilePath = ViewModel.FolderItemsQuery.CurrentFile?.Path;
|
||||
if (fileExplorerSelectedItemPath == null || currentFilePath == null || fileExplorerSelectedItemPath == currentFilePath)
|
||||
{
|
||||
|
@ -43,13 +43,13 @@ namespace Peek.UI.Native
|
||||
DDETopic,
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern HResult AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string? pszExtra, [Out] StringBuilder? pszOut, [In][Out] ref uint pcchOut);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern int GetWindowText(Windows.Win32.Foundation.HWND hWnd, StringBuilder lpString, int nMaxCount);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int GetClassName(IntPtr hWnd, StringBuilder buf, int nMaxCount);
|
||||
}
|
||||
}
|
||||
|
@ -7,4 +7,8 @@ GetCurrentThreadId
|
||||
AttachThreadInput
|
||||
BringWindowToTop
|
||||
ShowWindow
|
||||
GetWindowTextLength
|
||||
GetWindowTextLength
|
||||
FindWindowEx
|
||||
SID_STopLevelBrowser
|
||||
GetClassName
|
||||
_SVGIO
|
Loading…
Reference in New Issue
Block a user