mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
use stackalloc if possible and fix some incorrect use of safehandle
This commit is contained in:
parent
6f899092b5
commit
0153f71083
8 changed files with 96 additions and 96 deletions
|
|
@ -88,7 +88,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
PInvoke.UnhookWindowsHookEx(new HHOOK(hookId.DangerousGetHandle()));
|
||||
hookId.Dispose();
|
||||
}
|
||||
|
||||
~GlobalHotkey()
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
CheckSecurityWindow();
|
||||
Thread.Sleep(25);
|
||||
}
|
||||
|
||||
while (containsSecurityWindow) // while this process contains a "Windows Security" dialog, stay open
|
||||
{
|
||||
containsSecurityWindow = false;
|
||||
|
|
@ -52,24 +53,20 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
private static unsafe string GetWindowTitle(HWND hwnd)
|
||||
{
|
||||
var capacity = PInvoke.GetWindowTextLength(hwnd) + 1;
|
||||
char[] buffer = new char[capacity];
|
||||
int length;
|
||||
Span<char> buffer = stackalloc char[capacity];
|
||||
fixed (char* pBuffer = buffer)
|
||||
{
|
||||
// If the window has no title bar or text, if the title bar is empty,
|
||||
// or if the window or control handle is invalid, the return value is zero.
|
||||
if (PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity) == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Truncate the buffer to the actual length of the string
|
||||
int validLength = Array.IndexOf(buffer, '\0');
|
||||
if (validLength < 0) validLength = capacity;
|
||||
return new string(buffer, 0, validLength);
|
||||
length = PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity);
|
||||
}
|
||||
|
||||
return buffer[..length].ToString();
|
||||
}
|
||||
|
||||
public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "", bool createNoWindow = false)
|
||||
public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "",
|
||||
string arguments = "", string verb = "", bool createNoWindow = false)
|
||||
{
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Dwm;
|
||||
using Windows.Win32.UI.Controls;
|
||||
|
||||
|
|
@ -38,24 +39,22 @@ public class DwmDropShadow
|
|||
/// </summary>
|
||||
/// <param name="window">Window to which the shadow will be applied</param>
|
||||
/// <returns>True if the method succeeded, false if not</returns>
|
||||
private unsafe static bool DropShadow(Window window)
|
||||
private static unsafe bool DropShadow(Window window)
|
||||
{
|
||||
try
|
||||
{
|
||||
WindowInteropHelper helper = new WindowInteropHelper(window);
|
||||
int val = 2;
|
||||
int ret1 = PInvoke.DwmSetWindowAttribute(new(helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
|
||||
var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
|
||||
|
||||
if (ret1 == 0)
|
||||
if (ret1 == HRESULT.S_OK)
|
||||
{
|
||||
var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 };
|
||||
int ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
|
||||
return ret2 == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
var ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
|
||||
return ret2 == HRESULT.S_OK;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using Microsoft.Win32;
|
||||
using Windows.Win32;
|
||||
|
|
@ -9,19 +12,17 @@ namespace Flow.Launcher.Helper;
|
|||
|
||||
public static class WallpaperPathRetrieval
|
||||
{
|
||||
|
||||
private static readonly int MAX_PATH = 260;
|
||||
|
||||
public static unsafe string GetWallpaperPath()
|
||||
{
|
||||
var wallpaper = new StringBuilder(MAX_PATH);
|
||||
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH, &wallpaper, 0);
|
||||
|
||||
var str = wallpaper.ToString();
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return null;
|
||||
|
||||
return str;
|
||||
var wallpaperPtr = stackalloc char[MAX_PATH];
|
||||
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH,
|
||||
wallpaperPtr,
|
||||
0);
|
||||
var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr);
|
||||
|
||||
return wallpaper.ToString();
|
||||
}
|
||||
|
||||
public static Color GetWallpaperColor()
|
||||
|
|
@ -32,13 +33,14 @@ public static class WallpaperPathRetrieval
|
|||
{
|
||||
try
|
||||
{
|
||||
var parts = strResult.Trim().Split(new[] {' '}, 3).Select(byte.Parse).ToList();
|
||||
var parts = strResult.Trim().Split(new[] { ' ' }, 3).Select(byte.Parse).ToList();
|
||||
return Color.FromRgb(parts[0], parts[1], parts[2]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return Colors.Transparent;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Interop;
|
||||
|
|
@ -56,18 +58,17 @@ public class WindowsInteropHelper
|
|||
}
|
||||
|
||||
string windowClass;
|
||||
int capacity = 256;
|
||||
char[] buffer = new char[capacity];
|
||||
const int capacity = 256;
|
||||
Span<char> buffer = stackalloc char[capacity];
|
||||
int validLength;
|
||||
fixed (char* pBuffer = buffer)
|
||||
{
|
||||
PInvoke.GetClassName(hWnd, pBuffer, capacity);
|
||||
|
||||
// Truncate the buffer to the actual length of the string
|
||||
int validLength = Array.IndexOf(buffer, '\0');
|
||||
if (validLength < 0) validLength = capacity;
|
||||
windowClass = new string(buffer, 0, validLength);
|
||||
validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity);
|
||||
}
|
||||
|
||||
windowClass = buffer[..validLength].ToString();
|
||||
|
||||
|
||||
//for Win+Tab (Flip3D)
|
||||
if (windowClass == WINDOW_CLASS_WINTAB)
|
||||
{
|
||||
|
|
@ -87,14 +88,15 @@ public class WindowsInteropHelper
|
|||
{
|
||||
var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
|
||||
hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
|
||||
if (!hWndDesktop.Equals(IntPtr.Zero))
|
||||
if (hWndDesktop.Value != (IntPtr.Zero))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
|
||||
return (appBounds.bottom - appBounds.top) == screenBounds.Height && (appBounds.right - appBounds.left) == screenBounds.Width;
|
||||
return (appBounds.bottom - appBounds.top) == screenBounds.Height &&
|
||||
(appBounds.right - appBounds.left) == screenBounds.Width;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -104,7 +106,23 @@ public class WindowsInteropHelper
|
|||
public static void DisableControlBox(Window win)
|
||||
{
|
||||
var hwnd = new HWND(new WindowInteropHelper(win).Handle);
|
||||
PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE) & ~(int)WINDOW_STYLE.WS_SYSMENU);
|
||||
|
||||
var style = PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
|
||||
|
||||
if (style == 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
||||
}
|
||||
|
||||
style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
|
||||
|
||||
var previousStyle = PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE,
|
||||
style);
|
||||
|
||||
if (previousStyle == 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -127,6 +145,7 @@ public class WindowsInteropHelper
|
|||
using var src = new HwndSource(new HwndSourceParameters());
|
||||
matrix = src.CompositionTarget.TransformFromDevice;
|
||||
}
|
||||
|
||||
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
|
||||
using var safeHandle = new SafeProcessHandle(handle.Value, true);
|
||||
uint capacity = 2000;
|
||||
char[] buffer = new char[capacity];
|
||||
Span<char> buffer = new char[capacity];
|
||||
fixed (char* pBuffer = buffer)
|
||||
{
|
||||
if (!PInvoke.QueryFullProcessImageName(safeHandle, PROCESS_NAME_FORMAT.PROCESS_NAME_WIN32, (PWSTR)pBuffer, ref capacity))
|
||||
|
|
@ -106,10 +106,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
// Truncate the buffer to the actual length of the string
|
||||
int validLength = Array.IndexOf(buffer, '\0');
|
||||
if (validLength < 0) validLength = (int)capacity;
|
||||
return new string(buffer, 0, validLength);
|
||||
return buffer[..(int)capacity].ToString();
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
((IShellLinkW)link).Resolve(hwnd, 0);
|
||||
|
||||
const int MAX_PATH = 260;
|
||||
char[] buffer = new char[MAX_PATH];
|
||||
Span<char> buffer = stackalloc char[MAX_PATH];
|
||||
|
||||
var data = new WIN32_FIND_DATAW();
|
||||
var target = string.Empty;
|
||||
fixed (char* bufferChar = buffer)
|
||||
fixed (char* bufferPtr = buffer)
|
||||
{
|
||||
((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH);
|
||||
target = GetStringFromBuffer(buffer, MAX_PATH);
|
||||
((IShellLinkW)link).GetPath((PWSTR)bufferPtr, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH);
|
||||
target = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
|
||||
}
|
||||
|
||||
// To set the app description
|
||||
|
|
@ -46,11 +46,10 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
{
|
||||
try
|
||||
{
|
||||
char[] buffer1 = new char[MAX_PATH];
|
||||
fixed (char* buffer1Char = buffer1)
|
||||
fixed (char* bufferPtr = buffer)
|
||||
{
|
||||
((IShellLinkW)link).GetDescription((PWSTR)buffer1Char, MAX_PATH);
|
||||
description = GetStringFromBuffer(buffer1, MAX_PATH);
|
||||
((IShellLinkW)link).GetDescription(bufferPtr, MAX_PATH);
|
||||
description = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
|
||||
}
|
||||
}
|
||||
catch (COMException e)
|
||||
|
|
@ -61,11 +60,10 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
e);
|
||||
}
|
||||
|
||||
char[] buffer2 = new char[MAX_PATH];
|
||||
fixed (char* buffer2Char = buffer2)
|
||||
fixed (char* bufferPtr = buffer)
|
||||
{
|
||||
((IShellLinkW)link).GetArguments((PWSTR)buffer2Char, MAX_PATH);
|
||||
arguments = GetStringFromBuffer(buffer2, MAX_PATH);
|
||||
((IShellLinkW)link).GetArguments(bufferPtr, MAX_PATH);
|
||||
arguments = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,13 +72,5 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
return target;
|
||||
}
|
||||
|
||||
private static unsafe string GetStringFromBuffer(char[] buffer, int maxLength)
|
||||
{
|
||||
// Truncate the buffer to the actual length of the string
|
||||
int validLength = Array.IndexOf(buffer, '\0');
|
||||
if (validLength < 0) validLength = maxLength;
|
||||
return new string(buffer, 0, validLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.LibraryLoader;
|
||||
|
|
@ -20,39 +21,34 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
/// <returns>The localized name as string or <see cref="string.Empty"/>.</returns>
|
||||
public static unsafe string GetLocalizedName(string path)
|
||||
{
|
||||
int capacity = 1024;
|
||||
char[] resourcePathBuffer = new char[capacity];
|
||||
const int capacity = 1024;
|
||||
Span<char> buffer = new char[capacity];
|
||||
|
||||
// If there is no resource to localize a file name the method returns a non zero value.
|
||||
fixed (char* resourcePath = resourcePathBuffer)
|
||||
fixed (char* bufferPtr = buffer)
|
||||
{
|
||||
var result = PInvoke.SHGetLocalizedName(path, (PWSTR)resourcePath, (uint)capacity, out var id);
|
||||
if (result == HRESULT.S_OK)
|
||||
var result = PInvoke.SHGetLocalizedName(path, bufferPtr, capacity, out var id);
|
||||
if (result != HRESULT.S_OK)
|
||||
{
|
||||
int validLength = Array.IndexOf(resourcePathBuffer, '\0');
|
||||
if (validLength < 0) validLength = capacity;
|
||||
var resourcePathStr = new string(resourcePathBuffer, 0, validLength);
|
||||
_ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, resourcePath, (uint)capacity);
|
||||
var handle = PInvoke.LoadLibraryEx(resourcePathStr,
|
||||
LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE);
|
||||
IntPtr safeHandle = handle.DangerousGetHandle();
|
||||
if (safeHandle != IntPtr.Zero)
|
||||
{
|
||||
char[] localizedNameBuffer = new char[capacity];
|
||||
fixed (char* localizedName = localizedNameBuffer)
|
||||
{
|
||||
if (PInvoke.LoadString(handle, (uint)id, (PWSTR)localizedName, capacity) != 0)
|
||||
{
|
||||
validLength = Array.IndexOf(localizedNameBuffer, '\0');
|
||||
if (validLength < 0) validLength = capacity;
|
||||
var lString = new string(localizedNameBuffer, 0, validLength);
|
||||
PInvoke.FreeLibrary(new(safeHandle));
|
||||
return lString;
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
PInvoke.FreeLibrary(new(safeHandle));
|
||||
}
|
||||
var resourcePathStr = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
|
||||
_ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, bufferPtr, capacity);
|
||||
using var handle = PInvoke.LoadLibraryEx(resourcePathStr,
|
||||
LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE);
|
||||
if (handle.IsInvalid)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// not sure about the behavior of Pinvoke.LoadString, so we clear the buffer before using it (so it must be a null-terminated string)
|
||||
buffer.Clear();
|
||||
|
||||
if (PInvoke.LoadString(handle, (uint)id, bufferPtr, capacity) != 0)
|
||||
{
|
||||
var lString = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
|
||||
return lString;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue