use stackalloc if possible and fix some incorrect use of safehandle

This commit is contained in:
Hongtao Zhang 2024-12-25 11:20:09 -06:00
parent 6f899092b5
commit 0153f71083
8 changed files with 96 additions and 96 deletions

View file

@ -88,7 +88,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey
public void Dispose()
{
PInvoke.UnhookWindowsHookEx(new HHOOK(hookId.DangerousGetHandle()));
hookId.Dispose();
}
~GlobalHotkey()

View file

@ -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
{

View file

@ -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)
{

View file

@ -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;
}
}

View file

@ -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));
}
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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;
}
}