Search code examples
c#winformsmsbuildilmergesatellite-assembly

Trying to build a WinForms application with all satellite resource assemblies included


I'm using VS 2013 to build a C# WinForms application that ships as a single EXE file. So far, this was no problem using ilmerge as a post-build step in order to include all needed DLLs. Even ActiveX components can be embedded without problems.

But now, I am going to internationalize the application which results in localized satellite resource assemblies being generated. My current solution is as follows:

  1. Build generates DLL under (e.g.) .....\en\MyApp.resources.dll
  2. Post-build action copies this DLL into ..\..\Resources\i18n\en

The next time Build is executed, it embeds the resource under resource folder i18n\en as Embedded Resource into the target. In my application I use my own ResolveEventHandler for the AppDomain.CurrentDomain.AssemblyResolve event, reading the requested DLL from the application's internal resources.

This works fine, BUT: After committing changes that involve the localized DLL, I have to build the solution twice in order to get the new DLL into the output EXE.

Using ilmerge for including the satellite assemblies was not successful because it unpacks the DLLs and puts the objects contained therein directly into the EXE file.

So, my question is whether I can modify the .csproj file in such a way that after generating the DLL I can copy it into the resource directory before the resources are packed into the output binary, instead of copying after the first build. That way only one build pass would be necessary and errors could be avoided.


Solution

  • I got it working now, but in a different way than I was looking for initially.

    Instead of embedding the DLL as an Embedded Resource using Visual Studio / MS Build, I made a tool ResourceEmbedder for embedding resources afterwards. It uses Mono.Cecil to accomplish this. So the mechanism is now:

    1. Build the target EXE file the standard VS way.
    2. Post-build: Use the ResourceEmbedder tool to embed all satellite assemblies.
    3. Post-build: Use ilmerge to embed all external DLLs.
    4. At runtime, hook into the AppDomain.CurrentDomain.AssemblyResolve event in order to supply the satellite assemblies when needed.