Skip to content

fix(common): avoid icon extractor type-init crash on invalid fallback resources#2244

Merged
Belphemur merged 3 commits into
devfrom
copilot/fix-soundswitch-crash-issue
Jun 23, 2026
Merged

fix(common): avoid icon extractor type-init crash on invalid fallback resources#2244
Belphemur merged 3 commits into
devfrom
copilot/fix-soundswitch-crash-issue

Conversation

Copilot AI commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

After updating, SoundSwitch could crash during startup with a TypeInitializationException in AudioDeviceIconExtractor if bundled fallback icon resources failed deserialization. This blocked tray icon initialization and app boot.

  • Crash root cause addressed (static initialization hardening)

    • Replaced eager static fallback icon construction with guarded creation logic.
    • If Resources.defaultSpeakers / Resources.defaultMicrophone fail to load, code now logs and falls back to cloned SystemIcons instead of failing type initialization.
  • Fallback behavior preserved for invalid device icon paths

    • Existing ExtractIconFromPath fallback flow (Render/Capture) remains intact, now backed by resilient default-handle initialization.
  • Regression coverage

    • Added focused tests ensuring invalid icon paths still return a non-null fallback icon handle for both DataFlow.Render and DataFlow.Capture.
private static IconHandle CreatePermanentDefaultIcon(
    Func<System.Drawing.Icon> bundledIconFactory,
    Func<System.Drawing.Icon> fallbackIconFactory,
    string resourceName)
{
    try
    {
        return IconExtractor.CreatePermanent(bundledIconFactory());
    }
    catch (Exception e)
    {
        Log.Warning(e, "Can't load bundled fallback icon {resourceName}, using system icon fallback", resourceName);
        return IconExtractor.CreatePermanent((System.Drawing.Icon)fallbackIconFactory().Clone());
    }
}

… resources

Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix crash in SoundSwitch v7.1.1-beta.3 after updating Prevent AudioDeviceIconExtractor startup crash when bundled fallback icons fail to load Jun 23, 2026
Copilot AI requested a review from Belphemur June 23, 2026 12:07
@Belphemur Belphemur marked this pull request as ready for review June 23, 2026 12:23
Copilot AI review requested due to automatic review settings June 23, 2026 12:23
@Belphemur

Copy link
Copy Markdown
Owner

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8bb3e962-3e7d-4561-b2c2-01235470a26d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

AudioDeviceIconExtractor replaces direct static initialization of its two default icon handles with a new CreatePermanentDefaultIcon helper that wraps bundled-resource loading in a try/catch, logging a warning and falling back to a SystemIcons clone on failure. A new NUnit test fixture verifies the fallback returns non-null icon handles for both render and capture data flows given an invalid path.

Changes

Default Icon Fallback and Test

Layer / File(s) Summary
CreatePermanentDefaultIcon helper and fallback test
SoundSwitch.Common/Framework/Audio/Icon/AudioDeviceIconExtractor.cs, SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs
Static default icon handles are now initialized via CreatePermanentDefaultIcon, which catches exceptions during bundled-resource loading and falls back to a SystemIcons clone. A parameterized NUnit test asserts ExtractIconFromPath returns a non-null handle and Icon for both DataFlow.Render and DataFlow.Capture when given an invalid path.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Poem

🐇 Hop! The icons now land safe and sound,
If the bundle breaks, a fallback is found.
SystemIcons steps in with a clone of its own,
No null handle left to throw or moan.
The tests confirm both mic and speaker shine —
Every icon path walks a guarded line! 🎵

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding crash prevention for AudioDeviceIconExtractor when bundled fallback icons fail to load during startup.
Description check ✅ Passed The description is directly related to the changeset, providing context about the crash, the fix approach, and test coverage added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/fix-soundswitch-crash-issue

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs (1)

14-22: 🎯 Functional Correctness | 🔵 Trivial | ⚖️ Poor tradeoff

Consider validating the correct fallback icon type is returned.

The test effectively verifies non-null fallback icons are returned for invalid paths, which matches the PR objective. However, it could be strengthened by validating that DataFlow.Render returns the speakers icon and DataFlow.Capture returns the microphone icon, ensuring the dataflow-specific fallback logic is correct.

💡 Optional enhancement to validate icon types

This would require comparing the returned icon against the expected fallback (e.g., by comparing icon dimensions, pixel data, or other properties), which may be complex and brittle. The current test provides good coverage of the non-null guarantee, so this enhancement is optional.

🤖 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 `@SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs` around lines 14 - 22, The
test ExtractIconFromPath_WhenPathIsInvalid_ReturnsFallbackIcon currently only
validates that fallback icons are non-null, but does not verify that the correct
icon type is returned for each DataFlow parameter. Add assertions to validate
that when dataFlow is DataFlow.Render, a speakers icon is returned, and when
dataFlow is DataFlow.Capture, a microphone icon is returned. This can be done by
comparing icon properties or dimensions against the expected fallback icons to
ensure the dataflow-specific fallback logic functions correctly.
🤖 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.

Inline comments:
In `@SoundSwitch.Common/Framework/Audio/Icon/AudioDeviceIconExtractor.cs`:
- Around line 36-47: The CreatePermanentDefaultIcon method is missing XML
documentation comments that should describe its purpose, parameters, and return
value. Add XML documentation above the method signature that includes a summary
explaining what the method does, parameter descriptions for bundledIconFactory,
fallbackIconFactory, and resourceName parameters, and a returns section
describing the IconHandle that is returned. This will ensure the method complies
with coding guidelines requiring proper documentation for all public members.

In `@SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs`:
- Around line 11-13: The AudioDeviceIconExtractorTests class is missing XML
documentation comments. Add XML documentation above the class declaration using
the standard C# documentation syntax (/// comments) to describe the purpose and
responsibility of the test class. Include a summary tag that explains what the
AudioDeviceIconExtractorTests class tests and its overall purpose within the
test suite.

---

Nitpick comments:
In `@SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs`:
- Around line 14-22: The test
ExtractIconFromPath_WhenPathIsInvalid_ReturnsFallbackIcon currently only
validates that fallback icons are non-null, but does not verify that the correct
icon type is returned for each DataFlow parameter. Add assertions to validate
that when dataFlow is DataFlow.Render, a speakers icon is returned, and when
dataFlow is DataFlow.Capture, a microphone icon is returned. This can be done by
comparing icon properties or dimensions against the expected fallback icons to
ensure the dataflow-specific fallback logic functions correctly.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 15e70577-3a2a-4923-99d1-003a28fe3d8d

📥 Commits

Reviewing files that changed from the base of the PR and between 27e2005 and 12b35d9.

📒 Files selected for processing (2)
  • SoundSwitch.Common/Framework/Audio/Icon/AudioDeviceIconExtractor.cs
  • SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs

Comment on lines +36 to +47
private static IconHandle CreatePermanentDefaultIcon(Func<System.Drawing.Icon> bundledIconFactory, Func<System.Drawing.Icon> fallbackIconFactory, string resourceName)
{
try
{
return IconExtractor.CreatePermanent(bundledIconFactory());
}
catch (Exception e)
{
Log.Warning(e, "Can't load bundled fallback icon {resourceName}, using system icon fallback", resourceName);
return IconExtractor.CreatePermanent((System.Drawing.Icon)fallbackIconFactory().Clone());
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add XML documentation to the helper method.

The CreatePermanentDefaultIcon method lacks XML documentation. As per coding guidelines, classes and their members should use proper XML documentation to explain their purpose, parameters, and return values.

📝 Proposed XML documentation
+        /// <summary>
+        /// Creates a permanent icon handle from a bundled resource with fallback to system icons on failure.
+        /// </summary>
+        /// <param name="bundledIconFactory">Factory that returns the bundled icon resource.</param>
+        /// <param name="fallbackIconFactory">Factory that returns a system icon if bundled resource fails to load.</param>
+        /// <param name="resourceName">Name of the bundled resource for logging purposes.</param>
+        /// <returns>A permanent <see cref="IconHandle"/> that must be manually disposed.</returns>
         private static IconHandle CreatePermanentDefaultIcon(Func<System.Drawing.Icon> bundledIconFactory, Func<System.Drawing.Icon> fallbackIconFactory, string resourceName)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static IconHandle CreatePermanentDefaultIcon(Func<System.Drawing.Icon> bundledIconFactory, Func<System.Drawing.Icon> fallbackIconFactory, string resourceName)
{
try
{
return IconExtractor.CreatePermanent(bundledIconFactory());
}
catch (Exception e)
{
Log.Warning(e, "Can't load bundled fallback icon {resourceName}, using system icon fallback", resourceName);
return IconExtractor.CreatePermanent((System.Drawing.Icon)fallbackIconFactory().Clone());
}
}
/// <summary>
/// Creates a permanent icon handle from a bundled resource with fallback to system icons on failure.
/// </summary>
/// <param name="bundledIconFactory">Factory that returns the bundled icon resource.</param>
/// <param name="fallbackIconFactory">Factory that returns a system icon if bundled resource fails to load.</param>
/// <param name="resourceName">Name of the bundled resource for logging purposes.</param>
/// <returns>A permanent <see cref="IconHandle"/> that must be manually disposed.</returns>
private static IconHandle CreatePermanentDefaultIcon(Func<System.Drawing.Icon> bundledIconFactory, Func<System.Drawing.Icon> fallbackIconFactory, string resourceName)
{
try
{
return IconExtractor.CreatePermanent(bundledIconFactory());
}
catch (Exception e)
{
Log.Warning(e, "Can't load bundled fallback icon {resourceName}, using system icon fallback", resourceName);
return IconExtractor.CreatePermanent((System.Drawing.Icon)fallbackIconFactory().Clone());
}
}
🤖 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 `@SoundSwitch.Common/Framework/Audio/Icon/AudioDeviceIconExtractor.cs` around
lines 36 - 47, The CreatePermanentDefaultIcon method is missing XML
documentation comments that should describe its purpose, parameters, and return
value. Add XML documentation above the method signature that includes a summary
explaining what the method does, parameter descriptions for bundledIconFactory,
fallbackIconFactory, and resourceName parameters, and a returns section
describing the IconHandle that is returned. This will ensure the method complies
with coding guidelines requiring proper documentation for all public members.

Source: Coding guidelines

Comment on lines +11 to +13
[TestFixture]
public class AudioDeviceIconExtractorTests
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add XML documentation to the test class.

The test class lacks XML documentation. As per coding guidelines, classes should use proper XML documentation to describe their purpose.

📝 Proposed XML documentation
+    /// <summary>
+    /// Tests for <see cref="AudioDeviceIconExtractor"/> icon extraction and fallback behavior.
+    /// </summary>
     [TestFixture]
     public class AudioDeviceIconExtractorTests
🤖 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 `@SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs` around lines 11 - 13, The
AudioDeviceIconExtractorTests class is missing XML documentation comments. Add
XML documentation above the class declaration using the standard C#
documentation syntax (/// comments) to describe the purpose and responsibility
of the test class. Include a summary tag that explains what the
AudioDeviceIconExtractorTests class tests and its overall purpose within the
test suite.

Source: Coding guidelines

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Hardens AudioDeviceIconExtractor static initialization to avoid startup crashes when bundled fallback icon resources fail to deserialize, ensuring tray/icon initialization can proceed with a system-icon fallback.

Changes:

  • Replaced eager static fallback icon initialization with guarded creation that logs and falls back to cloned SystemIcons on resource load failure.
  • Kept existing ExtractIconFromPath exception-based fallback behavior, now backed by resilient default icon handles.
  • Added regression tests verifying invalid icon paths still produce a usable fallback icon for both DataFlow.Render and DataFlow.Capture.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
SoundSwitch.Common/Framework/Audio/Icon/AudioDeviceIconExtractor.cs Wraps bundled fallback icon creation in a try/catch and falls back to cloned system icons to prevent type init crashes.
SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs Adds a regression test ensuring invalid icon paths return a non-null fallback icon for render/capture flows.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 2 file(s) based on 2 unresolved review comments.

Files modified:

  • SoundSwitch.Common/Framework/Audio/Icon/AudioDeviceIconExtractor.cs
  • SoundSwitch.Tests/AudioDeviceIconExtractorTests.cs

Commit: c4c0b2902837d27329a6442254dcb4c3e12ac869

The changes have been pushed to the copilot/fix-soundswitch-crash-issue branch.

Time taken: 3m 3s

Fixed 2 file(s) based on 2 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@Belphemur Belphemur changed the title Prevent AudioDeviceIconExtractor startup crash when bundled fallback icons fail to load fix(common): avoid icon extractor type-init crash on invalid fallback resources Jun 23, 2026
@Belphemur Belphemur merged commit 01a7a43 into dev Jun 23, 2026
12 checks passed
@Belphemur Belphemur deleted the copilot/fix-soundswitch-crash-issue branch June 23, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SoundSwitch v7.1.1-beta.3 Crash after updating

3 participants