dotnet / ILMerge

ILMerge is a static linker for .NET Assemblies.
MIT License
1.22k stars 168 forks source link

ILMerge fails to properly merge WpfMath #70

Closed davidagross closed 4 years ago

davidagross commented 4 years ago

Repository https://github.com/davidagross/ILMerge-vs-WpfMath provides a MWE of this error.

Basically, when WpfMath.dll isn't next to the merged, standalone executable, the render fails:

System.TypeInitializationException: The type initializer for 'WpfMath.DefaultTexFont' threw an exception. ---> System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode, IntPtr errorInfo)
   at MS.Internal.Text.TextInterface.Native.Util.ConvertHresultToException(Int32 hr)
   at MS.Internal.Text.TextInterface.Factory.CreateFontFace(Uri filePathUri, UInt32 faceIndex, FontSimulations fontSimulationFlags)
   at System.Windows.Media.GlyphTypeface.Initialize(Uri typefaceSource, StyleSimulations styleSimulations)
   at WpfMath.DefaultTexFontParser.CreateFont(String name)
   at WpfMath.DefaultTexFontParser.GetFontDescriptions()
   at WpfMath.DefaultTexFont..cctor()
   --- End of inner exception stack trace ---
   at WpfMath.DefaultTexFont..ctor(Double size)
   at WpfMath.TexFormula.GetRenderer(TexStyle style, Double scale, String systemTextFontName)
   at WpfMath.Extensions.RenderToPng(TexFormula texForm, Double scale, Double x, Double y, String systemTextFontName)
   at ILMerge_vs_WpfMath.Renderer.DisplayEquation()
   at ILMerge_vs_WpfMath.Renderer..ctor()

indicating that the merge was not successfull. This is also tracked in https://github.com/ForNeVeR/wpf-math/issues/202.

mike-barnett commented 4 years ago

Sorry for not answering sooner! WPF assemblies often fail to merge correctly because WPF encodes assembly identities in strings and then at runtime decodes those strings and uses reflection to access the assembly. ILMerge is unable to update those strings to refer to the new, merged, assembly and then you see this kind of error at runtime. I'm sorry but ILMerge will not work for you in this scenario. There are other ways to get the same effect that you should use.

ForNeVeR commented 4 years ago

What's the general concensus on cases like this one? Should WPF libraries be more flexible in this aspect (and not hardcode their identities)?

mike-barnett commented 4 years ago

Well, I don't think it is possible to have WPF change that behavior: it's been that way for years.

ForNeVeR commented 4 years ago

Look: I am a maintainer of this particular library in question, and we could update the behavior at least for our library. If the user doesn't try to merge the actual WPF core libraries (and why would they?), then we could fix the resource paths in the library itself. Should we? Is it the accepted practice to create ILMerge-friendly code?

mike-barnett commented 4 years ago

If you can fix the library to not contain those patterns, then ILMerge should work. You can use ildasm (or Reflector or any other disassembler) to look at the constructor from the stack trace and you should see the string that contains the assembly name. I just don't know if you'll be able to avoid the compiler generating that. If you post that snippet of IL then maybe I can advise about what to do about it.

ForNeVeR commented 4 years ago

In this particular case, it isn't the compiler, but we just use the constant in the C# code. Thanks for your advice. I'll fix my library to be more flexible, then.