WPF features are not available in MGCB Pipeline

WPF features are not available in MGCB Pipeline

Thank you for your support, my name is Onodera.

I’m trying to create a SpriteFont creation function using the WPF function in MGCB Pipeline.
I get an MGCB build error, so please let me know if there is a solution.

【環境】

  • Windows 10 Pro 1909
  • Visual Studio 2019 16.7.5
  • MonoGame 3.8.0.1641

First, it worked fine with MonoGame 3.7. An error has occurred since the version was upgraded to 3.8.

I tried to create the following projects in 3.8, but all of them gave an error.

a. Create Pipeline in .NET Core
b. Create Pipeline with .NET Framework
c. Create a Pipeline in .NET Standard (however, Standard doesn’t use WPF, so it internally refers to the .NET Framework)

Since a, b, and c are all doing the same thing, let’s take a as an example.

The project file sets “Use WPF” and “Microsoft .NET.Sdk.WindowsDesktop” to enable the use of WPF functions.

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="MonoGame.Framework.Content.Pipeline" Version="3.8.0.1641" />
    <PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.0.1641" />
  </ItemGroup>
</Project>

The Pipeline code looks like this:
It’s a test code, so it just references the WPF code. No special processing is done for SpriteFont.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using TInput = Microsoft.Xna.Framework.Content.Pipeline.Graphics.FontDescription;
using TOutput = WpfFontPipelineNetFramework.WpfSpriteFontContent;

namespace WpfFontPipelineNetFramework
{
  [ContentProcessor(DisplayName = "WpfCore")]
  public class Processor1 : ContentProcessor<TInput, TOutput>
  {
    public override TOutput Process(TInput input, ContentProcessorContext context)
    {
      var fontContnet = new WpfSpriteFontContent();

      var fontWeight = ((input.Style & FontDescriptionStyle.Bold) == FontDescriptionStyle.Bold) ? FontWeights.Bold : FontWeights.Regular;
      var fontStyle = ((input.Style & FontDescriptionStyle.Italic) == FontDescriptionStyle.Italic) ? FontStyles.Italic : FontStyles.Normal;
      var typeface = new Typeface(new System.Windows.Media.FontFamily(input.FontName), fontStyle, fontWeight, FontStretches.Normal);
      typeface.TryGetGlyphTypeface(out GlyphTypeface glyphTypeface);

      return fontContnet;
    }
  }

  public class WpfSpriteFontContent
  {
    public Texture2DContent Texture { get; set; }
    public List<Rectangle> Glyphs { get; set; }
    public List<Rectangle> Cropping { get; set; }
    public List<char> CharacterMap { get; set; }
    public int LineSpacing { get; set; }
    public float Spacing { get; set; }
    public List<Microsoft.Xna.Framework.Vector3> Kerning { get; set; }
    [ContentSerializer(AllowNull = true)]
    public char? DefaultCharacter { get; set; }

    public WpfSpriteFontContent()
    {
      Texture = new Texture2DContent();
      Glyphs = new List<Rectangle>();
      Cropping = new List<Rectangle>();
      CharacterMap = new List<char>();
      Kerning = new List<Vector3>();
    }
  }
}

When you refer to the DLL created by MGCB and set “WpfCore” in the Processor of Font.spritefont and build it, the following error is output.

C:/xxxx/MonoGamePipelineWpfTest/Font.spritefont: error: Processor ‘Processor1’ had unexpected failure!
System.IO.FileNotFoundException: Could not load file or assembly ‘PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’. The specified file could not be found.
File name: ‘PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’
at WpfFontPipelineNetCore.Processor1.Process(FontDescription input, ContentProcessorContext context)
at Microsoft.Xna.Framework.Content.Pipeline.ContentProcessor`2.Microsoft.Xna.Framework.Content.Pipeline.IContentProcessor.Process(Object input, ContentProcessorContext context) in C:\BuildAgents\MonoGameWin1\work\f7381a85a626990\MonoGame.Framework.Content.Pipeline\ContentProcessor.cs:line 60
at MonoGame.Framework.Content.Pipeline.Builder.PipelineManager.ProcessContent(PipelineBuildEvent pipelineEvent) in C:\BuildAgents\MonoGameWin1\work\f7381a85a626990\MonoGame.Framework.Content.Pipeline\Builder\PipelineManager.cs:line 717

The following error is output in the .NET Framework version.

Failed to load assembly ‘C:/xxxx/MonoGamePipelineWpfTest/dll/Framework/WpfFontPipelineNetFramework.dll’: Unable to load one or more of the requested types.
Could not load file or assembly ‘System.Configuration.ConfigurationManager, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51’. The specified file could not be found.
C:/xxxx/MonoGamePipelineWpfTest/Font.spritefont
Warning: Unable to load one or more of the requested types.
Could not load file or assembly ‘System.Configuration.ConfigurationManager, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51’. The specified file could not be found.
C:/xxxx/MonoGamePipelineWpfTest/Font.spritefont: error: Failed to create processor ‘Processor1’

For the .NET Standard version, the same error will be output because the above project will be referenced.

Is there any solution?

By the way, all of the following dlls exist.

  • C:\Windows\Microsoft_NET\assembly\GAC_32\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll
  • C:\Windows\Microsoft_NET\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll

The sample project is on OneDrive.

https://1drv.ms/u/s!Ap-DYzVqMCtRsuNG6hgsR3L_vjDrAA?e=BXku96

Thank you.

What you’re experiencing is probably something similar to this Pipeline extension 3.8 not finding nuget files

I was able to get the assembly not found errors to go away from the core project by

  1. Adding <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> to the csproj
  2. Manually copying over all the assemblies in the framework “Microsoft.Windows.Desktop.App.WPF” you can the path on your computer by clicking the node in Visual studio.

All the assemblies has to be in the SAME DIRECTORY as the .mgcb file.

This got reported to the bug tracket but unfortunately closed as “by design”. You may want to report this problem there in case it makes them reconsider https://github.com/MonoGame/MonoGame/issues/7368

Thank you for your answer, persn.

I set and moved the file based on the contents of the answer, but as a result, the following error was displayed and the build could not be done.
The content of the error has changed from the previous time.

System.BadImageFormatException: Could not load file or assembly ‘PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context. (0x80131058)
File name: ‘PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ —> System.BadImageFormatException: Could not load file or assembly ‘PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context. (0x80131058)
File name: ‘PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ —> System.BadImageFormatException: Cannot load a reference assembly for execution.
at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at System.Reflection.Assembly.LoadFromResolveHandler(Object sender, ResolveEventArgs args)
at System.Runtime.Loader.AssemblyLoadContext.InvokeResolveEvent(ResolveEventHandler eventHandler, RuntimeAssembly assembly, String name)
at System.Runtime.Loader.AssemblyLoadContext.OnAssemblyResolve(RuntimeAssembly assembly, String assemblyFullName)

at WpfFontPipelineNetCore.Processor1.Process(FontDescription input, ContentProcessorContext context)
at Microsoft.Xna.Framework.Content.Pipeline.ContentProcessor`2.Microsoft.Xna.Framework.Content.Pipeline.IContentProcessor.Process(Object input, ContentProcessorContext context) in C:\BuildAgents\MonoGameWin1\work\f7381a85a626990\MonoGame.Framework.Content.Pipeline\ContentProcessor.cs:line 60
at MonoGame.Framework.Content.Pipeline.Builder.PipelineManager.ProcessContent(PipelineBuildEvent pipelineEvent) in C:\BuildAgents\MonoGameWin1\work\f7381a85a626990\MonoGame.Framework.Content.Pipeline\Builder\PipelineManager.cs:line 717

The procedure was as follows.

  1. Add CopyLocalLockFileAssemblies

<Project Sdk=“Microsoft.NET.Sdk.WindowsDesktop”>
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<Platforms>AnyCPU;x64;x86</Platforms>
</PropertyGroup>
::: :

  1. The following files are output, so copy them all to the .mgcb file folder.

2020-10-13 10_27_46-Cortana

  1. Copy all dlls from C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\3.1.0\ref\netcoreapp3.1 to the .mgcb file folder

2020-10-13 10_28_39-アクション センター

  1. Result

2020-10-13 10_29_24-Cortana

I got a BadImageFormatException, so I tried building on x64, but the result was the same.
x86 couldn’t be read by MGCB in the first place.

I tried again and it worked.

Try again yourself. Get rid of this line <Platforms>AnyCPU;x64;x86</Platforms>, delete the bin folder, and copy things over. Before you hit build in the content pipeline editor make sure that the .mgbc references the correct path to the assembly, and the font references the correct importert

Thank you for your answer, persn.

I tried changing the working folder, but I still get the error.

I tried to make a video of the operation procedure, so if you have any suggestions, please.

Video on OneDvie

https://1drv.ms/v/s!Ap-DYzVqMCtRsuNJ5FirCKM9ZHRI6A?e=ez8NCs

I don’t see anything obvious. Which version of the dotnet CLI is running? What is the output when you run the command dotnet --version

The content builder in v3.8 is a net.core 3.1 app. It doesn’t support WPF, WinForms, Windows.Drawing and other Windows specific libraries. The previous version was .net Framework 4.5.

“dotnet --version” is “3.1.402”.

2020-10-13 16_11_29-コマンド プロンプト

I don’t understand your sentence. You mention the content builder being a net .core 3.1 app, but all of the frameworks you listed are net .core 3.1 compatible, only the first 2 are windows specific, and ASFAIK the System.Drawing API in C# which used to reference Windows.Drawing have a cross platform replacement in net .core https://www.nuget.org/packages/System.Drawing.Common/

In order to isolate whether it is a DLL problem or an OS or Framework problem, I uploaded a set such as “DLL” and “mgcb” that cause an error.
Please let me know if there is any difference from the environment that operates normally.

https://1drv.ms/u/s!Ap-DYzVqMCtRsuNKZsIUnmZpwI2qZg?e=aWv3Je

I didn’t solve the DLL reference problem, but decided to take a different approach, albeit temporarily.

Since only the Pipeline DLL can be referenced from MGCB, I decided to create the processing related to WPF in another EXE and create the texture via the file.

Pipeline DLL

↓ Input Data File (Font Description, Custom Input)

WPF Process EXE (Rendering Font)

↓ Pixel Data File

Pipeline DLL (Create Texture)

xnb file