Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace DllImport and flags with CSWin32 & Remove useless DllImport and flags & Fix right Win key click issue #3122

Merged
merged 22 commits into from
Dec 28, 2024

Conversation

Jack251970
Copy link
Contributor

@Jack251970 Jack251970 commented Dec 11, 2024

PR

  • Replace DllImport & flags with CSWin32 to improve code quality and fix possible issue like getting localized string of certain application like Windows Performance Recorder.
  • Remove useless DllImport & flags in SingleInstance.cs.
  • Fix right Win key click issue (Fix VIRTUAL_KEY.VK_RWIN check issue).
  • Fix clipboard action under STA thread issue (see more in https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-oleinitialize).

Test already done

* Sleep & Empty Recycle Bin action in `Flow.Launcher.Plugin.Sys` plugin.
* All changes in `Flow.Launcher.Plugin.ProcessKiller` plugin.
* All changes in `Flow.Launcher.Plugin.Program` plugin.
* All changes in `ThumbnailReader.cs` in `Flow.Launcher.Plugin.Infrasture`.
* `API.CopyToClipboard` & `new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", () => Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result)`.

@prlabeler prlabeler bot added the bug Something isn't working label Dec 11, 2024
Copy link

gitstream-cm bot commented Dec 11, 2024

🥷 Code experts: no user matched threshold 10

Yusyuriv has most 🧠 knowledge in the files.

See details

Flow.Launcher.Infrastructure/FileExplorerHelper.cs

Knowledge based on git-blame:

Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj

Knowledge based on git-blame:

Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs

Knowledge based on git-blame:

Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs

Knowledge based on git-blame:

Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs

Knowledge based on git-blame:

Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj

Knowledge based on git-blame:

Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs

Knowledge based on git-blame:

Flow.Launcher/Flow.Launcher.csproj

Knowledge based on git-blame:

Flow.Launcher/Helper/DWMDropShadow.cs

Knowledge based on git-blame:
Yusyuriv: 67%

Flow.Launcher/Helper/SingleInstance.cs

Knowledge based on git-blame:

Flow.Launcher/Helper/WallpaperPathRetrieval.cs

Knowledge based on git-blame:
Yusyuriv: 62%

Flow.Launcher/Helper/WindowsInteropHelper.cs

Knowledge based on git-blame:
Yusyuriv: 72%

Flow.Launcher/MainWindow.xaml.cs

Knowledge based on git-blame:
Yusyuriv: 1%

Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj

Knowledge based on git-blame:
Yusyuriv: 3%

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

Knowledge based on git-blame:

Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj

Knowledge based on git-blame:
Yusyuriv: 2%

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

Knowledge based on git-blame:

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

Knowledge based on git-blame:

Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj

Knowledge based on git-blame:
Yusyuriv: 10%

Plugins/Flow.Launcher.Plugin.Sys/Main.cs

Knowledge based on git-blame:

To learn more about /:\ gitStream - Visit our Docs

This comment has been minimized.

Copy link

gitstream-cm bot commented Dec 11, 2024

Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX.

Copy link
Contributor

coderabbitai bot commented Dec 11, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces significant changes across multiple files in the Flow.Launcher project, primarily focusing on transitioning from traditional DllImport declarations to a more structured approach using a new PInvoke class. This includes updates to how Windows API functions are accessed, enhancing type safety and resource management. Key modifications involve the removal and replacement of various methods and constants related to window management, keyboard hooks, and system operations, while also adding new package references and files to support these changes.

Changes

File Change Summary
Flow.Launcher.Infrastructure/FileExplorerHelper.cs Replaced System.Runtime.InteropServices with Windows.Win32, removed EnumWindows method, updated GetZOrder method to use PInvoke.EnumWindows.
Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj Added NativeMethods.txt and PackageReference for Microsoft.Windows.CsWin32 version 0.3.106.
Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs Changed hookId type to UnhookWindowsHookExSafeHandle, introduced SetHook method, updated CheckModifiers and hook callback method for improved type safety.
Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs Deleted file containing low-level keyboard input handling methods.
Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs Updated key event values to reference PInvoke constants instead of hardcoded integers.
Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs Replaced P/Invoke declarations with Windows.Win32, updated GetThumbnail method for error handling and type changes.
Flow.Launcher.Infrastructure/NativeMethods.txt Introduced native method declarations and constants for Windows API functionalities.
Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj Added NativeMethods.txt and PackageReference for Microsoft.Windows.CsWin32 version 0.3.106.
Flow.Launcher.Plugin/NativeMethods.txt Added new entries for EnumThreadWindows, GetWindowText, and GetWindowTextLength.
Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs Removed DllImport attributes for window functions, updated method signatures for type safety.
Flow.Launcher/Flow.Launcher.csproj Added PackageReference for Microsoft.Windows.CsWin32 version 0.3.106.
Flow.Launcher/Helper/DWMDropShadow.cs Removed DllImport declarations for DWM API calls, updated method signatures for pointer usage.
Flow.Launcher/Helper/SingleInstance.cs Removed WM enum and NativeMethods class, simplifying message handling logic.
Flow.Launcher/Helper/WallpaperPathRetrieval.cs Updated GetWallpaperPath method to use PInvoke.SystemParametersInfo with pointer operations.
Flow.Launcher/Helper/WindowsInteropHelper.cs Replaced IntPtr with HWND for window handles, updated method calls to use PInvoke.
Flow.Launcher/MainWindow.xaml.cs Replaced DllImport for SetForegroundWindow with PInvoke.SetForegroundWindow.
Flow.Launcher/NativeMethods.txt Added entries for various window management and system parameter functions.
Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj Added PackageReference for Microsoft.Windows.CsWin32 version 0.3.106.
Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt Added QueryFullProcessImageName and OpenProcess method declarations.
Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs Updated TryGetProcessFilename to use PInvoke methods, removed ProcessAccessFlags enum.
Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj Added NativeMethods.txt and PackageReference for Microsoft.Windows.CsWin32 version 0.3.106.
Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt Added entries for various Windows API functions and constants.
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs Removed several enumerations and structures, updated retrieveTargetPath for unsafe code usage.
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs Updated GetLocalizedName to use unsafe code and PInvoke methods for string retrieval.
Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj Added PackageReference for Microsoft.Windows.CsWin32 version 0.3.106.
Plugins/Flow.Launcher.Plugin.Sys/Main.cs Removed DllImport declarations, updated to use PInvoke for system operations.
Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt Added entries for various system operation methods and constants.
Flow.Launcher.Infrastructure/UserSettings/Settings.cs Updated clipboard functionality to use asynchronous behavior with Win32Helper.StartSTATaskAsync.
Flow.Launcher.Infrastructure/Win32Helper.cs Introduced a new static class with asynchronous methods for STA thread operations.
Flow.Launcher/PublicAPIInstance.cs Updated CopyToClipboard method to support asynchronous operations.
Flow.Launcher.Core/Resource/Theme.cs Removed direct blur handling methods, replaced with calls to Win32Helper for managing blur effects.

Possibly related PRs

Suggested labels

enhancement, 1 min review

Suggested reviewers

  • jjw24

🐰 In the land of code, we hop with glee,
New methods and structures, so fancy and free.
With PInvoke in hand, we dance through the night,
Windows API calls now feel just right!
So let’s celebrate changes, both big and small,
For in this code garden, we’re having a ball! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Outside diff range and nitpick comments (14)
Flow.Launcher/Flow.Launcher.csproj (1)

93-96: Document the package's purpose in a comment.

Consider adding a comment explaining that this package is used for generating P/Invoke code, similar to the existing comment for ModernWpfUI below.

+    <!-- Microsoft.Windows.CsWin32 provides source generators for Windows API P/Invoke code -->
     <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
Flow.Launcher.Plugin/NativeMethods.txt (1)

1-3: Consider adding complementary Windows API functions.

For robust window enumeration and text handling, consider adding these complementary functions:

  • IsWindow: Verifies if a window handle is valid
  • IsWindowVisible: Checks window visibility
  • GetClassName: Gets window class name for filtering
Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt (1)

4-5: Consider adding more error handling constants.

While S_OK and E_UNEXPECTED are good baseline constants, consider adding other relevant HRESULT constants for more specific error handling:

  • ERROR_ACCESS_DENIED
  • ERROR_CANCELLED
  • ERROR_INSUFFICIENT_BUFFER
Plugins/Flow.Launcher.Plugin.Sys/Main.cs (1)

249-249: Use HWND.Null instead of new() when passing a null window handle

For clarity and best practices, consider using HWND.Null when passing a null window handle to SHEmptyRecycleBin.

Apply this diff to improve code clarity:

-var result = PInvoke.SHEmptyRecycleBin(new(), string.Empty, 0);
+var result = PInvoke.SHEmptyRecycleBin(HWND.Null, string.Empty, 0);
Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs (4)

30-30: Consider removing or refining the external URL in the comment

The comment includes a direct link to an external website (StackOverflow). While it's acceptable to reference sources, embedding URLs in the code may not be ideal as they might become inaccessible over time.

Consider summarizing the relevant information from the source directly in the comment or moving the reference to the documentation or a README file.


32-32: Simplify SHCreateItemFromParsingName call by specifying the interface directly

You can streamline the code by specifying the interface type directly in the SHCreateItemFromParsingName call, eliminating the need for GUID_IShellItem.

Apply the following changes:

  1. Remove the declaration of GUID_IShellItem:
-private static readonly Guid GUID_IShellItem = typeof(IShellItem).GUID;
  1. Modify the SHCreateItemFromParsingName call:
-var retCode = PInvoke.SHCreateItemFromParsingName(
+IShellItem nativeShellItem = PInvoke.SHCreateItemFromParsingName<IShellItem>(
    fileName,
    null,
-   GUID_IShellItem,
-   out var nativeShellItem);

This leverages the generic overload provided by CsWin32, improving readability and simplifying error handling.

Also applies to: 53-57


59-60: Allow SHCreateItemFromParsingName to handle exceptions

Instead of manually checking the HRESULT and throwing an exception, consider using the version of SHCreateItemFromParsingName that throws an exception on failure. This simplifies the code and ensures consistent error handling.

Modify the code as follows:

-var retCode = PInvoke.SHCreateItemFromParsingName<IShellItem>(
+IShellItem nativeShellItem = PInvoke.SHCreateItemFromParsingName<IShellItem>(
    fileName,
    null,
-   out var nativeShellItem);

-if (retCode != HRESULT.S_OK)
-    throw Marshal.GetExceptionForHR(retCode);

This change assumes that SHCreateItemFromParsingName is configured to throw exceptions on failure in the CsWin32 settings.


Line range hint 14-26: Use SIIGBF directly instead of defining ThumbnailOptions

Since ThumbnailOptions mirrors the SIIGBF enum from the Windows API, you can simplify the code by using SIIGBF directly. This reduces duplication and potential inconsistencies.

Apply the following changes:

  1. Remove the ThumbnailOptions enum:
-/// <summary>
-/// Subclass of <see cref="Windows.Win32.UI.Shell.SIIGBF"/>
-/// </summary>
-[Flags]
-public enum ThumbnailOptions
-{
-    None = 0x00,
-    BiggerSizeOk = 0x01,
-    InMemoryOnly = 0x02,
-    IconOnly = 0x04,
-    ThumbnailOnly = 0x08,
-    InCacheOnly = 0x10,
-}
  1. Update method signatures to use SIIGBF:
-public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
+public static BitmapSource GetThumbnail(string fileName, int width, int height, SIIGBF options)

-private static unsafe HBITMAP GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
+private static unsafe HBITMAP GetHBitmap(string fileName, int width, int height, SIIGBF options)
  1. Update method calls:
-imageFactory.GetImage(size, (SIIGBF)options, &hBitmap);
+imageFactory.GetImage(size, options, &hBitmap);
  1. Update the fallback option in the catch block:
-imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap);
+imageFactory.GetImage(size, SIIGBF.ICONONLY, &hBitmap);

This change uses the existing SIIGBF enum, enhancing code clarity and maintainability.

Also applies to: 79-80, 84-84

Flow.Launcher/Helper/DWMDropShadow.cs (1)

47-52: Enhance code readability and maintainability

  • Use sizeof(int) instead of hardcoding the size: Replace the hardcoded value 4 with sizeof(int) to ensure correctness and portability.

  • Specify types explicitly in new expressions: Instead of using new(helper.Handle), explicitly specify the type to improve readability.

Apply this diff:

 int val = 2;
-int ret1 = PInvoke.DwmSetWindowAttribute(new(helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
+int ret1 = PInvoke.DwmSetWindowAttribute(new HWND(helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, (uint)sizeof(int));

 var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 };
-int ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
+int ret2 = PInvoke.DwmExtendFrameIntoClientArea(new HWND(helper.Handle), &m);
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (1)

Line range hint 25-75: Ensure availability of removed enums and structs

The enums SLGP_FLAGS and struct WIN32_FIND_DATAW have been removed from the class but are still referenced in the retrieveTargetPath method. Ensure that these types are imported from the appropriate namespaces in Windows.Win32, such as Windows.Win32.UI.Shell and Windows.Win32.Storage.FileSystem, or redefine them if necessary to prevent compilation errors.

Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs (1)

40-56: Simplify calls to GetKeyState by removing unnecessary casts

The PInvoke.GetKeyState method accepts VIRTUAL_KEY directly without the need to cast to int. Removing the casts improves code readability.

Apply this diff:

 if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_SHIFT) & 0x8000) != 0)
+if ((PInvoke.GetKeyState(VIRTUAL_KEY.VK_SHIFT) & 0x8000) != 0)
 {
     // SHIFT is pressed
     state.ShiftPressed = true;
 }
 
 if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_CONTROL) & 0x8000) != 0)
+if ((PInvoke.GetKeyState(VIRTUAL_KEY.VK_CONTROL) & 0x8000) != 0)
 {
     // CONTROL is pressed
     state.CtrlPressed = true;
 }
 
 if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_MENU) & 0x8000) != 0)
+if ((PInvoke.GetKeyState(VIRTUAL_KEY.VK_MENU) & 0x8000) != 0)
 {
     // ALT is pressed
     state.AltPressed = true;
 }
 
 if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0 ||
     (PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RWIN) & 0x8000) != 0)
+if ((PInvoke.GetKeyState(VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0 ||
+    (PInvoke.GetKeyState(VIRTUAL_KEY.VK_RWIN) & 0x8000) != 0)
 {
     // WIN is pressed
     state.WinPressed = true;
 }
Flow.Launcher/Helper/WindowsInteropHelper.cs (1)

Line range hint 42-67: Refactor 'IsWindowFullscreen' to eliminate 'unsafe' code

The IsWindowFullscreen method can be refactored to remove the unsafe context by utilizing managed types like StringBuilder. This enhances code safety and maintainability.

Apply this diff to refactor the code:

-        public unsafe static bool IsWindowFullscreen()
+        public static bool IsWindowFullscreen()
         {
             // get current active window
             var hWnd = PInvoke.GetForegroundWindow();
             if (hWnd.Equals(HWND.Null))
             {
                 return false;
             }
             // if current active window is desktop or shell, exit early
             if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
             {
                 return false;
             }
-            string windowClass;
-            int capacity = 256;
-            char[] buffer = new char[capacity];
-            fixed (char* pBuffer = buffer)
-            {
-                PInvoke.GetClassName(hWnd, pBuffer, capacity);
-                int validLength = Array.IndexOf(buffer, '\0');
-                if (validLength < 0) validLength = capacity;
-                windowClass = new string(buffer, 0, validLength);
-            }
+            int capacity = 256;
+            var sb = new StringBuilder(capacity);
+            PInvoke.GetClassName(hWnd, sb, capacity);
+            var windowClass = sb.ToString();
             // for Win+Tab (Flip3D)
             if (windowClass == WINDOW_CLASS_WINTAB)
             {
                 return false;
             }
             PInvoke.GetWindowRect(hWnd, out var appBounds);
             // for console (ConsoleWindowClass), we have to check for negative dimensions
             if (windowClass == WINDOW_CLASS_CONSOLE)
             {
                 return appBounds.top < 0 && appBounds.bottom < 0;
             }
             // for desktop (Progman or WorkerW, depends on the system), we have to check
             if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
             {
                 var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
                 hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
                 if (!hWndDesktop.Equals(IntPtr.Zero))
                 {
                     return false;
                 }
             }
             Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
             return (appBounds.bottom - appBounds.top) == screenBounds.Height && (appBounds.right - appBounds.left) == screenBounds.Width;
         }
Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt (1)

6-10: Consider adding additional shell link constants

For completeness, consider adding these commonly used shell link constants:

  • STGM_READ
  • SLGP_SHORTPATH
  • SLGP_UNCPRIORITY
Flow.Launcher/MainWindow.xaml.cs (1)

692-692: Consider error handling for GetForegroundWindow.

While the code correctly accesses the handle value, consider adding error handling as GetForegroundWindow can return null in certain scenarios (e.g., no foreground window).

-    var foregroundWindowHandle = PInvoke.GetForegroundWindow().Value;
+    var foregroundWindow = PInvoke.GetForegroundWindow();
+    var foregroundWindowHandle = foregroundWindow.Value;
+    if (foregroundWindowHandle == IntPtr.Zero)
+    {
+        // Fallback to primary screen
+        return Screen.PrimaryScreen;
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1f81ea0 and 49fc0b8.

📒 Files selected for processing (27)
  • Flow.Launcher.Infrastructure/FileExplorerHelper.cs (2 hunks)
  • Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj (2 hunks)
  • Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs (3 hunks)
  • Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs (0 hunks)
  • Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs (1 hunks)
  • Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs (3 hunks)
  • Flow.Launcher.Infrastructure/NativeMethods.txt (1 hunks)
  • Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj (2 hunks)
  • Flow.Launcher.Plugin/NativeMethods.txt (1 hunks)
  • Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (2 hunks)
  • Flow.Launcher/Flow.Launcher.csproj (1 hunks)
  • Flow.Launcher/Helper/DWMDropShadow.cs (2 hunks)
  • Flow.Launcher/Helper/SingleInstance.cs (0 hunks)
  • Flow.Launcher/Helper/WallpaperPathRetrieval.cs (1 hunks)
  • Flow.Launcher/Helper/WindowsInteropHelper.cs (3 hunks)
  • Flow.Launcher/MainWindow.xaml.cs (3 hunks)
  • Flow.Launcher/NativeMethods.txt (1 hunks)
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj (1 hunks)
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt (1 hunks)
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (2 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj (2 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt (1 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (3 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs (2 hunks)
  • Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj (1 hunks)
  • Plugins/Flow.Launcher.Plugin.Sys/Main.cs (5 hunks)
  • Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt (1 hunks)
💤 Files with no reviewable changes (2)
  • Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs
  • Flow.Launcher/Helper/SingleInstance.cs
✅ Files skipped from review due to trivial changes (1)
  • Flow.Launcher.Infrastructure/NativeMethods.txt
🔇 Additional comments (24)
Flow.Launcher/Flow.Launcher.csproj (1)

93-96: Verify the CSWin32 package version selection.

The addition of Microsoft.Windows.CsWin32 aligns well with the PR objective of replacing DllImport. However, let's verify the version choice.

✅ Verification successful

Version 0.3.106 is appropriate for this project

The selected version 0.3.106 is actually the latest stable release of Microsoft.Windows.CsWin32 (published on 2024-05-10), making it a suitable choice. This version represents a progression from the beta releases and is more stable than the previously mentioned 0.3.49-beta. The version choice aligns well with production use in the Flow.Launcher project.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check NuGet for latest stable and preview versions
curl -s https://api.nuget.org/v3/registration5-semver1/microsoft.windows.cswin32/index.json | jq -r '.items[0].items[].catalogEntry | select(.version) | {version: .version, published: .published}'

# Check for any known issues or breaking changes
gh search issues --repo microsoft/CsWin32 --state all --json title,url,state --query 'breaking changes in:title'

Length of output: 5319

Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj (1)

62-62: Verify CSWin32 package version compatibility

Let's verify the compatibility and latest stable version of the Microsoft.Windows.CsWin32 package.

✅ Verification successful

CSWin32 package version is consistent and up-to-date

The Microsoft.Windows.CsWin32 package version 0.3.106 is:

  • Currently the latest stable version available on NuGet
  • Used consistently across all 6 project files in the codebase
  • Properly configured with PrivateAssets in all locations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check latest version and release notes
curl -s https://api.nuget.org/v3/registration5-semver1/microsoft.windows.cswin32/index.json | jq -r '.items[0].items[-1].catalogEntry | {version, description}'

# Check if this version is used in other parts of the codebase
rg -l "Microsoft.Windows.CsWin32"

Length of output: 663


Script:

#!/bin/bash
# Check the version of Microsoft.Windows.CsWin32 used in other project files
for file in $(rg -l "Microsoft.Windows.CsWin32"); do
    echo "=== $file ==="
    rg -A 1 "Microsoft.Windows.CsWin32" "$file"
done

Length of output: 2530

Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj (2)

56-58: LGTM! Good practice adding NativeMethods.txt as an additional file.

The explicit declaration of Win32 APIs in a separate file improves maintainability and makes the API surface clear.


68-71: Verify the CSWin32 package version.

The package configuration is correct with appropriate asset settings. However, let's verify if version 0.3.106 is the most suitable version.

✅ Verification successful

CSWin32 package version is appropriate and consistently used

The version 0.3.106 of Microsoft.Windows.CsWin32 is consistently used across all projects in the solution that reference it, including:

  • Flow.Launcher
  • Flow.Launcher.Infrastructure
  • Flow.Launcher.Plugin
  • Flow.Launcher.Plugin.ProcessKiller
  • Flow.Launcher.Plugin.Program
  • Flow.Launcher.Plugin.Sys

While there are newer beta versions available (up to 0.3.x-beta), using the stable 0.3.106 version is a safer choice for production code.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check latest versions and compatibility of Microsoft.Windows.CsWin32

# Check NuGet for latest versions
curl -s https://api.nuget.org/v3/registration5-semver1/microsoft.windows.cswin32/index.json | jq -r '.items[0].items[].catalogEntry.version'

# Check if this version is used consistently across the solution
fd -e csproj -x grep -l "Microsoft.Windows.CsWin32"

Length of output: 940


Script:

#!/bin/bash
# Check the specific version used in each project file
echo "=== Checking CsWin32 versions across projects ==="
for proj in $(fd -e csproj); do
    echo "=== $proj ==="
    grep -A 2 "Microsoft.Windows.CsWin32" "$proj"
done

Length of output: 6568

Flow.Launcher.Plugin/NativeMethods.txt (2)

1-3: Verify error handling in the codebase.

Since these Windows API functions can fail, ensure proper error handling is implemented.

Let's check the error handling patterns:

✅ Verification successful

Let me gather more context about the implementation to verify the error handling patterns.


Error handling is properly implemented for these Windows API functions

The code shows appropriate error handling:

  • GetWindowText return value is checked for 0 (failure case) and returns an empty string
  • The code includes documentation about possible failure cases in comments
  • Win32Exception is used throughout the codebase for Windows API error handling
  • EnumThreadWindows is used in a callback pattern where errors are handled by the return value
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check error handling for Windows API calls
# Expected results: Marshal.GetLastWin32Error() or similar error checking

# Search for error handling patterns
rg -A 2 "GetWindowText|EnumThreadWindows" 

# Check for Win32 error handling
ast-grep --pattern 'Marshal.GetLastWin32Error()'

Length of output: 1141


Script:

#!/bin/bash
# Let's check the full implementation context
rg -B 5 -A 10 "GetWindowText.*|EnumThreadWindows.*" --type cs

# Also check for any other error handling patterns
rg "Marshal\.GetLastWin32Error|Win32Exception|WindowsError" --type cs

Length of output: 4113


1-3: LGTM! The selected Windows API functions are appropriate for window enumeration and text retrieval.

These functions form a logical set for retrieving window titles during thread window enumeration.

Let's verify the implementation patterns in the codebase:

✅ Verification successful

The Windows API functions are correctly implemented with proper usage patterns

The implementation in ShellCommand.cs demonstrates correct usage of all three Windows API functions:

  • EnumThreadWindows is properly used with a callback function (CheckSecurityThread)
  • GetWindowTextLength is called first to determine the required buffer size
  • GetWindowText is used with proper buffer allocation based on the length
  • Safe memory handling is implemented using fixed pointers and null termination checks
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check implementation patterns of window enumeration and text retrieval
# Expected results: 
# 1. EnumThreadWindows should be used with a callback
# 2. GetWindowText should be preceded by GetWindowTextLength
# 3. Proper buffer allocation should be used

# Check for window enumeration patterns
ast-grep --pattern 'EnumThreadWindows($_)'

# Check for proper text retrieval patterns
ast-grep --pattern $'GetWindowTextLength($_);
$$$
GetWindowText($_)'

Length of output: 114


Script:

#!/bin/bash
# Let's try a different approach to find these Windows API usages
# First, let's search for any existing files that might be using these APIs

# Search for files containing these Windows API functions
echo "=== Files containing Windows API functions ==="
rg -l "EnumThreadWindows|GetWindowText|GetWindowTextLength"

# Look for any existing P/Invoke declarations or usage patterns
echo -e "\n=== Existing DllImport or usage patterns ==="
rg -A 5 "EnumThreadWindows|GetWindowText|GetWindowTextLength"

# Check for any test files or documentation mentioning these functions
echo -e "\n=== Tests or documentation ==="
fd -e cs -e md -e txt | xargs rg "EnumThreadWindows|GetWindowText|GetWindowTextLength"

Length of output: 3085

Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj (3)

38-40: Verify the content and location of NativeMethods.txt

The addition of NativeMethods.txt as an AdditionalFiles is crucial for CSWin32 source generation. This file should contain the list of Win32 APIs that need to be generated.

✅ Verification successful

NativeMethods.txt content is properly configured for CSWin32 migration

The NativeMethods.txt file exists and contains the necessary Win32 API declarations for the project's requirements:

  • Shell-related APIs: SHCreateItemFromParsingName, IShellItem, IShellItemImageFactory
  • Window hook APIs: SetWindowsHookEx, UnhookWindowsHookEx, CallNextHookEx
  • Window message constants: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP
  • Other required Win32 functions: GetModuleHandle, GetKeyState, EnumWindows

The remaining DllImport usages found are in plugin projects which are separate from the Infrastructure project and not affected by this change.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify NativeMethods.txt exists and contains necessary Win32 API declarations

# Check if the file exists and show its content
if [ -f "Flow.Launcher.Infrastructure/NativeMethods.txt" ]; then
    echo "File exists. Content:"
    cat "Flow.Launcher.Infrastructure/NativeMethods.txt"
else
    echo "Warning: NativeMethods.txt not found in expected location"
    # Search for the file in case it's in a different location
    fd -t f "NativeMethods.txt"
fi

# Search for DllImport usage that might need to be included in NativeMethods.txt
rg "DllImport" -t cs

Length of output: 12792


Line range hint 1-76: Verify target framework compatibility with CSWin32

The project targets net7.0-windows which should be compatible with CSWin32, but let's verify other framework-related settings.

✅ Verification successful

Target framework is compatible with CSWin32

All projects in the solution are targeting .NET 7.0 Windows, with some specifically targeting Windows 10.0.19041.0. This is fully compatible with Microsoft.Windows.CSWin32 0.3.106, which supports .NET Standard 2.0 and newer platforms including .NET 7.0.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for framework compatibility issues in other project files

# Search for target framework declarations in other project files
fd -e csproj | xargs grep -l "TargetFramework"

# Check for any framework-specific conditional compilation
rg "net7.0|netstandard" -t cs

Length of output: 1259


Script:

#!/bin/bash
# Let's check the target framework versions in all csproj files
fd -e csproj -x cat {} | grep -A 1 "<TargetFramework"

# Also check for any CSWin32 package references across all csproj files
fd -e csproj -x cat {} | grep -A 3 "CSWin32"

Length of output: 2048


63-66: Verify CSWin32 package version compatibility and security

The addition of Microsoft.Windows.CsWin32 package is aligned with the PR objective to replace DllImport with CSWin32. However, we should verify the version choice.

✅ Verification successful

Consider upgrading Microsoft.Windows.CsWin32 package to latest stable version

The current version 0.3.106 is the latest stable release available on NuGet. While there are some open issues reported for this version, they are specific to certain API functionalities (AttachConsole, EnumProcessModulesEx, MFEnumDeviceSources) and don't indicate critical security concerns.

Let's verify if the project is using any of these affected APIs:


Version 0.3.106 of Microsoft.Windows.CsWin32 is appropriate for this project

The codebase scan shows that none of the problematic APIs mentioned in the open issues are being used. The project primarily uses common Win32 APIs like window management (GetForegroundWindow, SetWindowLong), hook functions (SetWindowsHookEx), and shell interactions (SHEmptyRecycleBin), which are well-tested and stable in the current version.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for latest stable versions and known issues with Microsoft.Windows.CsWin32

# Check NuGet for latest versions
curl -s https://api.nuget.org/v3-flatcontainer/microsoft.windows.cswin32/index.json | jq -r '.versions[]' | sort -V | tail -n 5

# Check for any GitHub issues related to the specific version
gh api graphql -f query='
{
  search(query: "repo:microsoft/CsWin32 is:issue 0.3.106", type: ISSUE, first: 5) {
    nodes {
      ... on Issue {
        title
        state
        url
      }
    }
  }
}'

Length of output: 1178


Script:

#!/bin/bash
# Search for usage of potentially affected APIs
rg -i "AttachConsole|EnumProcessModulesEx|MFEnumDeviceSources|MFTEnumEx|CollectMetadataPaths" --type cs

# Check all Win32 API usages in the codebase
ast-grep --pattern 'PInvoke.$_($$$)'

Length of output: 7157

Plugins/Flow.Launcher.Plugin.Sys/NativeMethods.txt (2)

1-6: LGTM! Clear list of Windows API methods for CSWin32 generation.

The file correctly lists the required Windows API methods and constants needed for system operations. This aligns well with the PR objective of transitioning from DllImport to CSWin32.


1-3: Verify security implications of system-level operations.

These Windows APIs (ExitWindowsEx, LockWorkStation, SHEmptyRecycleBin, SetSuspendState) can perform powerful system-level operations. Ensure proper security checks and user confirmations are implemented in the calling code.

Also applies to: 6-6

✅ Verification successful

Let me gather more context about user confirmations and error handling.


Let me check the implementation of system operations to verify security measures.


Security measures are properly implemented for system operations

The code review shows that appropriate security measures are in place:

  • All destructive operations (shutdown, restart, log off) require explicit user confirmation through warning message boxes
  • Error handling is implemented for operations like emptying the recycle bin
  • Sleep/Lock operations are direct OS calls that are inherently safe and don't require additional confirmation
  • Operations use proper Windows API calls through PInvoke rather than unsafe alternatives
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for security checks and user confirmations in the implementation

# Look for security checks and user confirmations
rg -A 5 "ExitWindowsEx|LockWorkStation|SHEmptyRecycleBin|SetSuspendState" --type cs

# Check for UAC/elevation related code
ast-grep --pattern 'new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)'

Length of output: 2740


Script:

#!/bin/bash
# Check for user confirmations and error handling patterns
rg -B 5 -A 10 "Title = \"(Logoff|Lock|Empty Recycle Bin|Hibernate|Sleep)\"" --type cs

# Check if there's any confirmation dialog implementation
rg -A 5 "ShowMsgBox|MessageBox|Confirm" --type cs

# Look for the complete Result class implementation to understand the action execution flow
ast-grep --pattern 'class Result {
  $$$
}'

Length of output: 81181


Script:

#!/bin/bash
# Look for the implementation of system operations and their security checks
rg -B 5 -A 10 "Title = \"(Shutdown|Restart|Restart Advanced|Log Off)\"" --type cs

# Check for any additional security-related code around these operations
rg -A 5 "ExitWindowsEx|LockWorkStation|SHEmptyRecycleBin|SetSuspendState" --type cs --glob "!NativeMethods.txt"

Length of output: 5842

Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj (3)

64-65: LGTM: FodyWeavers.xml inclusion

The inclusion of FodyWeavers.xml in the None ItemGroup is correct and aligns with the existing Fody package reference for property change notifications.


75-78: Consider updating to the latest stable version of CSWin32

The Microsoft.Windows.CsWin32 package version 0.3.106 is being used, but there might be a more recent stable version available. Please verify if this version aligns with other Flow Launcher projects for consistency.

Let's check the version usage across the solution:

✅ Verification successful

Version 0.3.106 of Microsoft.Windows.CsWin32 is consistently used across all projects

The version check reveals that all Flow Launcher projects are using the exact same version (0.3.106) of the Microsoft.Windows.CsWin32 package:

  • Flow.Launcher.Plugin
  • Flow.Launcher.Plugin.Program
  • Flow.Launcher.Plugin.ProcessKiller
  • Flow.Launcher.Plugin.Sys
  • Flow.Launcher.Infrastructure
  • Flow.Launcher

This consistent version usage across the solution indicates proper version alignment.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CSWin32 package references in all project files
echo "Checking CSWin32 versions across all projects:"
rg -A 1 "Microsoft\.Windows\.CsWin32" --glob "*.csproj"

Length of output: 1627


60-61: Verify the contents of NativeMethods.txt

The addition of NativeMethods.txt is crucial for the DllImport to CSWin32 migration. This file should contain the list of Win32 APIs that need to be generated.

Let's verify the contents and existence of this file:

✅ Verification successful

NativeMethods.txt contains the expected Win32 APIs for CSWin32 generation

The file contains the three Win32 APIs required for window enumeration and text retrieval:

  • EnumThreadWindows: For enumerating windows of a thread
  • GetWindowText: For retrieving window text
  • GetWindowTextLength: For getting the length of window text

NativeMethods.txt correctly lists the Win32 APIs used in the codebase

The file contains the three Win32 APIs that are being migrated from DllImport to CSWin32:

  • EnumThreadWindows: Used in ShellCommand.cs for checking security windows
  • GetWindowText and GetWindowTextLength: Used in GetWindowTitle method to retrieve window titles

The migration is properly implemented in ShellCommand.cs using the new CSWin32 approach with Windows.Win32.PInvoke instead of DllImport statements.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if NativeMethods.txt exists and show its contents
if [ -f "Flow.Launcher.Plugin/NativeMethods.txt" ]; then
    echo "Contents of NativeMethods.txt:"
    cat "Flow.Launcher.Plugin/NativeMethods.txt"
else
    echo "Warning: NativeMethods.txt not found"
    # Search for it in case it's in a different location
    fd -t f "NativeMethods.txt"
fi

Length of output: 220


Script:

#!/bin/bash
# Let's verify if these APIs were previously used via DllImport
rg "DllImport.*(?:EnumThreadWindows|GetWindowText|GetWindowTextLength)" -g "*.cs"

Length of output: 83


Script:

#!/bin/bash
# Let's try a different approach to find these Win32 API usages
# First, let's search for any file containing these method names
rg -l "EnumThreadWindows|GetWindowText|GetWindowTextLength"

# Then, let's also check for DllImport usage in the codebase
rg "\[DllImport" -A 1

Length of output: 20079


Script:

#!/bin/bash
# Let's check the specific file that uses these Win32 APIs
cat "Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs"

Length of output: 4272

Plugins/Flow.Launcher.Plugin.Sys/Main.cs (1)

10-12: Appropriate inclusion of Windows.Win32 namespaces

The added using directives correctly include the necessary namespaces for the PInvoke calls.

Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs (1)

68-93: Code implementation is correct and follows best practices

The GetHBitmap method correctly handles resource management with appropriate use of try and finally blocks. The use of unsafe code is necessary due to pointer operations required by the Windows API, and the logic handles exceptions effectively.

Plugins/Flow.Launcher.Plugin.ProcessKiller/NativeMethods.txt (1)

1-2: Verify process access security implications

The combination of QueryFullProcessImageName and OpenProcess is appropriate for process path resolution. However, ensure that:

  1. Process access rights are properly restricted when using OpenProcess
  2. Error handling is implemented for access denied scenarios
✅ Verification successful

Let me verify the security implications further by checking the complete implementation of the process handling code.


Let me check the complete context of the process handling method to ensure proper error handling and resource cleanup.


Let me try a different pattern to get the method implementation.


Let me try one final approach to get the process handling code.


Process access implementation is secure and well-implemented

The implementation in ProcessHelper.cs demonstrates secure process access practices:

  1. Uses PROCESS_QUERY_LIMITED_INFORMATION which is the minimum required access right
  2. Properly handles access denied scenarios by returning empty string
  3. Implements proper resource cleanup using SafeProcessHandle
  4. Has appropriate error handling with try-catch blocks
  5. The combination of QueryFullProcessImageName and OpenProcess in NativeMethods.txt is complete for the intended functionality
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if OpenProcess is used with minimum required access rights
rg -A 5 "OpenProcess" --type cs

Length of output: 644


Script:

#!/bin/bash
# Check the complete implementation of process handling
ast-grep --pattern 'var handle = PInvoke.OpenProcess($$$)'

Length of output: 249


Script:

#!/bin/bash
# Get the complete method implementation
ast-grep --pattern 'GetProcessPath($$$) {
  $$$
}'

Length of output: 52


Script:

#!/bin/bash
# Get the complete method implementation using ripgrep
rg -U "GetProcessPath.*?\{.*?\}" -A 20 --multiline --type cs

Length of output: 62


Script:

#!/bin/bash
# Get the content of ProcessHelper.cs
cat Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs

Length of output: 3882

Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt (1)

1-5: Consider security implications of environment string expansion

The ExpandEnvironmentStrings API can expose sensitive environment variables. Ensure that:

  1. Expanded strings are properly sanitized before use
  2. No sensitive information is leaked through environment variables
Flow.Launcher/NativeMethods.txt (1)

3-14: Consider additional window-related constants and messages

For completeness, consider adding these commonly used window constants:

  • WM_ACTIVATE
  • WM_WINDOWPOSCHANGED
  • WM_SETFOCUS
  • WS_EX_TOOLWINDOW

Also, ensure proper error handling when using SetForegroundWindow as it can fail due to Windows focus assault prevention.

Flow.Launcher.Infrastructure/Hotkey/KeyEvent.cs (1)

1-1: LGTM! Good improvement in code maintainability

The changes effectively replace magic numbers with type-safe PInvoke constants from Windows.Win32, which:

  • Improves code maintainability
  • Reduces the risk of errors from hardcoded values
  • Provides better type safety

Also applies to: 10-10, 15-15, 20-20, 25-25

Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj (1)

53-58: Verify package version compatibility and security

The addition of Microsoft.Windows.CsWin32 aligns with the PR objective. However, let's verify:

  1. If this is the latest stable version
  2. If there are any known security issues
✅ Verification successful

Package version is consistent and up-to-date

The version 0.3.106 of Microsoft.Windows.CsWin32 is:

  • The latest stable release (not beta) according to NuGet feed
  • Consistently used across all projects in the codebase that reference it
  • Has no known security vulnerabilities according to GitHub Security Advisories
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check latest version and security advisories for Microsoft.Windows.CsWin32

# Get latest version from NuGet
curl -s https://api.nuget.org/v3-flatcontainer/Microsoft.Windows.CsWin32/index.json | jq -r '.versions[-1]'

# Check for any security advisories
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NUGET, package: "Microsoft.Windows.CsWin32") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 527


Script:

#!/bin/bash
# Let's try a different approach to check the latest version
# Using a simpler curl command to get the raw index
curl -s "https://api.nuget.org/v3-flatcontainer/microsoft.windows.cswin32/index.json"

# Also, let's check if this version is used in other parts of the codebase
rg -l "Microsoft\.Windows\.CsWin32" --type csproj

Length of output: 850


Script:

#!/bin/bash
# Let's try searching with a different approach for csproj files
fd -e csproj -x grep -l "Microsoft.Windows.CsWin32" {}

Length of output: 440


Script:

#!/bin/bash
# Let's check the version used in other project files
for file in $(fd -e csproj); do
    echo "=== $file ==="
    grep -A 3 "Microsoft.Windows.CsWin32" "$file" || true
done

Length of output: 6680

Flow.Launcher.Infrastructure/FileExplorerHelper.cs (1)

5-5: LGTM! Good transition to CSWin32

The changes successfully:

  • Replace DllImport with PInvoke.EnumWindows
  • Update HWND handling to use the safer Value property
  • Maintain existing functionality while improving type safety

Let's verify the HWND handling consistency across the codebase:

Also applies to: 69-71

✅ Verification successful

Let me gather more information to verify the HWND handling across the codebase.


Based on the search results, I can now generate the final response since I have enough information to verify the HWND handling across the codebase.

HWND handling is consistent with CSWin32 usage

The codebase shows consistent HWND handling patterns:

  • All HWND comparisons use Equals() or != with HWND.Null
  • No instances of ToInt32() found on HWND objects
  • Proper usage of Value property when needed (e.g., in FileExplorerHelper.cs)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any remaining ToInt32() calls on HWND objects
# and verify consistent Value property usage

# Search for potential HWND conversions
rg "ToInt32\(\)" -A 2 -B 2

# Search for HWND usage patterns
ast-grep --pattern 'HWND.$$$'

Length of output: 742


Script:

#!/bin/bash
# Search for all HWND related code patterns
rg "HWND" -A 3 -B 3

# Search specifically for Value property access on HWND
rg "\.Value" -A 2 -B 2

Length of output: 86128

Flow.Launcher/MainWindow.xaml.cs (2)

29-29: LGTM! Using CSWin32 for improved type safety.

The change from System.Runtime.InteropServices to Windows.Win32 aligns with modern best practices for Windows API interop.


424-424: Verify handle lifetime management.

The handle wrapping looks correct, but ensure the underlying handle is properly managed.

✅ Verification successful

Let me gather more information about the handle management patterns in the codebase.


Handle management appears to be properly implemented

The handle management is correctly implemented through the following patterns:

  • HwndSource is obtained via PresentationSource.FromVisual() which is managed by WPF's lifecycle
  • Proper disposal pattern is used with using statement where HwndSource is manually created
  • The hwndSource.Handle usage in SetForegroundWindow is safe as the handle lifetime is tied to the WPF window
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for proper handle cleanup patterns in the codebase
rg -A 5 "SetForegroundWindow|GetForegroundWindow" 

Length of output: 1924


Script:

#!/bin/bash
# Check for HwndSource usage and disposal patterns
ast-grep --pattern 'HwndSource $_'

# Check for handle related cleanup/disposal patterns
rg -A 5 "HwndSource|Handle.Dispose|Handle.Close"

Length of output: 2080

Plugins/Flow.Launcher.Plugin.Sys/Main.cs Show resolved Hide resolved
Plugins/Flow.Launcher.Plugin.Sys/Main.cs Show resolved Hide resolved
Plugins/Flow.Launcher.Plugin.Sys/Main.cs Show resolved Hide resolved
Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs Outdated Show resolved Hide resolved
Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs Outdated Show resolved Hide resolved
Flow.Launcher/NativeMethods.txt Show resolved Hide resolved

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs (1)

34-34: Document the S_ExtractionFailed constant

Consider adding a comment explaining what this HRESULT value represents and when it occurs.

-        private static readonly HRESULT S_ExtractionFailed = (HRESULT)0x8004B200;
+        /// <summary>
+        /// HRESULT value indicating that thumbnail extraction failed.
+        /// Typically occurs when a thumbnail cannot be generated for a file.
+        /// </summary>
+        private static readonly HRESULT S_ExtractionFailed = (HRESULT)0x8004B200;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 49fc0b8 and 8a05c60.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs (3 hunks)
🔇 Additional comments (6)
Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs (6)

4-10: LGTM: Clean transition to CSWin32 imports

The new using directives appropriately support the transition from DllImport to CSWin32, with specific imports that align with the PR objectives.


14-16: LGTM: Improved documentation clarity

The added XML documentation clearly indicates the relationship between ThumbnailOptions and the Windows API enum SIIGBF.


38-38: LGTM: Improved type safety and resource management

The changes enhance type safety by using HBITMAP instead of IntPtr, and properly manage resources using CSWin32's PInvoke.DeleteObject.

Also applies to: 47-47


62-67: LGTM: Fixed COM object release issue

The implementation now correctly handles the COM object release by setting nativeShellItem to null after release, addressing the previous review comment about potential double release.


78-86: LGTM: Well-implemented fallback behavior

The code gracefully handles thumbnail extraction failures by falling back to icon extraction when appropriate, with proper exception handling.


51-96: Verify the thumbnail extraction behavior

Let's verify that the changes maintain correct thumbnail extraction behavior across different file types.

✅ Verification successful

Thumbnail extraction behavior maintains proper fallback mechanism

The code changes maintain correct thumbnail extraction behavior:

  • Proper fallback from ThumbnailOnly to IconOnly when extraction fails
  • Consistent handling across different file types:
    • Icon-only for directories
    • Full thumbnails for image files
    • Standard icons for regular files
  • Appropriate error handling with COM exception catching and resource cleanup

The implementation in ImageLoader.cs shows the correct usage patterns and the error handling in ThumbnailReader.cs ensures graceful degradation when thumbnail extraction fails.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for tests related to thumbnail extraction
rg -l "GetThumbnail.*ThumbnailOptions" --type cs

# Look for any existing issue reports about thumbnail extraction
gh issue list --search "thumbnail extraction"

# Check for any related changes in test files
rg -l "WindowsThumbnailProvider" --type cs

Length of output: 349


Script:

#!/bin/bash
# Check the implementation in ImageLoader.cs to understand the usage
rg -A 10 "GetThumbnail.*ThumbnailOptions" Flow.Launcher.Infrastructure/Image/ImageLoader.cs

# Check test coverage
fd -e cs -e config "Test" --exec rg -l "ThumbnailReader|ImageLoader"

# Look for any error handling or logging related to thumbnail extraction
rg "catch.*ThumbnailOptions" --type cs -A 5

Length of output: 2278

@taooceros
Copy link
Member

Cool! This has been something I want to do for a while.

@taooceros
Copy link
Member

taooceros commented Dec 14, 2024

Would you mind split this into three pr? We can probably get the two bug fix merged earlier. If too hard then let's just keep it here.

I think cswin32 will take a while to review (as I want to check the specific generated type). I am a bit messed up lately with my thesis (due probably 12/20) and some research stuff, so probably I will delay the review for that.

@Jack251970
Copy link
Contributor Author

Would you mind split this into three pr? We can probably get the two bug fix merged earlier. If too hard then let's just keep it here.

I think cswin32 will take a while to review (as I want to check the specific generated type). I am a bit messed up lately with my thesis (due probably 12/20) and some research stuff, so probably I will delay the review for that.

No worries for the time.

In those bug fixes, I use PInvoke so I think I should include it here.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (5)
Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (1)

100-100: Define buffer size as a named constant

The magic number 2000 for buffer capacity should be defined as a named constant at the class level for better maintainability and clarity.

Apply this diff at the class level:

+        private const uint MAX_PATH_LENGTH = 2000;

And update the usage:

-                uint capacity = 2000;
+                uint capacity = MAX_PATH_LENGTH;
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (1)

33-34: Extract magic number into a named constant

The value 260 (MAX_PATH) should be defined as a private constant at the class level since it's used multiple times.

+ private const int MAX_PATH = 260;
- const int MAX_PATH = 260;
Flow.Launcher/Helper/WindowsInteropHelper.cs (3)

Line range hint 42-97: Consider refactoring for improved maintainability

While the implementation is functionally correct, consider breaking down the method into smaller, focused methods to improve readability and maintainability.

Suggested refactoring:

+ private static bool IsSpecialWindowClass(string windowClass)
+ {
+     return windowClass == WINDOW_CLASS_WINTAB ||
+            windowClass == WINDOW_CLASS_CONSOLE ||
+            windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW;
+ }
+
+ private unsafe static string GetWindowClassName(HWND hWnd)
+ {
+     int capacity = 256;
+     char[] buffer = new char[capacity];
+     fixed (char* pBuffer = buffer)
+     {
+         PInvoke.GetClassName(hWnd, pBuffer, capacity);
+         int validLength = Array.IndexOf(buffer, '\0');
+         if (validLength < 0) validLength = capacity;
+         return new string(buffer, 0, validLength);
+     }
+ }
+
+ private static bool IsDesktopWindow(HWND hWnd, string windowClass)
+ {
+     if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
+     {
+         var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
+         hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
+         return !hWndDesktop.Equals(IntPtr.Zero);
+     }
+     return false;
+ }

58-69: Add comments explaining the string handling logic

The string handling approach using fixed buffers is correct, but it would benefit from comments explaining why this specific approach was chosen over alternatives like new string(pBuffer) or buffer.ToString().

Add the following comments:

+ // We use a fixed buffer approach instead of new string(pBuffer) or buffer.ToString() because:
+ // 1. new string(pBuffer) might read beyond the null terminator if the API doesn't add one
+ // 2. buffer.ToString() would return the type name instead of the buffer contents
  string windowClass;
  int capacity = 256;
  char[] buffer = new char[capacity];

106-107: Add error handling for window handle operations

While the implementation is correct, consider adding error handling for cases where the window handle might be invalid.

 public static void DisableControlBox(Window win)
 {
+    if (win == null) throw new ArgumentNullException(nameof(win));
     var hwnd = new HWND(new WindowInteropHelper(win).Handle);
+    if (hwnd.Value == IntPtr.Zero)
+    {
+        throw new InvalidOperationException("Failed to get window handle.");
+    }
     PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, 
         PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE) & ~(int)WINDOW_STYLE.WS_SYSMENU);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a05c60 and a088f91.

📒 Files selected for processing (4)
  • Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (2 hunks)
  • Flow.Launcher/Helper/WindowsInteropHelper.cs (3 hunks)
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (2 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (3 hunks)
🔇 Additional comments (12)
Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (4)

1-10: LGTM! Import changes align with CSWin32 transition

The new imports properly support the transition to CSWin32 for Windows API access.


89-117: 🛠️ Refactor suggestion

Refactor to eliminate 'unsafe' code in 'TryGetProcessFilename' method

The use of unsafe code can be avoided by utilizing managed code alternatives, enhancing code safety and maintainability.


109-112: ⚠️ Potential issue

Correct the usage of 'capacity' after 'QueryFullProcessImageName'

After calling PInvoke.QueryFullProcessImageName, the capacity parameter is updated to contain the length of the string copied into the buffer.


93-99: 🛠️ Refactor suggestion

Improve handle management using a single 'using' statement

The current implementation creates a handle and then wraps it in a SafeProcessHandle. This can be simplified to reduce the chance of handle leaks.

Apply this diff:

-                var handle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id);
-                if (handle.Value == IntPtr.Zero)
-                {
-                    return string.Empty;
-                }
-                using var safeHandle = new SafeProcessHandle(handle.Value, true);
+                using var safeHandle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id);
+                if (safeHandle.IsInvalid)
+                {
+                    return string.Empty;
+                }

Likely invalid or redundant comment.

Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (2)

5-7: LGTM: Appropriate CSWin32 imports added

The new imports from Windows.Win32 namespaces align with the PR's objective of replacing DllImport with CSWin32, providing type-safe access to Windows APIs.


Line range hint 13-18: LGTM: Clean COM import implementation

The ShellLink class implementation is correct and follows COM interop best practices. The GUID matches the IShellLinkW interface specification.

Flow.Launcher/Helper/WindowsInteropHelper.cs (2)

7-9: LGTM: Improved type safety with CSWin32

The transition from raw IntPtr to strongly-typed HWND and the addition of CSWin32 imports enhances type safety and follows modern Windows API best practices.

Also applies to: 16-17


21-34: LGTM: Clean property implementations

The properties are well-implemented with proper null checks and lazy initialization using the new CSWin32 types and PInvoke class.

Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (4)

6-7: LGTM! Using directives align with CSWin32 transition

The addition of Windows.Win32 namespaces properly supports the transition from DllImport to CSWin32, providing better type safety for Windows API interactions.


42-42: LGTM! Proper usage of PInvoke.EnumThreadWindows

The conversion to CSWin32's PInvoke is correct, with proper type casting for the thread ID.


45-50: LGTM! Improved type safety with Windows-specific types

The signature change from generic IntPtr to specific HWND and LPARAM types enhances type safety and better represents the Windows API contract.


52-69: 🛠️ Refactor suggestion

Refactor GetWindowTitle to avoid unsafe code

While the current implementation works, using StringBuilder would be safer and eliminate the need for unsafe code and manual null termination handling.

Apply this diff to refactor the code:

-        private static unsafe string GetWindowTitle(HWND hwnd)
+        private static string GetWindowTitle(HWND hwnd)
         {
-            var capacity = PInvoke.GetWindowTextLength(hwnd) + 1;
-            char[] buffer = new char[capacity];
-            fixed (char* pBuffer = buffer)
-            {
-                if (PInvoke.GetWindowText(hwnd, (PWSTR)pBuffer, capacity) == 0)
-                {
-                    return string.Empty;
-                }
-
-                int validLength = Array.IndexOf(buffer, '\0');
-                if (validLength < 0) validLength = capacity;
-                return new string(buffer, 0, validLength);
-            }
+            int capacity = PInvoke.GetWindowTextLength(hwnd) + 1;
+            var sb = new StringBuilder(capacity);
+            if (PInvoke.GetWindowText(hwnd, sb, capacity) == 0)
+            {
+                return string.Empty;
+            }
+            return sb.ToString();
         }

This comment has been minimized.

This comment has been minimized.

@taooceros
Copy link
Member

@Jack251970 I add some change to your pr, please take a look.

Mainly it does two things:

  • Use stackalloc and Span API whenever possible
  • Release the safehandle directly if possible instead of releasing the underlying resource manually

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (1)

89-114: 🛠️ Refactor suggestion

Eliminate unsafe code using StringBuilder.

The method currently uses unsafe code with pointer manipulation, which can be replaced with a safer StringBuilder approach as suggested in the previous review.

-        public unsafe string TryGetProcessFilename(Process p)
+        public string TryGetProcessFilename(Process p)
         {
             try
             {
-                var handle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id);
-                if (handle.Value == IntPtr.Zero)
+                using var safeHandle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id);
+                if (safeHandle.IsInvalid)
                 {
                     return string.Empty;
                 }
-                using var safeHandle = new SafeProcessHandle(handle.Value, true);
-                uint capacity = 2000;
-                Span<char> buffer = new char[capacity];
-                fixed (char* pBuffer = buffer)
-                {
-                    if (!PInvoke.QueryFullProcessImageName(safeHandle, PROCESS_NAME_FORMAT.PROCESS_NAME_WIN32, (PWSTR)pBuffer, ref capacity))
-                    {
-                        return string.Empty;
-                    }
-
-                    return buffer[..(int)capacity].ToString();
-                }
+                uint capacity = 2000;
+                var sb = new StringBuilder((int)capacity);
+                if (!PInvoke.QueryFullProcessImageName(safeHandle, PROCESS_NAME_FORMAT.PROCESS_NAME_WIN32, sb, ref capacity))
+                {
+                    return string.Empty;
+                }
+                return sb.ToString();
             }
             catch
             {
                 return string.Empty;
             }
         }
🧹 Nitpick comments (9)
Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (2)

89-89: Add XML documentation for the method.

Consider adding XML documentation to describe the method's purpose, parameters, return value, and potential exceptions.

+        /// <summary>
+        /// Attempts to get the full path of the executable file for the specified process.
+        /// </summary>
+        /// <param name="p">The process to query.</param>
+        /// <returns>The full path of the process executable, or an empty string if the path cannot be retrieved.</returns>
         public unsafe string TryGetProcessFilename(Process p)

93-96: Improve handle management using using declaration.

The current handle management could be improved by using a using declaration directly with OpenProcess.

-                var handle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id);
-                if (handle.Value == IntPtr.Zero)
-                {
-                    return string.Empty;
-                }
-
-                using var safeHandle = new SafeProcessHandle(handle.Value, true);
+                using var safeHandle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, (uint)p.Id);
+                if (safeHandle.IsInvalid)
+                {
+                    return string.Empty;
+                }
Flow.Launcher/Helper/WallpaperPathRetrieval.cs (2)

19-25: Add null check and validation for wallpaper path

The wallpaper path retrieval could return null or empty string which should be handled explicitly before returning.

Apply this diff:

 public static unsafe string GetWallpaperPath()
 {
     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();
+    var path = wallpaper.ToString();
+    return string.IsNullOrWhiteSpace(path) ? null : path;
 }

36-43: Add logging for color parsing failures

The catch block silently swallows exceptions from color parsing. Consider logging these failures to help with debugging.

Flow.Launcher/Helper/DWMDropShadow.cs (1)

48-48: Replace magic number with sizeof operator

The hard-coded value '4' for the size parameter should be replaced with sizeof(int) for better maintainability.

Apply this diff:

-var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
+var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, sizeof(int));
Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs (1)

32-34: Consider using null-conditional operator for ModuleName access

The ModuleName property access could throw if MainModule is null.

Apply this diff:

-return PInvoke.SetWindowsHookEx(hookId, proc, PInvoke.GetModuleHandle(curModule.ModuleName), 0);
+return PInvoke.SetWindowsHookEx(hookId, proc, PInvoke.GetModuleHandle(curModule?.ModuleName), 0);
Flow.Launcher/Helper/WindowsInteropHelper.cs (1)

108-125: Add documentation for the window style modification

While the error handling is robust, consider adding a comment explaining which specific window style bits are being modified and their impact. This would help future maintainers understand the implications of the style changes.

 public static void DisableControlBox(Window win)
 {
     var hwnd = new HWND(new WindowInteropHelper(win).Handle);
     
+    // Remove the system menu (WS_SYSMENU) style bit to disable the control box
+    // This affects: close button, minimize button, maximize button, and system menu
     var style = PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs (2)

22-54: Consider the tradeoffs of unsafe code vs. performance

While the previous review suggested avoiding unsafe code, the current implementation makes good use of modern C# features like Span<T> and MemoryMarshal which provide both safety and performance benefits. The pointer operations are well-contained within the fixed block and proper resource cleanup is implemented.

However, to improve maintainability, consider adding XML documentation to explain:

  1. Why unsafe code is necessary here
  2. What safety measures are in place
  3. The performance benefits of this approach

24-25: Consider making buffer size configurable

The hard-coded buffer size of 1024 characters might be insufficient for some localized strings. Consider:

  1. Making this configurable via a constant at the class level
  2. Adding a comment explaining why this size was chosen
  3. Adding validation for very long paths
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f89909 and 0153f71.

📒 Files selected for processing (8)
  • Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs (3 hunks)
  • Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (3 hunks)
  • Flow.Launcher/Helper/DWMDropShadow.cs (2 hunks)
  • Flow.Launcher/Helper/WallpaperPathRetrieval.cs (2 hunks)
  • Flow.Launcher/Helper/WindowsInteropHelper.cs (4 hunks)
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (2 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (3 hunks)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs
🔇 Additional comments (15)
Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs (1)

1-10: LGTM! Imports align with CSWin32 migration.

The new imports correctly support the transition from DllImport to CSWin32, providing access to the necessary Windows API functionality through managed wrappers.

Flow.Launcher/Helper/DWMDropShadow.cs (1)

52-54: LGTM: Proper MARGINS initialization and error handling

The MARGINS structure is correctly initialized and the HRESULT is properly checked.

Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs (2)

55-56: LGTM: Fixed right Win key detection

The implementation now correctly checks both left and right Windows keys, fixing the issue mentioned in the PR objectives.


91-91: LGTM: Proper resource cleanup

The hook handle is properly disposed using the SafeHandle's Dispose method.

Flow.Launcher/Helper/WindowsInteropHelper.cs (5)

9-11: LGTM! Improved type safety with HWND

The transition from IntPtr to HWND for window handles and the addition of CSWin32 namespaces enhances type safety and aligns with modern Windows API best practices.

Also applies to: 18-19


23-37: LGTM! Proper null handling with HWND

The properties correctly handle null checks using HWND.Null and utilize the PInvoke class for Windows API calls.


Line range hint 44-70: LGTM! Efficient buffer handling with stackalloc

The method now uses modern C# features for efficient buffer handling:

  • stackalloc for small, temporary buffers
  • Span<char> for safe memory management
  • Fixed pointer operations for native interop

149-149: LGTM! Consistent formatting

The minor formatting change maintains consistency without affecting functionality.


Line range hint 1-151: Verify complete migration to CSWin32 across codebase

While the changes in this file are well-implemented, there are other files in the codebase that still use DllImport. Consider creating follow-up tasks to migrate the remaining files for consistency:

  • Flow.Launcher.Core/Resource/Theme.cs
  • Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs
  • Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenuDisplayHelper.cs
  • Flow.Launcher.Plugin.Explorer/Search/Everything/*.cs
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs (2)

4-6: LGTM: Using directives align with CSWin32 migration

The new using directives correctly import the necessary Windows.Win32 namespaces for the CSWin32-based implementation.


45-46: Document buffer clearing behavior

The comment indicates uncertainty about PInvoke.LoadString behavior. Consider:

  1. Verifying the actual behavior through testing or documentation
  2. Updating the comment to reflect the findings
  3. If the behavior is confirmed, remove the "not sure about" phrasing
✅ Verification successful

Buffer clearing is necessary for null-terminated string handling

The code is using Windows API functions through PInvoke to handle localized shell item names. The buffer clearing is necessary because:

  1. The code uses MemoryMarshal.CreateReadOnlySpanFromNullTerminated() which relies on null-termination
  2. The same buffer is reused after ExpandEnvironmentStrings call
  3. LoadString is a Windows API function that writes a null-terminated string to the buffer

The comment should be updated to explain the requirement rather than expressing uncertainty:

// Clear the buffer to ensure proper null-termination for LoadString and subsequent CreateReadOnlySpanFromNullTerminated call
buffer.Clear();
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for tests or documentation about LoadString behavior
rg -i "loadstring.*test" 
rg -i "loadstring.*behavior"

Length of output: 57


Script:

#!/bin/bash
# Let's look for the PInvoke.LoadString usage and implementation
rg -A 5 "LoadString" 

# Also search for any related comments or documentation
rg -i "pinvoke.*loadstring"

Length of output: 1893


Script:

#!/bin/bash
# Let's look at the broader context of this file to understand the buffer usage
cat "Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs"

# Also check if there are any related Windows API or PInvoke documentation references
rg -i "loadstring.*windows"
rg -i "windows.*api.*string"

Length of output: 3703

Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (4)

5-7: LGTM! Appropriate use of CSWin32 imports

The migration to Windows.Win32 namespaces aligns with the PR objective of replacing DllImport with CSWin32, providing better type safety and IntelliSense support.


49-53: Refactor repeated buffer handling pattern

The buffer handling pattern is repeated multiple times in the code. This should be extracted into a helper method.


25-31: ⚠️ Potential issue

Add null check and implement IDisposable pattern

The COM object handling should follow proper disposal patterns and include parameter validation.

+ public class ShellLinkHelper : IDisposable
+ {
+     private bool _disposed;
+     private ShellLink? _link;
+
-     public unsafe string retrieveTargetPath(string path)
+     public unsafe string retrieveTargetPath(string path)
      {
+         if (path == null) throw new ArgumentNullException(nameof(path));
+         if (_disposed) throw new ObjectDisposedException(nameof(ShellLinkHelper));
+
-         var link = new ShellLink();
+         _link = new ShellLink();
          const int STGM_READ = 0;
-         ((IPersistFile)link).Load(path, STGM_READ);
+         ((IPersistFile)_link).Load(path, STGM_READ);

Likely invalid or redundant comment.


34-42: Consider buffer overflow risks with stackalloc

The use of stackalloc with MAX_PATH (260) size could cause stack overflow in certain scenarios. Consider using a pooled buffer or heap allocation for safer memory management.

Also, document why SLGP_FLAGS.SLGP_SHORTPATH is used instead of SLGP_RAWPATH.

@Jack251970
Copy link
Contributor Author

@Jack251970 I add some change to your pr, please take a look.

Mainly it does two things:

  • Use stackalloc and Span API whenever possible
  • Release the safehandle directly if possible instead of releasing the underlying resource manually

It looks good to me. Thanks!

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (2)

34-44: Consider validating path length before stackalloc

While using stackalloc and MemoryMarshal is more efficient, consider validating that the path length doesn't exceed MAX_PATH before allocation to prevent stack overflow.

+ if (path.Length >= MAX_PATH)
+     throw new ArgumentException($"Path length exceeds maximum allowed length of {MAX_PATH}", nameof(path));
  Span<char> buffer = stackalloc char[MAX_PATH];

Line range hint 25-82: Overall improvement in memory management and type safety

The transition to CSWin32 and the use of modern C# features (stackalloc, Span, MemoryMarshal) improve both type safety and performance. However, consider implementing the suggested improvements from previous reviews to make the code more robust and maintainable:

  1. Add proper null checks and COM object disposal
  2. Extract repeated buffer handling pattern
  3. Add consistent error handling
  4. Add path length validation
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0153f71 and 02a4566.

📒 Files selected for processing (1)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (3 hunks)
🔇 Additional comments (5)
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs (5)

5-7: LGTM: CSWin32 imports properly replace DllImport

The transition to Windows.Win32 namespaces aligns with the PR objective of replacing DllImport with CSWin32, providing better type safety and maintainability.


25-25: Add null check and proper COM object disposal

The unsafe keyword is correctly added, but the previous review suggestions about adding null checks and proper COM object disposal are still relevant.


30-31: LGTM: Proper HWND initialization

The HWND initialization using IntPtr.Zero is correct and consistent with CSWin32 usage.


57-61: Extract repeated buffer handling pattern

The previous review suggestion about extracting the repeated buffer handling pattern into a helper method is still valid and would improve maintainability.


71-75: Add consistent error handling for GetArguments

The previous review suggestion about adding consistent error handling for GetArguments is still valid to maintain robustness.

@taooceros taooceros enabled auto-merge December 27, 2024 18:46
Copy link

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

❌ Errors Count
❌ forbidden-pattern 26
❌ ignored-expect-variant 1
⚠️ non-alpha-in-dictionary 19

See ❌ Event descriptions for more information.

Forbidden patterns 🙅 (1)

In order to address this, you could change the content to not match the forbidden patterns (comments before forbidden patterns may help explain why they're forbidden), add patterns for acceptable instances, or adjust the forbidden patterns themselves.

These forbidden patterns matched content:

s.b. workaround(s)

\bwork[- ]arounds?\b
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (1)

53-65: Performance optimization with safe memory management.

The implementation cleverly uses stackalloc for small buffers while falling back to heap allocation for larger ones, which is more performant than using StringBuilder. The error handling is also well-documented.

However, consider adding XML documentation to explain the return value behavior:

+        /// <summary>
+        /// Gets the title of the specified window.
+        /// </summary>
+        /// <param name="hwnd">A handle to the window or control containing the text.</param>
+        /// <returns>
+        /// The window title string if successful, or an empty string if the window has no title bar or text,
+        /// the title bar is empty, or the window handle is invalid.
+        /// </returns>
         private static unsafe string GetWindowTitle(HWND hwnd)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02a4566 and 9350e82.

📒 Files selected for processing (1)
  • Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (3 hunks)
🔇 Additional comments (3)
Flow.Launcher.Plugin/SharedCommands/ShellCommand.cs (3)

6-7: LGTM! Appropriate imports for CSWin32 implementation.

The addition of Windows.Win32 imports aligns with the PR objective of replacing DllImport with CSWin32.


43-43: LGTM! Improved type safety with CSWin32.

The transition to CSWin32 types (HWND, LPARAM) and PInvoke.EnumThreadWindows provides better type safety while maintaining the original functionality.

Also applies to: 46-51


6-7: Verify consistent CSWin32 usage across the codebase.

Let's verify that similar Windows API calls in other files have been consistently updated to use CSWin32.

Also applies to: 43-43, 46-46, 53-53

@taooceros taooceros merged commit fd3576d into Flow-Launcher:dev Dec 28, 2024
4 checks passed
@taooceros
Copy link
Member

emmm I am a little bit suspecting that this pr breaks the program plugin indexing. I will retest it.

@Jack251970
Copy link
Contributor Author

emmm I am a little bit suspecting that this pr breaks the program plugin indexing. I will retest it.

Thank you for reviewing.

@taooceros
Copy link
Member

Maybe not because of this. I try the latest dev and it seems to be able to index? I am not sure. Have you experienced some issue with indexing?

@Jack251970
Copy link
Contributor Author

Maybe not because of this. I try the latest dev and it seems to be able to index? I am not sure. Have you experienced some issue with indexing?

how can I test it?

@taooceros
Copy link
Member

How about deleting the cache first and then start the latest dev and see whether it can successfully load the programs?

@Jack251970
Copy link
Contributor Author

How about deleting the cache first and then start the latest dev and see whether it can successfully load the programs?

I have tested and I have not encountered this problem.

@taooceros
Copy link
Member

Thanks for testing. I guess it's something else.

@Jack251970 Jack251970 mentioned this pull request Jan 3, 2025
Comment on lines -57 to -59
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jack251970 I am getting an error from using the built-in shortcut active explorer path, could you please check if it's caused by this change.

image

Repro:

  1. Open any path in Windows Explorer
  2. Set the Custom Query Hotkey like this
    image
  3. Use the hotkey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jjw24 Check #3168 please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants