I had a user reach out to me over the weekend expressing concerns that he could not use the emailing functionality of our WindowSMART 2013 software. A couple releases back, we licensed Chilkat to harness the more powerful .NET emailing capability (including SSL support) as well as the awesome zip and FTP capabilities, which make it easy for users to submit debug logs and bug reports to us.

The user in question noted when he tried to do the mail send test, he'd get a .NET just-in-time error dialogue that indicated BadImageFormatException - could not load ChilkatDotNet4.dll or one of its dependencies because it's not a valid Win32 application (0x800700C1).

We have clearly ruled out the "incorrect format" problem. He is running the 64-bit version of our software on his 64-bit system. We have two different PCs in our lab running Windows 8 64-bit, and we are NOT experiencing this issue.

Our software requires the Microsoft .NET Framework 4 Full to be installed, and users cannot install it without the Framework. We do not, however, require that they have the Microsoft Visual C++ 2010 runtime installed. We build our installer package with the VC++ 2010 merge modules, in their 32- and 64-bit variants, as appropriate, so if the user has the VC++ runtime installed, our installer skips it. But if the user doesn't have the VC++ runtime installed, we include it. WindowSMART 2013 includes an unmanaged C++ DLL that we wrote for communicating with the disks via IOCTL calls, hence the need for the VC++ 2010 runtime, whether the user installs it themselves or we include it via the merge modules.

I went back to my WXS files (we use WIX to build the installers) and double-checked our merge modules to be sure we're bundling 64-bit modules with the 64-bit installer. Confirmed--the correct modules are being included.

For the 64-bit build, we merge Microsoft_VC100_CRT_x64.msm and Microsoft_VC100_MFC_x64.msm. For the 32-bit build, we use the same filenames except x86 is substituted for x64.

The only possible cause for a "BadImageFormatException" (i.e. an "incorrect format" error) is if a 32-bit process tries to load a 64-bit DLL, or the reverse. This is the ONLY possible reason.

It all boils down to whether a process is running in a 32-bit address space or a 64-bit address space. (When managed .NET code runs, which is identical to other interpreted languages such as Java, the byte code is translated into either 32-bit or 64-bit instructions to be run in either a 32-bit or 64-bit address space. With .NET, you may target your app to "Any CPU" which means this decision happens at runtime. In other words, your program will run as a 32-bit process on 32-bit machines, and it will run as a 64-bit process on 64-bit machines.

What does it mean to "run as a 32-bit process" or "has a 32-bit address space"? It means that memory references (i.e. pointers) are 32-bits. If running in a 64-bit address space (i.e. in 64-bit mode) it means that memory references are 64-bits wide. A program in a compiled language must be compiled for either 32-bit or 64-bit. The amount of space required to hold a pointer would be either 4 bytes or 8 bytes, and this must be decided at compile time.

When a process loads a DLL (or a dynamic shared library) into its memory space, the DLL (or .so, or .dylib) must have been compiled such that the pointers are the correct size for the address space (32-bit or 64-bit). This is true regardless of operating system (Linux, MacOSX, Windows) and is true of whatever terminology you might call the DLL (.so, .dylib, etc.).

The Chilkat .NET assembly is a mixed-mode assembly, meaning that the inner core is written in C++ and compiles to native code. This is why there are two separate builds (32-bit and 64-bit). When a .NET program loads the Chilkat .NET assembly (i.e. DLL) into it's address space, it must load the one that matches, otherwise you'll get an "incorrect format" error. There is no other reason for "incorrect format".

See this Forum topic which explains several possible solutions to make it easy to avoid the "incorrect format" error:

I've encountered the BadImageFormatException in the past, although usually in its "an attempt was made to load a program with an incorrect format variant." And as you noted, the reason has always been trying to load 32-bit DLLs into a 64-bit app (or vice versa).

In the case I am describing here, this should NOT be the reason.

When we build WindowSMART 2013, we create both an x86 and an x64 build. We created our own C++ DLL, also in Win32 (x86) and x64 flavors. We use WiX to build the installers, and we have two folders which contain a number of reference DLLs. Most utility DLLs we use, which provide support for mobile notifications and such, reside in the ReferenceDll folder. We have a ReferenceDll64 folder, which contains two DLLs--one being our x64 flavor of the C++ utility DLL, and the other being the x64 version of the ChilkatDotNet4.dll. Our installers also bake in either the 32- or 64-bit Microsoft VC++ 2010 merge modules.

We have the x64 version of our software installed on all of our 64-bit machines here, and the x86 version installed on all of our 32-bit machines. We have Windows 8, Windows 7, Windows Vista and XP, as well as Server 2008 R2 and Server 2012, and we cover both 32- and 64-bits of the clients and 64-bit for the servers.

Our software interacts with Chilkat perfectly fine on ALL of these machines, and we use the exact same installer that is published on our website. We do not get BadImageFormatException on any of our PCs here.

Furthermore, if we had in fact put out a bad build with a mix of x86 and x64 DLLs, then I should have HUNDREDS (if not thousands) of end users complaining that the software isn't working correctly.

Perhaps the user installed ANOTHER 32-bit application that comes bundled with the ChilkatDotNet4.dll. In such a case, the machine would have two versions of that dll (32-bit & 64-bit). Can this create a conflict?

I'm not sure. I do NOT install ChilkatDotNet4.dll in the GAC; all of my DLLs reside in the application's Program Files directory.

If a user were to install the 32-bit version of Chilkat into the GAC, it would go into the 32-bit GAC; by the same token if they installed the 64-bit version into the GAC, it would go into the 64-bit GAC. Only "any CPU" assemblies go into the "any CPU" (MSIL) GAC.

That said, this shouldn't create a conflict because my application on a 64-bit machine should never try to pull an assembly from the 32-bit (x86) GAC. Nevertheless I will test this scenario.