ResGen.exe error: An attempt was made to load a program with an incorrect format

ResGen.exe error: An attempt was made to load a program with an incorrect format

  • Comments 65

UPDATE: This issue is fixed in .NET 4.5. As always, feedback is welcome! Please leave your comments in this blog post and report any bugs on Microsoft Connect.

 

Recently, we’ve seen a number of people reporting problems with resource generation in Visual Studio 2010, particularly when they target .NET Framework 3.5 on 64-bit machines.  In this blog post, I will highlight one of the most common errors; when and where it occurs, and how to work around it.  In a later post, we’ll take a look at some other somewhat less common errors, and some background on the differences between the GenerateResource of VS 2008 and that of VS 2010. 

Sample error:

ResourceForm.resx(1436,5): error RG0000: Could not load file or assembly 'file:///C:/Users/sjoiner/Desktop/TestForm/ResTest/bin/x86/Debug/Foo.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format. Line 1436, position 5.

Circumstances under which this error is found:

All of the below conditions must be met:

  • 64-bit operating system
  • Project that contains resource files (Project A)
  • Assembly that is referenced by project A (Assembly B). This can be either a third-party assembly, or another project in your solution that is referenced via a project-to-project reference
  • One or more of Project A’s resources files use types from Assembly B.  For example, if Project A is a form and Assembly B contains controls used by that form. 
  • One of the ‘X’-marked combinations of configuration below must be true.  Note: Building using the Visual Studio IDE is equivalent to building using 32-bit MSBuild.exe.
    VS 2008 VS 2010
Targeting 3.5 or below
VS2010
Targeting 4.0
MSBuild.exe Architecture

32-bit

64-bit

32-bit

64-bit

32-bit

64-bit

Assembly B’s Architecture 32-bit   X X X   X
64-bit X       X  
AnyCPU            

Workaround 1:

Make the assembly you’re referencing (Assembly B) AnyCPU rather than being architecture-specific.

Pros: Easy, means that Assembly B can be loaded by any referencing assembly.

Cons: Not feasible if you made the assembly you’re referencing architecture-specific for a specific reason, or if you’re referencing a 3rd party assembly that is architecture-specific.

Notes on Workarounds 2 and 3:

Workarounds 2 and 3 apply specifically to the scenario where a project targeting .NET 3.5 has a .resx file that references a 32-bit assembly. There is currently no workaround for targeting 4.0 and trying to reference a 32-bit assembly from 64-bit MSBuild or vice versa – aside from changing to use the MSBuild.exe of the architecture you’re targeting.

Please be aware that by forcing ResGen.exe to execute as 32-bit, you are essentially introducing the opposite problem:  ResGen.exe will now error if you try to load 64-bit architecture-specific reference assemblies in it. 

Workaround 2:

Make ResGen.exe 32-bit by:

1. Cd “%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.0A\Bin”

2. Corflags /32Bit+ /Force ResGen.exe

However, since our current build process has a heuristic that assumes that ResGen.exe is MSIL, just doing the above step will cause a different error (“The specified task executable "ResGen.exe" could not be run. The handle is invalid”) unless you inform GenerateResource that ResGen.exe is now 32-bit via setting the property “ResGenToolArchitecture” to “Managed32Bit”. This can be accomplished by doing one of the following:

1. Adding <ResGenToolArchitecture>Managed32Bit</ResGenToolArchitecture> to a PropertyGroup in the project file of any project that generates resources targeting .NET 3.5 – since the corflags trick affects the bitness of ResGen.exe on a system-wide level, the property must be set for all affected projects as well.

2. OR If running MSBuild.exe directly, passing it using the global property switch: ‘/p:ResGenToolArchitecture=Managed32Bit’

3. OR Setting it as an environment variable in the command window that MSBuild.exe is run from or the VS 2010 IDE is opened from: ‘set RESGENTOOLARCHITECTURE=Managed32Bit’

Pros: Doesn’t require changing the architecture of the referenced assembly

Cons: More complicated; requires baking the workaround either into the project file, or into your build system as a whole.

Workaround 3:

Force the CLR to load all MSIL applications as 32-bit by:

1. Cd “%windir%\Microsoft.NET\Framework64\v2.0.50727”

2. Ldr64.exe setwow

Then, since this also is a way to force ResGen.exe to execute as though it’s a 32-bit process, you must also go through the second part of Workaround 2 (setting ResGenToolArchitecture=Managed32Bit).

Pros: Doesn’t require changing the architecture of the referenced assembly

Cons: Affects how the CLR works for the entire machine. Also the same cons as Workaround 2.

Explanation:

This problem occurs whenever an attempt is made to load a referenced assembly that is of an architecture that is incompatible with the architecture of the currently running process. Since framework reference assemblies are all AnyCPU – so they can be loaded by any architecture with no problem – this typically happens when you have two bit-specific user projects that reference each other, for example one with a form and one that implements a control, and the referencing project contains a resx that uses types defined in the referenced project.  Obviously, the same problem also occurs if your projects reference 3rd-party assemblies that are architecture-specific. 

This problem existed in VS 2008 as well, but it was a lot less noticeable because, since we generated resources in-proc in a typically 32-bit MSBuild.exe (64-bit MSBuild.exe existed, but was not frequently used), in order for this problem to be noticed, the user would have had to have referenced a specifically 64-bit assembly; and even then, a simple workaround would have been to just use 64-bit MSBuild.

However, in MSBuild 4.0, due to the fact that we use ResGen.exe when targeting .NET 3.5 or below, and due to the fact that the ResGen.exe associated with .NET 3.5 is an MSIL application, this error now occurs for anyone who targets .NET 3.5 on a 64-bit machine and has a resx that tries to load types from a specifically 32-bit assembly.

The first workaround removes the bitness mismatch by changing the referenced assembly to be loadable by any application. The second and third workarounds remove the bitness mismatch by making ResGen.exe 32-bit, so that it can successfully load 32-bit assemblies.

I hope this post has provided you with an improved understanding of this error and with the tools you need to work around it. 

Sara Joiner

Software Development Engineer, MSBuild

Leave a Comment
  • Please add 3 and 2 and type the answer here:
  • Post
  • now i have this bug. a typed dataset is causing the resx to throw compile error. nothing works. "could not find a type for a name". That typed dataset is in the assembly!

  • and i'm not using 64 bit OS / cpu target type etc. Plain winforms with typed dataset. suddenly appeared out of the blue when i modified a typed dataset used by a user control.

  • Hello Microsoft,

    Still no update/hotfix for this error ?

  • Are you joking? I can not add an imageList control to form after installation win to my developer's PC. Shame on you!!!!!

  • Posted by Ed Hartley1 on 9/2/2010 at 4:56 PM

    After editing the form search the resx for "j00L" on the first line of the imagelists block and change to "j0yL".

    You have to do it everytime you make a change though.

  • Been a while since this was posted, but solved a world of pain for me on a project I inherited. Thanks!

  • The manual workaround of changing the resx file after each time you make a change is not something I have the time for. Considering I deal with high priority projects all the time that have very strict time deliverables and any late delivery results in huge costs to the company. I don't think Microsoft is taking this seriously enough. Not releasing a hot fix for those that have this problem but instead forcing people to upgrade to VS2011 which will install .net 4.5 which overwrites the old CLR isn't acceptable.

  • This is just plain silly. Go fix!

  • I read the first paragraph and once again with Microsoft we have to play with workarounds.

    Could you once in your life solve just a single bug ?

    How many versions of Studio will you have to release before we have something stable and safe ?

    I can write an entire book with bugs in Studio (or other Microsoft products), and an entire library with annoyances.

    Go back to sleep or dig your own grave.

    This is the wrong attitude and it will destroy you.

  • I have just run into this problem.  Drag a dataset onto a form.  Try to compile - get the error.  Noticed that after a dataset is dragged onto the form, the current project is added to the list of References.  Delete the reference to itself and the project compiles.

  • I agree with the previous posters.  A fix for this issue NEEDS to be back ported to VS2010.  It is simply unacceptable to require everyone using VS2010 to pay for an upgrade to 2012 just to get a bug fixed that has been in VS2010 since the begining.

  • It is astonishing how much time our team regularly wastes on that bug :(

  • This is just nightmare. Again I have used now 4 hours to workaround this but no help. Because of our customer platforms 4.5 is out of option. Microsoft just fix that compiler bug and stop throwing that crap to your customer faces.

    This bug is most customer time consuming bug in vs.net on whole vs.net history so why it is so hard to fix it?

  • In the update you wrote "This issue is fixed in .NET 4.5". Does that mean my target platform have to be .NET 4.5 or does it mean my build platform (the machine on which I am building, local or build agent) must have .NET 4.5?

  • Workaround 4:

    Create small program and add to pre-build event.

    1. In Visual Studio create new project - Console Application

    2. Copy this source code:

    Imports System.IO

    Module modMain

     Private Const fixSrc As String = "wgVmVyc2lvbj00"

     Private Const fixDest As String = "wgVmVyc2lvbj0y"

     Sub Main()

       If My.Application.CommandLineArgs.Count > 0 Then StartFix(My.Application.CommandLineArgs(0))

     End Sub

     Private Sub StartFix(srcPath As String)

       Dim sr As StreamReader

       Dim sw As StreamWriter

       Dim fName As String, buf As String

       Dim files() As String

       files = Directory.GetFiles(srcPath, "*.resx", SearchOption.TopDirectoryOnly)

       For Each fName In files

         sr = New StreamReader(fName)

         buf = sr.ReadToEnd()

         sr.Close()

         If buf.IndexOf(fixSrc) <> -1 Then

           buf = buf.Replace(fixSrc, fixDest)

           Try

             If File.Exists(fName + ".bak") Then File.Delete(fName + ".bak")

           Catch ex As Exception

           End Try

           Try

             File.Move(fName, fName + ".bak")

           Catch ex As Exception

             Return

           End Try

           sw = New StreamWriter(fName)

           sw.Write(buf)

           sw.Close()

         End If

       Next

     End Sub

    End Module

    3. SaveAs ResGenFix64, build and copy ResGenFix64.exe to your project source directory.

    4. In your project add to Properties->Compile->Build Events...->Pre-build event command line:

      $(ProjectDir)ResGenFix64.exe $(ProjectDir)

    5. Check the Tools->Options->Environment->Documents->Auto-load changes, if saved

Page 4 of 5 (65 items) 12345