Skip to content

Commit 0153f71

Browse files
committed
use stackalloc if possible and fix some incorrect use of safehandle
1 parent 6f89909 commit 0153f71

File tree

8 files changed

+96
-96
lines changed

8 files changed

+96
-96
lines changed

Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private static LRESULT HookKeyboardCallback(int nCode, WPARAM wParam, LPARAM lPa
8888

8989
public void Dispose()
9090
{
91-
PInvoke.UnhookWindowsHookEx(new HHOOK(hookId.DangerousGetHandle()));
91+
hookId.Dispose();
9292
}
9393

9494
~GlobalHotkey()

Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public static Process RunAsDifferentUser(ProcessStartInfo processStartInfo)
2525
CheckSecurityWindow();
2626
Thread.Sleep(25);
2727
}
28+
2829
while (containsSecurityWindow) // while this process contains a "Windows Security" dialog, stay open
2930
{
3031
containsSecurityWindow = false;
@@ -52,24 +53,20 @@ private static BOOL CheckSecurityThread(HWND hwnd, LPARAM lParam)
5253
private static unsafe string GetWindowTitle(HWND hwnd)
5354
{
5455
var capacity = PInvoke.GetWindowTextLength(hwnd) + 1;
55-
char[] buffer = new char[capacity];
56+
int length;
57+
Span<char> buffer = stackalloc char[capacity];
5658
fixed (char* pBuffer = buffer)
5759
{
5860
// If the window has no title bar or text, if the title bar is empty,
5961
// or if the window or control handle is invalid, the return value is zero.
60-
if (PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity) == 0)
61-
{
62-
return string.Empty;
63-
}
64-
65-
// Truncate the buffer to the actual length of the string
66-
int validLength = Array.IndexOf(buffer, '\0');
67-
if (validLength < 0) validLength = capacity;
68-
return new string(buffer, 0, validLength);
62+
length = PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity);
6963
}
64+
65+
return buffer[..length].ToString();
7066
}
7167

72-
public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "", string arguments = "", string verb = "", bool createNoWindow = false)
68+
public static ProcessStartInfo SetProcessStartInfo(this string fileName, string workingDirectory = "",
69+
string arguments = "", string verb = "", bool createNoWindow = false)
7370
{
7471
var info = new ProcessStartInfo
7572
{

Flow.Launcher/Helper/DWMDropShadow.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Windows;
33
using System.Windows.Interop;
44
using Windows.Win32;
5+
using Windows.Win32.Foundation;
56
using Windows.Win32.Graphics.Dwm;
67
using Windows.Win32.UI.Controls;
78

@@ -38,24 +39,22 @@ private static void window_SourceInitialized(object sender, EventArgs e) //fixed
3839
/// </summary>
3940
/// <param name="window">Window to which the shadow will be applied</param>
4041
/// <returns>True if the method succeeded, false if not</returns>
41-
private unsafe static bool DropShadow(Window window)
42+
private static unsafe bool DropShadow(Window window)
4243
{
4344
try
4445
{
4546
WindowInteropHelper helper = new WindowInteropHelper(window);
4647
int val = 2;
47-
int ret1 = PInvoke.DwmSetWindowAttribute(new(helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
48+
var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
4849

49-
if (ret1 == 0)
50+
if (ret1 == HRESULT.S_OK)
5051
{
5152
var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 };
52-
int ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
53-
return ret2 == 0;
54-
}
55-
else
56-
{
57-
return false;
53+
var ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
54+
return ret2 == HRESULT.S_OK;
5855
}
56+
57+
return false;
5958
}
6059
catch (Exception)
6160
{
Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
using System.Linq;
1+
using System;
2+
using System.Linq;
3+
using System.Runtime.InteropServices;
24
using System.Text;
5+
using System.Windows.Documents;
36
using System.Windows.Media;
47
using Microsoft.Win32;
58
using Windows.Win32;
@@ -9,19 +12,17 @@ namespace Flow.Launcher.Helper;
912

1013
public static class WallpaperPathRetrieval
1114
{
12-
1315
private static readonly int MAX_PATH = 260;
1416

1517
public static unsafe string GetWallpaperPath()
1618
{
17-
var wallpaper = new StringBuilder(MAX_PATH);
18-
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH, &wallpaper, 0);
19-
20-
var str = wallpaper.ToString();
21-
if (string.IsNullOrEmpty(str))
22-
return null;
23-
24-
return str;
19+
var wallpaperPtr = stackalloc char[MAX_PATH];
20+
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH,
21+
wallpaperPtr,
22+
0);
23+
var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr);
24+
25+
return wallpaper.ToString();
2526
}
2627

2728
public static Color GetWallpaperColor()
@@ -32,13 +33,14 @@ public static Color GetWallpaperColor()
3233
{
3334
try
3435
{
35-
var parts = strResult.Trim().Split(new[] {' '}, 3).Select(byte.Parse).ToList();
36+
var parts = strResult.Trim().Split(new[] { ' ' }, 3).Select(byte.Parse).ToList();
3637
return Color.FromRgb(parts[0], parts[1], parts[2]);
3738
}
3839
catch
3940
{
4041
}
4142
}
43+
4244
return Colors.Transparent;
4345
}
4446
}

Flow.Launcher/Helper/WindowsInteropHelper.cs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
2+
using System.ComponentModel;
23
using System.Drawing;
4+
using System.Runtime.InteropServices;
35
using System.Windows;
46
using System.Windows.Forms;
57
using System.Windows.Interop;
@@ -56,18 +58,17 @@ public unsafe static bool IsWindowFullscreen()
5658
}
5759

5860
string windowClass;
59-
int capacity = 256;
60-
char[] buffer = new char[capacity];
61+
const int capacity = 256;
62+
Span<char> buffer = stackalloc char[capacity];
63+
int validLength;
6164
fixed (char* pBuffer = buffer)
6265
{
63-
PInvoke.GetClassName(hWnd, pBuffer, capacity);
64-
65-
// Truncate the buffer to the actual length of the string
66-
int validLength = Array.IndexOf(buffer, '\0');
67-
if (validLength < 0) validLength = capacity;
68-
windowClass = new string(buffer, 0, validLength);
66+
validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity);
6967
}
7068

69+
windowClass = buffer[..validLength].ToString();
70+
71+
7172
//for Win+Tab (Flip3D)
7273
if (windowClass == WINDOW_CLASS_WINTAB)
7374
{
@@ -87,14 +88,15 @@ public unsafe static bool IsWindowFullscreen()
8788
{
8889
var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
8990
hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
90-
if (!hWndDesktop.Equals(IntPtr.Zero))
91+
if (hWndDesktop.Value != (IntPtr.Zero))
9192
{
9293
return false;
9394
}
9495
}
9596

9697
Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
97-
return (appBounds.bottom - appBounds.top) == screenBounds.Height && (appBounds.right - appBounds.left) == screenBounds.Width;
98+
return (appBounds.bottom - appBounds.top) == screenBounds.Height &&
99+
(appBounds.right - appBounds.left) == screenBounds.Width;
98100
}
99101

100102
/// <summary>
@@ -104,7 +106,23 @@ public unsafe static bool IsWindowFullscreen()
104106
public static void DisableControlBox(Window win)
105107
{
106108
var hwnd = new HWND(new WindowInteropHelper(win).Handle);
107-
PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE) & ~(int)WINDOW_STYLE.WS_SYSMENU);
109+
110+
var style = PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
111+
112+
if (style == 0)
113+
{
114+
throw new Win32Exception(Marshal.GetLastPInvokeError());
115+
}
116+
117+
style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
118+
119+
var previousStyle = PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE,
120+
style);
121+
122+
if (previousStyle == 0)
123+
{
124+
throw new Win32Exception(Marshal.GetLastPInvokeError());
125+
}
108126
}
109127

110128
/// <summary>
@@ -127,6 +145,7 @@ public static Point TransformPixelsToDIP(Visual visual, double unitX, double uni
127145
using var src = new HwndSource(new HwndSourceParameters());
128146
matrix = src.CompositionTarget.TransformFromDevice;
129147
}
148+
130149
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
131150
}
132151
}

Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,15 @@ public unsafe string TryGetProcessFilename(Process p)
9898

9999
using var safeHandle = new SafeProcessHandle(handle.Value, true);
100100
uint capacity = 2000;
101-
char[] buffer = new char[capacity];
101+
Span<char> buffer = new char[capacity];
102102
fixed (char* pBuffer = buffer)
103103
{
104104
if (!PInvoke.QueryFullProcessImageName(safeHandle, PROCESS_NAME_FORMAT.PROCESS_NAME_WIN32, (PWSTR)pBuffer, ref capacity))
105105
{
106106
return string.Empty;
107107
}
108108

109-
// Truncate the buffer to the actual length of the string
110-
int validLength = Array.IndexOf(buffer, '\0');
111-
if (validLength < 0) validLength = (int)capacity;
112-
return new string(buffer, 0, validLength);
109+
return buffer[..(int)capacity].ToString();
113110
}
114111
}
115112
catch

Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,25 @@ public unsafe string retrieveTargetPath(string path)
3131
((IShellLinkW)link).Resolve(hwnd, 0);
3232

3333
const int MAX_PATH = 260;
34-
char[] buffer = new char[MAX_PATH];
34+
Span<char> buffer = stackalloc char[MAX_PATH];
3535

3636
var data = new WIN32_FIND_DATAW();
3737
var target = string.Empty;
38-
fixed (char* bufferChar = buffer)
38+
fixed (char* bufferPtr = buffer)
3939
{
40-
((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH);
41-
target = GetStringFromBuffer(buffer, MAX_PATH);
40+
((IShellLinkW)link).GetPath((PWSTR)bufferPtr, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH);
41+
target = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
4242
}
4343

4444
// To set the app description
4545
if (!string.IsNullOrEmpty(target))
4646
{
4747
try
4848
{
49-
char[] buffer1 = new char[MAX_PATH];
50-
fixed (char* buffer1Char = buffer1)
49+
fixed (char* bufferPtr = buffer)
5150
{
52-
((IShellLinkW)link).GetDescription((PWSTR)buffer1Char, MAX_PATH);
53-
description = GetStringFromBuffer(buffer1, MAX_PATH);
51+
((IShellLinkW)link).GetDescription(bufferPtr, MAX_PATH);
52+
description = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
5453
}
5554
}
5655
catch (COMException e)
@@ -61,11 +60,10 @@ public unsafe string retrieveTargetPath(string path)
6160
e);
6261
}
6362

64-
char[] buffer2 = new char[MAX_PATH];
65-
fixed (char* buffer2Char = buffer2)
63+
fixed (char* bufferPtr = buffer)
6664
{
67-
((IShellLinkW)link).GetArguments((PWSTR)buffer2Char, MAX_PATH);
68-
arguments = GetStringFromBuffer(buffer2, MAX_PATH);
65+
((IShellLinkW)link).GetArguments(bufferPtr, MAX_PATH);
66+
arguments = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
6967
}
7068
}
7169

@@ -74,13 +72,5 @@ public unsafe string retrieveTargetPath(string path)
7472

7573
return target;
7674
}
77-
78-
private static unsafe string GetStringFromBuffer(char[] buffer, int maxLength)
79-
{
80-
// Truncate the buffer to the actual length of the string
81-
int validLength = Array.IndexOf(buffer, '\0');
82-
if (validLength < 0) validLength = maxLength;
83-
return new string(buffer, 0, validLength);
84-
}
8575
}
8676
}

Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Runtime.InteropServices;
34
using Windows.Win32;
45
using Windows.Win32.Foundation;
56
using Windows.Win32.System.LibraryLoader;
@@ -20,39 +21,34 @@ public static class ShellLocalization
2021
/// <returns>The localized name as string or <see cref="string.Empty"/>.</returns>
2122
public static unsafe string GetLocalizedName(string path)
2223
{
23-
int capacity = 1024;
24-
char[] resourcePathBuffer = new char[capacity];
24+
const int capacity = 1024;
25+
Span<char> buffer = new char[capacity];
2526

2627
// If there is no resource to localize a file name the method returns a non zero value.
27-
fixed (char* resourcePath = resourcePathBuffer)
28+
fixed (char* bufferPtr = buffer)
2829
{
29-
var result = PInvoke.SHGetLocalizedName(path, (PWSTR)resourcePath, (uint)capacity, out var id);
30-
if (result == HRESULT.S_OK)
30+
var result = PInvoke.SHGetLocalizedName(path, bufferPtr, capacity, out var id);
31+
if (result != HRESULT.S_OK)
3132
{
32-
int validLength = Array.IndexOf(resourcePathBuffer, '\0');
33-
if (validLength < 0) validLength = capacity;
34-
var resourcePathStr = new string(resourcePathBuffer, 0, validLength);
35-
_ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, resourcePath, (uint)capacity);
36-
var handle = PInvoke.LoadLibraryEx(resourcePathStr,
37-
LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE);
38-
IntPtr safeHandle = handle.DangerousGetHandle();
39-
if (safeHandle != IntPtr.Zero)
40-
{
41-
char[] localizedNameBuffer = new char[capacity];
42-
fixed (char* localizedName = localizedNameBuffer)
43-
{
44-
if (PInvoke.LoadString(handle, (uint)id, (PWSTR)localizedName, capacity) != 0)
45-
{
46-
validLength = Array.IndexOf(localizedNameBuffer, '\0');
47-
if (validLength < 0) validLength = capacity;
48-
var lString = new string(localizedNameBuffer, 0, validLength);
49-
PInvoke.FreeLibrary(new(safeHandle));
50-
return lString;
51-
}
52-
}
33+
return string.Empty;
34+
}
35+
36+
var resourcePathStr = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
37+
_ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, bufferPtr, capacity);
38+
using var handle = PInvoke.LoadLibraryEx(resourcePathStr,
39+
LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE);
40+
if (handle.IsInvalid)
41+
{
42+
return string.Empty;
43+
}
44+
45+
// not sure about the behavior of Pinvoke.LoadString, so we clear the buffer before using it (so it must be a null-terminated string)
46+
buffer.Clear();
5347

54-
PInvoke.FreeLibrary(new(safeHandle));
55-
}
48+
if (PInvoke.LoadString(handle, (uint)id, bufferPtr, capacity) != 0)
49+
{
50+
var lString = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
51+
return lString;
5652
}
5753
}
5854

0 commit comments

Comments
 (0)