Skip to content

Program Plugin: Refactor ShellLinkReader and fix argument/description retrieval#4490

Open
DavidGBrett wants to merge 14 commits into
devfrom
fix-shell-link-buffer-issue
Open

Program Plugin: Refactor ShellLinkReader and fix argument/description retrieval#4490
DavidGBrett wants to merge 14 commits into
devfrom
fix-shell-link-buffer-issue

Conversation

@DavidGBrett
Copy link
Copy Markdown
Contributor

@DavidGBrett DavidGBrett commented May 25, 2026

Closes #4486

Bug Fixes

  • Uses a seperate buffer for description with the correct constant INFOTIPSIZE for its size
  • Use IPropertyStore to retrieve arguments as is recommended, instead of outdated IShellLinkW .GetArguments

Rework

  • Rename ShellLinkHelper to ShellLinkReader, to properly reflect its narrow scope
  • Replace manual COM imports and hardcoded constants with CsWin32-generated equivalents
  • Seperate each retrieval path into its own private method
  • Use a single static read method that returns a new immutable record, instead of messy mix of return value and implicitly modified instance fields

Summary by cubic

Refactors .lnk parsing into a new ShellLinkReader using CsWin32 interop and separate, correctly sized buffers. Fixes truncated descriptions and arguments, simplifies usage in Win32.cs, and corrects logger class names.

Summary of changes

  • Changed: Arguments read via IPropertyStore/PKEY_Link_Arguments (replaces IShellLinkW.GetArguments); description uses PInvoke.INFOTIPSIZE; target uses PInvoke.MAX_PATH; separate stackalloc buffers per field and cleared before use; resolve with SLR_NO_UI; improved COMException handling; LogException messages use the correct class name.
  • Added: ShellLinkReader.Read(path) returning immutable ShellLinkReadResult; dedicated methods for target/description/arguments; NativeMethods.txt entries for ShellLink, STGM, IPropertyStore, PROPERTYKEY, PROPVARIANT, PKEY_Link_Arguments, PropVariantClear, VARENUM, INFOTIPSIZE, MAX_PATH.
  • Removed: Legacy ShellLinkHelper, old IShellLinkW.GetArguments path, and ad-hoc StringBuilder/constant handling in Win32.cs.
  • Memory impact: Neutral. Small stackalloc buffers, explicit PInvoke.PropVariantClear, and COM releases.
  • Security risks: Low. No new privileges; SLR_NO_UI avoids UI prompts; better cleanup reduces interop risk.
  • Unit tests: None added. Manually verified with shortcuts containing long descriptions/arguments.

Release Note
Shortcuts now show full descriptions and command-line options without being cut off.

Written for commit 1de6d75. Summary will update on new commits. Review in cubic

@github-actions github-actions Bot added this to the 2.2.0 milestone May 25, 2026
…_PATH in ShellLinkHelper

MAX_PATH can crop the description - INFOTIPSIZE is larger and the documented maximum length after Windows 2000
…tore access for arguments

This is the recommended method from win 7 onwards, as the old method could truncate the string

fix retrieveArguments param
…n immutable ShellLinkReadResult from Read

ShellLinkReadResult is a record that contains the target path, description, and arguments - this is better and more consistent than getting target path as return value and the others as mutable fields on the helper
This better reflects its purpose as the only thing it does is parse the shell link and get information from it - a single public read method
@DavidGBrett DavidGBrett force-pushed the fix-shell-link-buffer-issue branch from 722068a to 08df0ca Compare May 25, 2026 10:09
@DavidGBrett DavidGBrett added bug Something isn't working Code Refactor labels May 25, 2026
@DavidGBrett DavidGBrett marked this pull request as ready for review May 25, 2026 10:16
@coderabbitai coderabbitai Bot removed the bug Something isn't working label May 25, 2026
@DavidGBrett DavidGBrett added the bug Something isn't working label May 25, 2026
@DavidGBrett DavidGBrett changed the title Program Plugin: Refactor ShellLinkReader and improve argument/description retrieval Program Plugin: Refactor ShellLinkReader and fix argument/description retrieval May 25, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

Re-trigger cubic

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 12a1b6e9-8cf0-4e18-a75b-bec0547f5db8

📥 Commits

Reviewing files that changed from the base of the PR and between 7eb3adb and 1de6d75.

📒 Files selected for processing (1)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs

📝 Walkthrough

Walkthrough

Refactors .lnk handling: adds ShellLinkReadResult and native symbols, implements ShellLinkReader (uses IShellLinkW + IPropertyStore to extract path/description/arguments), replaces ShellLinkHelper usage in Win32.cs.

Changes

Shell Link Reader Refactoring

Layer / File(s) Summary
Data contract and native symbols
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReadResult.cs, Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
Adds ShellLinkReadResult(TargetPath, Description, Arguments) and updates NativeMethods.txt with IPropertyStore, PROPVARIANT, PKEY_Link_Arguments, PropVariantClear, VARENUM, INFOTIPSIZE, MAX_PATH, and related symbols.
ShellLinkReader implementation
Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs
New ShellLinkReader.Read(path) entry point; uses IPersistFile/IShellLinkW to load/resolve the link and IPropertyStore + PROPVARIANT parsing to extract arguments; includes helpers for path, description, and arguments plus COM cleanup and logging.
Integration and cleanup
Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs, Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs
Replaces ShellLinkHelper usage with ShellLinkReader.Read() in LnkProgram, reads TargetPath, Arguments, and Description from the result, removes the old ShellLinkHelper implementation, and updates using directives.

Sequence Diagram(s)

sequenceDiagram
  participant LnkProgram as LnkProgram
  participant Reader as ShellLinkReader
  participant IShellLinkW as IShellLinkW
  participant IPropertyStore as IPropertyStore
  LnkProgram->>Reader: Read(path)
  Reader->>IShellLinkW: IPersistFile.Load & Resolve (SLR_NO_UI)
  Reader->>IShellLinkW: GetPath() -> TargetPath
  Reader->>IShellLinkW: GetDescription() -> Description
  Reader->>IPropertyStore: GetValue(PKEY_Link_Arguments)
  IPropertyStore->>Reader: PROPVARIANT (vt, pwszVal)
  Reader->>LnkProgram: ShellLinkReadResult(TargetPath, Description, Arguments)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Jack251970
  • jjw24
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main changes: refactoring ShellLinkHelper into ShellLinkReader and fixing argument/description retrieval with improved buffer handling.
Description check ✅ Passed The description clearly relates to the changeset, explaining bug fixes for buffer sizes, IPropertyStore usage for arguments, and the refactoring from ShellLinkHelper to ShellLinkReader with immutable records.
Linked Issues check ✅ Passed The PR fully addresses issue #4486: uses INFOTIPSIZE for description buffer, replaces IShellLinkW.GetArguments with IPropertyStore/PKEY_Link_Arguments, and implements correctly-sized stackalloc buffers to prevent truncation.
Out of Scope Changes check ✅ Passed All changes are in-scope: refactoring ShellLinkHelper to ShellLinkReader, creating ShellLinkReadResult record, adding new NativeMethods entries, and updating Win32.cs to use the new API—all directly address the issue requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-shell-link-buffer-issue

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b9744b13-d357-46b6-ae43-4ae6ac072992

📥 Commits

Reviewing files that changed from the base of the PR and between ef7d89d and 08df0ca.

📒 Files selected for processing (5)
  • Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReadResult.cs
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs
  • Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
💤 Files with no reviewable changes (1)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs

Comment thread Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs Outdated
@DavidGBrett DavidGBrett marked this pull request as draft May 25, 2026 10:32
@DavidGBrett DavidGBrett marked this pull request as ready for review May 25, 2026 10:47
@coderabbitai coderabbitai Bot removed the bug Something isn't working label May 25, 2026
Copy link
Copy Markdown
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.

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

88-93: ⚡ Quick win

Keep GetDescription failures on the existing known-error path.

ProgramLogger.IsKnownWinProgramError only treats GetDescription exceptions as known when the logged calling method is LnkProgram. Logging this as retrieveDescription will reclassify the long-standing MiracastView.lnk failure as UNKNOWN and add noise. Either preserve the old token here or widen the logger mapping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs` around
lines 88 - 93, The logged calling token must remain the same so GetDescription
exceptions stay classified as known; change the ProgramLogger.LogException call
in ShellLinkReader.GetDescription to use the original "LnkProgram" (or the exact
token used by ProgramLogger.IsKnownWinProgramError) instead of
"retrieveDescription", keeping the existing message structure and passing the
exception e so IsKnownWinProgramError continues to recognize MiracastView.lnk
failures.

32-38: ⚡ Quick win

Return an explicit empty result instead of default.

return default; makes the failure contract depend on ShellLinkReadResult's declaration and default-state semantics. Win32.LnkProgram dereferences the result immediately, so returning an initialized empty result is safer and keeps this API stable.

Suggested change
                 catch (COMException e)
                 {
                     ProgramLogger.LogException(
                         $"|IShellLinkW|Read|{path}|Error occurred while loading or resolving shell link",
                         e
                     );
-                    return default;
+                    return new ShellLinkReadResult(string.Empty, string.Empty, string.Empty);
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs` around
lines 32 - 38, The catch block for COMException in ShellLinkReader.cs currently
returns default which makes caller behavior fragile; replace the return default
with an explicit, initialized ShellLinkReadResult instance (e.g., a
failure/empty result) so Win32.LnkProgram doesn't dereference an unset
value—construct and return a ShellLinkReadResult populated with safe defaults
(Success=false or equivalent, empty/nullable target/path fields set
appropriately, and any error metadata) instead of relying on default(T); update
the return in the COMException handler that surrounds ProgramLogger.LogException
to return that explicit empty result.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs`:
- Around line 88-93: The logged calling token must remain the same so
GetDescription exceptions stay classified as known; change the
ProgramLogger.LogException call in ShellLinkReader.GetDescription to use the
original "LnkProgram" (or the exact token used by
ProgramLogger.IsKnownWinProgramError) instead of "retrieveDescription", keeping
the existing message structure and passing the exception e so
IsKnownWinProgramError continues to recognize MiracastView.lnk failures.
- Around line 32-38: The catch block for COMException in ShellLinkReader.cs
currently returns default which makes caller behavior fragile; replace the
return default with an explicit, initialized ShellLinkReadResult instance (e.g.,
a failure/empty result) so Win32.LnkProgram doesn't dereference an unset
value—construct and return a ShellLinkReadResult populated with safe defaults
(Success=false or equivalent, empty/nullable target/path fields set
appropriately, and any error metadata) instead of relying on default(T); update
the return in the COMException handler that surrounds ProgramLogger.LogException
to return that explicit empty result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d261c827-570a-4957-ba37-29944f5491b2

📥 Commits

Reviewing files that changed from the base of the PR and between 08df0ca and 7eb3adb.

📒 Files selected for processing (1)
  • Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkReader.cs

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

Re-trigger cubic

@DavidGBrett DavidGBrett marked this pull request as draft May 25, 2026 10:52
Not necessary currently but defensive addition in case something goes wrong on the com side or no exception is thrown
@DavidGBrett DavidGBrett force-pushed the fix-shell-link-buffer-issue branch from 7eb3adb to 1f1d233 Compare May 25, 2026 10:54
@DavidGBrett DavidGBrett marked this pull request as ready for review May 25, 2026 11:01
@DavidGBrett DavidGBrett added the bug Something isn't working label May 25, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

Re-trigger cubic

@coderabbitai coderabbitai Bot removed the bug Something isn't working label May 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Program Plugin - MAX_PATH too small for IShellLinkW.GetDescription and .GetArguments buffers

1 participant