Skip to content

Try fix the dll file copy error - #22

Open
lindexi wants to merge 24 commits into
mainfrom
t/lindexi/FixMissingMethodExceptionTextAnalyzerItemize
Open

Try fix the dll file copy error#22
lindexi wants to merge 24 commits into
mainfrom
t/lindexi/FixMissingMethodExceptionTextAnalyzerItemize

Conversation

@lindexi

@lindexi lindexi commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Fixes #21

Description

Fixes a MissingMethodException thrown at runtime in ordinary AnyCPU WPF projects.

The repository-built PresentationCore.dll calls TextAnalyzer.Itemize, and its signature exactly matches the DirectWriteForwarder.dll implementation in the repo — the exception is not a bug in the text rendering code. The real cause is runtime assembly mixing:

  • The app loads the repository-built PresentationCore.dll;
  • but the matching DirectWriteForwarder.dll is not deployed;
  • so it binds to a same-named older implementation from the SDK / shared framework;
  • their internal method signatures differ, ultimately throwing a MissingMethodException.

This PR updates the transitive targets generated by the NuGet package so that ordinary AnyCPU projects also select and deploy the runtime assets matched with PresentationCore.

Customer Impact

Without this fix, ordinary AnyCPU WPF projects that do not explicitly set RuntimeIdentifier, PlatformTarget, or Platform (not limited to HandyControlDemo) throw a MissingMethodException at runtime due to assembly mixing, causing text-rendering-related functionality to fail outright and potentially crashing or breaking the app.

Regression

No. This is not a regression introduced in a recent release; it is a long-standing gap in the package's runtime asset selection logic. The repository runtime was only selected when a project explicitly set an RuntimeIdentifier or an x64/x86 platform, causing common AnyCPU projects to miss the app-local DirectWriteForwarder.dll.

Testing

  • NuGetPackageServiceTests: all 17 tests pass.
  • Builder.csproj builds successfully.
  • Added regression tests for AnyCPU and Prefer32Bit scenarios covering the transitive targets' runtime asset selection logic.

Risk

Low risk. The fix is focused on the architecture inference logic in the NuGet package's transitive targets:

  • Explicit RID and x64/x86 platform still take the highest priority, so behavior for existing explicitly-configured projects is unchanged;
  • For ordinary AnyCPU projects, win-x86 / win-x64 is selected based on Prefer32Bit and NETCoreSdkRuntimeIdentifier; the logic is clear and covered by new regression tests;
  • The affected scope is primarily scenarios that previously failed to deploy the runtime assets correctly, with minimal impact on already-working explicitly-configured projects.

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

WPF NuGet Build

@lindexi

lindexi commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Correction to my earlier analysis — the root cause is not a DLL copy error, but a CLR assembly resolution issue.

This was written by me (a human) in Chinese, then translated into English by DeepSeek (AI).

Root cause

The DirectWriteForwarder.dll in the publish directory is actually correct and binary-identical to the one inside the NuGet package. However, the original targets only copied the DLL into the output directory after Build/Publish completed. That post-hoc copy ensures the file exists on disk, but it does not register DirectWriteForwarder in the app's .deps.json.

As a result, the CLR keeps resolving the same-named assembly from the Microsoft.WindowsDesktop.App shared framework:

C:\Program Files (x86)\dotnet\shared\Microsoft.WindowsDesktop.App\8.0.29\DirectWriteForwarder.dll

The repo-built PresentationCore.dll has private ABI differences with the shared framework's DirectWriteForwarder.dll, so the call to TextAnalyzer.Itemize throws MissingMethodException.

This also explains:

  • Why having the correct DLL in the publish directory still doesn't help;
  • Why it reproduces on both x86 and x64;
  • Why it's not specific to HandyControl;
  • Why a default SDK WPF app doesn't fail — its PresentationCore and DirectWriteForwarder both come from the same shared framework.

Fix

Updated the buildTransitive targets generated by eng/Builder/NuGetPackageService.cs to:

  • Select the in-package DirectWriteForwarder.dll based on the current RID;
  • Add it to ReferenceDependencyPaths;
  • Set IncludeRuntimeDependency="true";
  • Add it to ReferenceCopyLocalPaths;
  • Remove any existing same-named old asset before registering it.

This makes it land in .deps.json, so the CLR resolves the repo version from the app directory instead of the shared framework version.

Added regression tests in eng/Builder.Tests/NuGetPackageServiceTests.cs.

Verification

Builder.Tests all pass:

  • Passed: 128
  • Failed: 0
  • Skipped: 0

lindexi and others added 23 commits August 30, 2026 12:47
…ps.json

The generated buildTransitive targets previously copied
DirectWriteForwarder.dll into the output directory only after
Build/Publish completed. This placed the file on disk but did not
register it in the application's .deps.json, so the CLR continued to
resolve the same-named assembly from the Microsoft.WindowsDesktop.App
shared framework. The resulting private ABI mismatch with the
repo-built PresentationCore.dll caused MissingMethodException when
calling TextAnalyzer.Itemize.

Update the generated targets to register the RID-specific
DirectWriteForwarder.dll as a real runtime dependency:

- Add it to ReferenceDependencyPaths.
- Set IncludeRuntimeDependency="true".
- Add it to ReferenceCopyLocalPaths.
- Remove any existing same-named asset before registering it.

This ensures the assembly is written to .deps.json and the CLR resolves
the repo version from the app directory instead of the shared framework
version.

Add regression tests covering this behavior.
…ences

The generated buildTransitive targets previously copied
DirectWriteForwarder.dll into the output directory only after
ResolveReferences completed. The file existed on disk but was never part
of the app's dependency graph, so framework-dependent apps still resolved
the same-named assembly from the Microsoft.WindowsDesktop.App shared
framework. The resulting internal ABI mismatch with the repo-built
PresentationCore.dll caused MissingMethodException at TextAnalyzer.Itemize.

Register the assembly before reference resolution instead:

- Add <Reference Include="DirectWriteForwarder"> with a RID-specific
  <HintPath>.
- Set <Private>true</Private> so it is treated as a real runtime
  dependency and written to .deps.json.
- Remove the previous ineffective logic that injected
  ReferenceDependencyPaths and ReferenceCopyLocalPaths after
  ResolveReferences.
This reverts commit b146214.
This reverts commit 703b230.
This reverts commit cd9859a.
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.

BUG: System.MissingMethodException: Method not found MS.Internal.Text.TextInterface.TextAnalyzer.Itemize

1 participant