Skip to content

Keep BAML decompilation working when WPF assemblies are missing - #3876

Merged
siegfriedpammer merged 2 commits into
masterfrom
fix-baml-missing-wpf-assemblies
Jul 12, 2026
Merged

Keep BAML decompilation working when WPF assemblies are missing#3876
siegfriedpammer merged 2 commits into
masterfrom
fix-baml-missing-wpf-assemblies

Conversation

@siegfriedpammer

@siegfriedpammer siegfriedpammer commented Jul 11, 2026

Copy link
Copy Markdown
Member

Problem

Decompiling a WPF binary's BAML on a machine without WPF (Linux/macOS) crashed the entire BAML decompile. KnownThings hard-requires PresentationFramework, PresentationCore and WindowsBase to be resolvable; when they aren't, it throws Could not resolve known assembly '...' and aborts.

Fix

Mirroring MinimalCorlib: when a well-known BAML assembly can't be resolved, BamlDecompilerTypeSystem substitutes a synthetic stand-in module (SyntheticWpfModule) that upholds the invariant KnownThings assumes.

  • The stand-in only materializes the types the decompiler explicitly seeds, so it stays bounded to the well-known set; references to any other type keep degrading to UnknownType exactly as before (no behavioural change when the assemblies are present).
  • For the WPF assemblies it reproduces the XmlnsDefinitionAttribute mapping, so known types still serialize under the presentation xmlns instead of a clr-namespace fallback.

Tests

The BAML tests were orphaned (in no solution, no CI, and missing their ICSharpCode.BamlDecompiler reference). They are revived and split by platform, mirroring ILSpy.Tests / ILSpy.Tests.Windows:

  • ILSpy.BamlDecompiler.Tests (net11.0) — platform-agnostic tests, including a regression test that decompiles with the WPF assemblies hidden. Runs on the Linux/macOS/Windows legs.
  • ILSpy.BamlDecompiler.Tests.Windows (net11.0-windows) — the WPF round-trip cases that compile XAML into BAML. Runs on the Windows leg.

Each project is single-TFM, so each keeps a normal committed lock file; the Windows one declares all RIDs so its lock is generatable and verifiable on any host. The Windows job also archives the round-trip assembly (its embedded BAML lets the decompiler be exercised against real BAML on a host without WPF).

🤖 PR opened by an agent (Claude Code) on behalf of @siegfriedpammer.

image

KnownThings hard-required PresentationFramework, PresentationCore and
WindowsBase to be resolvable, so decompiling a WPF binary on a machine
without WPF (Linux/macOS) threw "Could not resolve known assembly" and
aborted the whole BAML decompile.

Mirror MinimalCorlib: when a well-known BAML assembly cannot be resolved,
BamlDecompilerTypeSystem substitutes a synthetic stand-in module that
upholds the invariant KnownThings assumes. The stand-in only materializes
the types the decompiler explicitly seeds, so it stays bounded to the
well-known set and references to other types keep degrading to
UnknownType exactly as before. For the WPF assemblies it also reproduces
the XmlnsDefinitionAttribute mapping so known types still serialize under
the presentation xmlns instead of a clr-namespace fallback.

Assisted-by: Claude:claude-opus-4-8:Claude Code

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

This PR updates the BAML decompiler’s type-system setup so it can continue decompiling WPF BAML when the well-known WPF assemblies (e.g., PresentationFramework) are not resolvable (common on non-Windows machines), by substituting synthetic stand-in modules and reviving/splitting BAML test coverage.

Changes:

  • Add a SyntheticWpfModule fallback and hook it into BamlDecompilerTypeSystem/KnownThings to avoid hard failures when WPF assemblies are missing.
  • Reintroduce and split BAML decompiler tests into platform-agnostic vs Windows-only projects, updating solutions/solution filters accordingly.
  • Extend Windows CI to archive the compiled BAML-fixtures assembly and execute the platform-agnostic BAML tests.

Reviewed changes

Copilot reviewed 13 out of 50 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ILSpy.XPlat.slnf Includes the platform-agnostic BAML decompiler test project in the xplat solution filter.
ILSpy.sln Adds both BAML decompiler test projects to the main solution.
ILSpy.Desktop.slnf Includes the platform-agnostic BAML decompiler test project in the desktop solution filter.
ILSpy.BamlDecompiler.Tests/packages.lock.json Updates lock file for the platform-agnostic test project’s new TFM/dependency graph.
ILSpy.BamlDecompiler.Tests/MissingReferencesTests.cs Adds regression coverage for decompiling when WPF assemblies are intentionally hidden.
ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj Converts the base BAML test project to platform-agnostic (net11.0) and wires references/signing.
ILSpy.BamlDecompiler.Tests.Windows/Mocks/AvalonDock.cs Restores WPF fixture mock types used by round-trip tests.
ILSpy.BamlDecompiler.Tests.Windows/ILSpy.BamlDecompiler.Tests.Windows.csproj Introduces Windows-only test project for WPF XAML→BAML round-trip fixtures.
ILSpy.BamlDecompiler.Tests.Windows/Cases/SimplePropertyElement.xaml Adds WPF XAML fixture for property-element serialization cases.
ILSpy.BamlDecompiler.Tests.Windows/Cases/SimpleNames.xaml.cs Adds code-behind fixture for name-related XAML cases.
ILSpy.BamlDecompiler.Tests.Windows/Cases/SimpleNames.xaml Adds XAML fixture for name/x:Name scenarios.
ILSpy.BamlDecompiler.Tests.Windows/Cases/SimpleDictionary.xaml Adds ResourceDictionary fixture.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Simple.xaml.cs Adds code-behind fixture for a basic Window case.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Simple.xaml Adds basic Window XAML fixture.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Resources.xaml.cs Adds code-behind fixture for resource dictionary nesting scenarios.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Resources.xaml Adds XAML fixture exercising repeated resource scopes.
ILSpy.BamlDecompiler.Tests.Windows/Cases/ReadonlyProperty.xaml.cs Adds code-behind fixture for readonly-property related cases.
ILSpy.BamlDecompiler.Tests.Windows/Cases/ReadonlyProperty.xaml Adds XAML fixture for readonly property element scenarios.
ILSpy.BamlDecompiler.Tests.Windows/Cases/NamespacePrefix.xaml Adds fixture stressing namespace prefix handling and unknown assemblies.
ILSpy.BamlDecompiler.Tests.Windows/Cases/MyControl.xaml.cs Adds custom control fixture code-behind used by multiple XAML cases.
ILSpy.BamlDecompiler.Tests.Windows/Cases/MyControl.xaml Adds custom control XAML fixture.
ILSpy.BamlDecompiler.Tests.Windows/Cases/MarkupExtension.xaml Adds fixture for markup extension parsing/formatting.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue775.xaml Adds fixture for a historical issue case.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue445.xaml Adds fixture for a historical issue case involving context menus/resources.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue3318.xaml.cs Adds code-behind fixture for issue 3318 scenario.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue3318.xaml Updates fixture assembly-qualified namespace to match the new Windows test assembly name.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue2116.xaml.cs Adds code-behind fixture for component resource key/static references.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue2116.xaml Adds fixture for style/resource reference permutations.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue2097.xaml.cs Adds code-behind fixture for static member usage in XAML.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue2097.xaml Adds fixture for {x:Static} usage.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue2052.xaml Adds fixture for x:XmlAttributeProperties.XmlSpace usage.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue1547.xaml.cs Adds code-behind fixture for style/setter ordering scenarios.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue1547.xaml Adds fixture for style/setter cases.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue1546.xaml Adds large ResourceDictionary fixture for serialization coverage.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Issue1435.xaml Adds fixture covering automation properties/name behaviors.
ILSpy.BamlDecompiler.Tests.Windows/Cases/EscapeSequence.xaml Adds fixture for escaped type names, cultures, and formatting.
ILSpy.BamlDecompiler.Tests.Windows/Cases/Dictionary1.xaml Adds fixture for color/brush resources and gradients.
ILSpy.BamlDecompiler.Tests.Windows/Cases/CustomControl.cs Adds a custom control fixture with an attached property for namespace-prefix tests.
ILSpy.BamlDecompiler.Tests.Windows/Cases/AvalonDockCommon.xaml Adds fixture exercising merged dictionaries and component resource keys.
ILSpy.BamlDecompiler.Tests.Windows/Cases/AvalonDockBrushes.xaml Adds fixture for resource keys and brushes.
ILSpy.BamlDecompiler.Tests.Windows/Cases/AttachedEvent.xaml.cs Adds code-behind fixture for attached event handling.
ILSpy.BamlDecompiler.Tests.Windows/Cases/AttachedEvent.xaml Adds fixture for attached event markup.
ILSpy.BamlDecompiler.Tests.Windows/BamlTestRunner.cs Adds the WPF round-trip test runner that compares decompiled XAML to source fixtures.
ILSpy.BamlDecompiler.Tests.Windows/BamlSecurityTests.cs Adds security/hardening tests to ensure malformed/crafted BAML fails safely.
ICSharpCode.BamlDecompiler/SyntheticWpfModule.cs Introduces the synthetic stand-in module for missing WPF assemblies, including XmlnsDefinitionAttribute mapping.
ICSharpCode.BamlDecompiler/Properties/AssemblyInfo.cs Adds InternalsVisibleTo so the new test project can access required internals.
ICSharpCode.BamlDecompiler/BamlDecompilerTypeSystem.cs Synthesizes missing “default BAML references” as synthetic modules (with presentation-xmlns mapping where applicable).
ICSharpCode.BamlDecompiler/Baml/KnownThings.cs Seeds synthetic modules via RegisterType() so only known types are materialized.
.github/workflows/build-ilspy.yml Archives Windows-built BAML fixture binaries and adds a step to run the platform-agnostic BAML tests (Windows workflow).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ICSharpCode.BamlDecompiler/SyntheticWpfModule.cs
Comment thread ILSpy.BamlDecompiler.Tests/MissingReferencesTests.cs Outdated
Comment thread .github/workflows/build-ilspy.yml
@siegfriedpammer
siegfriedpammer force-pushed the fix-baml-missing-wpf-assemblies branch from 9c22225 to 57388cc Compare July 12, 2026 09:21
The BAML tests were orphaned: in no solution, no CI, and missing their
ICSharpCode.BamlDecompiler reference. Revive them split by platform,
mirroring ILSpy.Tests / ILSpy.Tests.Windows: ILSpy.BamlDecompiler.Tests
(net11.0) holds platform-agnostic tests - including a regression test that
decompiles with the WPF assemblies hidden, covering the missing-assembly
fix - and ILSpy.BamlDecompiler.Tests.Windows (net11.0-windows) holds the
WPF round-trip cases that compile XAML into BAML. Single-TFM projects keep
normal lock files; the Windows one declares all RIDs so its lock is
generatable and verifiable on any host.

Wire the cross-platform project into ILSpy.sln, ILSpy.XPlat.slnf and
ILSpy.Desktop.slnf so it builds and runs on the Linux/macOS legs; the
Windows project stays in ILSpy.sln (its tests execute in the Windows leg).
The Windows job also archives that assembly, whose embedded BAML lets the
decompiler be exercised against real BAML on a host without WPF.

Assisted-by: Claude:claude-opus-4-8:Claude Code
@siegfriedpammer
siegfriedpammer force-pushed the fix-baml-missing-wpf-assemblies branch from 57388cc to de00484 Compare July 12, 2026 15:53
@siegfriedpammer
siegfriedpammer merged commit 5343d84 into master Jul 12, 2026
13 checks passed
@siegfriedpammer
siegfriedpammer deleted the fix-baml-missing-wpf-assemblies branch July 13, 2026 11:04
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.

2 participants