From f461ff0ff0d3acfdcc8095206facb98ea32a53c8 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Sat, 17 May 2025 16:02:45 +0100 Subject: [PATCH] Unfinished --- src/Files.App.CsWin32/Extras.cs | 19 ++++++ src/Files.App.CsWin32/NativeMethods.txt | 5 ++ .../Files.App.Launcher.exe.sha256 | 2 +- .../Helpers/Win32/Win32Helper.Storage.cs | 31 +++++++++ src/Files.App/Utils/Shell/ContextMenu.cs | 68 +++++++++---------- 5 files changed, 90 insertions(+), 35 deletions(-) diff --git a/src/Files.App.CsWin32/Extras.cs b/src/Files.App.CsWin32/Extras.cs index 422d9fbdfc68..0c4dab91fb6c 100644 --- a/src/Files.App.CsWin32/Extras.cs +++ b/src/Files.App.CsWin32/Extras.cs @@ -44,6 +44,25 @@ public static unsafe nint SetWindowLongPtr(HWND hWnd, WINDOW_LONG_PTR_INDEX nInd public const int PixelFormat32bppARGB = 2498570; } + namespace Foundation + { + public partial struct PCSTR + { + public static unsafe PCSTR FromString(string value) + { + fixed (byte* p = global::System.Text.Encoding.UTF8.GetBytes(value)) + { + return new PCSTR(p); + } + } + + public static unsafe PCSTR FromInt(int value) + { + return new PCSTR((byte*)&value); + } + } + } + namespace Extras { [GeneratedComInterface, Guid("EACDD04C-117E-4E17-88F4-D1B12B0E3D89"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index ce5524f6885e..6d7d7d05063e 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -225,3 +225,8 @@ QITIPF_FLAGS GetKeyboardState MapVirtualKey GetKeyboardLayout +MENUITEMINFO +GetMenuItemCount +GetMenuItemInfo +IContextMenu2 +CreateMenu diff --git a/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 b/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 index 11864831640e..d10eaa1f245a 100644 --- a/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 +++ b/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 @@ -1 +1 @@ -cb1ca000ef2f03f1afc7bde9ed4fb2987669c89a58b63919e67574696091f60f +04fb6dcd84d19b858484bd1812b2361d06897f802eabaf430ec8799e1b3ca1f9 diff --git a/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs b/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs index 7e878896a3f9..46d64eea3eb5 100644 --- a/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs +++ b/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs @@ -602,6 +602,37 @@ public static Task MountVhdDisk(string vhdPath) } } + public static Bitmap? GetBitmapFromHBitmap(Windows.Win32.Graphics.Gdi.HBITMAP hBitmap) + { + try + { + Bitmap bmp = Image.FromHbitmap((IntPtr)hBitmap); + if (Image.GetPixelFormatSize(bmp.PixelFormat) < 32) + return bmp; + + Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); + var bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); + + if (IsAlphaBitmap(bmpData)) + { + var alpha = GetAlphaBitmapFromBitmapData(bmpData); + + bmp.UnlockBits(bmpData); + bmp.Dispose(); + + return alpha; + } + + bmp.UnlockBits(bmpData); + + return bmp; + } + catch + { + return null; + } + } + public static Shell32.ITaskbarList4? CreateTaskbarObject() { try diff --git a/src/Files.App/Utils/Shell/ContextMenu.cs b/src/Files.App/Utils/Shell/ContextMenu.cs index b409ba730c03..3811aa6a02b7 100644 --- a/src/Files.App/Utils/Shell/ContextMenu.cs +++ b/src/Files.App/Utils/Shell/ContextMenu.cs @@ -3,11 +3,11 @@ using System.Drawing; using System.Runtime.InteropServices; -using Vanara.InteropServices; -using Vanara.PInvoke; -using Vanara.Windows.Shell; using Windows.Win32; using Windows.Win32.UI.WindowsAndMessaging; +using Windows.Win32.UI.Shell; +using Windows.Win32.Foundation; +using Windows.Win32.Graphics.Gdi; namespace Files.App.Utils.Shell { @@ -16,9 +16,9 @@ namespace Files.App.Utils.Shell /// public partial class ContextMenu : Win32ContextMenu, IDisposable { - private Shell32.IContextMenu _cMenu; + private IContextMenu _cMenu; - private User32.SafeHMENU _hMenu; + private HMENU _hMenu; private readonly ThreadWithMessageQueue _owningThread; @@ -31,7 +31,7 @@ public partial class ContextMenu : Win32ContextMenu, IDisposable public List ItemsPath { get; } - private ContextMenu(Shell32.IContextMenu cMenu, User32.SafeHMENU hMenu, IEnumerable itemsPath, ThreadWithMessageQueue owningThread, Func? itemFilter) + private ContextMenu(IContextMenu cMenu, HMENU hMenu, IEnumerable itemsPath, ThreadWithMessageQueue owningThread, Func? itemFilter) { _cMenu = cMenu; _hMenu = hMenu; @@ -64,10 +64,10 @@ public async Task InvokeVerb(string? verb) { var currentWindows = Win32Helper.GetDesktopWindows(); - var pici = new Shell32.CMINVOKECOMMANDINFOEX + var pici = new CMINVOKECOMMANDINFO { - lpVerb = new SafeResourceId(verb, CharSet.Ansi), - nShow = ShowWindowCommand.SW_SHOWNORMAL, + lpVerb = PCSTR.FromString(verb), + nShow = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL }; pici.cbSize = (uint)Marshal.SizeOf(pici); @@ -93,15 +93,15 @@ public async Task InvokeItem(int itemID, string? workingDirectory = null) try { var currentWindows = Win32Helper.GetDesktopWindows(); - var pici = new Shell32.CMINVOKECOMMANDINFOEX + var pici = new CMINVOKECOMMANDINFO { - lpVerb = Macros.MAKEINTRESOURCE(itemID), - nShow = ShowWindowCommand.SW_SHOWNORMAL, + lpVerb = PCSTR.FromInt(itemID), + nShow = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL, }; pici.cbSize = (uint)Marshal.SizeOf(pici); if (workingDirectory is not null) - pici.lpDirectoryW = workingDirectory; + pici.lpDirectory = PCSTR.FromString(workingDirectory); await _owningThread.PostMethod(() => _cMenu.InvokeCommand(pici)); Win32Helper.BringToForeground(currentWindows); @@ -161,9 +161,9 @@ public async Task InvokeItem(int itemID, string? workingDirectory = null) // NOTE: The items are all in the same folder using var sf = shellItems[0].Parent; - Shell32.IContextMenu menu = sf.GetChildrenUIObjects(default, shellItems); - var hMenu = User32.CreatePopupMenu(); - menu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, (Shell32.CMF)flags); + IContextMenu menu = sf.GetChildrenUIObjects(default, shellItems); + var hMenu = PInvoke.CreatePopupMenu(); + menu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, flags); var contextMenu = new ContextMenu(menu, hMenu, shellItems.Select(x => x.ParsingName), owningThread, itemFilter); contextMenu.EnumMenuItems(hMenu, contextMenu.Items); @@ -181,18 +181,18 @@ public static async Task WarmUpQueryContextMenuAsync() using var cMenu = await GetContextMenuForFiles(new string[] { $@"{Constants.UserEnvironmentPaths.SystemDrivePath}\" }, PInvoke.CMF_NORMAL); } - private void EnumMenuItems(Vanara.PInvoke.HMENU hMenu, List menuItemsResult, bool loadSubenus = false) + private void EnumMenuItems(HMENU hMenu, List menuItemsResult, bool loadSubenus = false) { - var itemCount = User32.GetMenuItemCount(hMenu); + var itemCount = PInvoke.GetMenuItemCount(hMenu); - var menuItemInfo = new User32.MENUITEMINFO() + var menuItemInfo = new MENUITEMINFOW() { fMask = - User32.MenuItemInfoMask.MIIM_BITMAP | - User32.MenuItemInfoMask.MIIM_FTYPE | - User32.MenuItemInfoMask.MIIM_STRING | - User32.MenuItemInfoMask.MIIM_ID | - User32.MenuItemInfoMask.MIIM_SUBMENU, + MENU_ITEM_MASK.MIIM_BITMAP | + MENU_ITEM_MASK.MIIM_FTYPE | + MENU_ITEM_MASK.MIIM_STRING | + MENU_ITEM_MASK.MIIM_ID | + MENU_ITEM_MASK.MIIM_SUBMENU, }; menuItemInfo.cbSize = (uint)Marshal.SizeOf(menuItemInfo); @@ -200,15 +200,15 @@ private void EnumMenuItems(Vanara.PInvoke.HMENU hMenu, List(); @@ -267,7 +267,7 @@ void LoadSubMenu() { try { - cMenu2?.HandleMenuMsg((uint)User32.WindowMessage.WM_INITMENUPOPUP, (IntPtr)hSubMenu, new IntPtr(index)); + cMenu2?.HandleMenuMsg(PInvoke.WM_INITMENUPOPUP, (IntPtr)hSubMenu, new IntPtr(index)); } catch (Exception ex) when (ex is InvalidCastException or ArgumentException) { @@ -316,7 +316,7 @@ public Task LoadSubMenu(List subItems) } } - private static string? GetCommandString(Shell32.IContextMenu cMenu, uint offset, Shell32.GCS flags = Shell32.GCS.GCS_VERBW) + private static string? GetCommandString(IContextMenu cMenu, uint offset, GCS flags = GCS.GCS_VERBW) { // A workaround to avoid an AccessViolationException on some items, // notably the "Run with graphic processor" menu item of NVIDIA cards @@ -325,11 +325,11 @@ public Task LoadSubMenu(List subItems) return null; } - SafeCoTaskMemString? commandString = null; + PSTR? commandString = null; try { - commandString = new SafeCoTaskMemString(512); + commandString = new PSTR(512); cMenu.GetCommandString(new IntPtr(offset), flags, IntPtr.Zero, commandString, (uint)commandString.Capacity - 1); Debug.WriteLine("Verb {0}: {1}", offset, commandString); @@ -374,7 +374,7 @@ protected virtual void Dispose(bool disposing) // TODO: Free unmanaged resources (unmanaged objects) and override a finalizer below if (_hMenu is not null) { - User32.DestroyMenu(_hMenu); + PInvoke.DestroyMenu(_hMenu); _hMenu = null; } if (_cMenu is not null)