Building an inproc ATL COM object as x86 and x64

I’m currently wrapping a server’s client side API in an ATL COM object for a client. The COM object will be used to communicate with the server from managed code or VB or other COM compatible systems. It’s a fairly straight forward process as the original ‘C’ DLL interface client API was built with this kind of thing in mind and I’ve done enough C++ objects wrapping a ‘C’ API conversions in the past to make the whole process relatively painless and straight forward.

However, there’s always something…

I’m running the code through my automated build process before release and I find that the x64 builds of the COM object are failing to link with a missing XXX_ProxyFileInfo error (error LNK2001: unresolved external symbol MYTypeLib_ProxyFileInfo). A clean rebuild works fine and building again after a successful build works fine. Switching from a successful x86 build to an x64 build fails as does switching from a successful x64 build to building in x86 mode.

The problem is that the MIDL compiler generates different code for x86 marshalling and x64 marshalling and since this code is compiler specific it doesn’t get built if you compile the resulting proxy file MyTypeLib_p.c for the wrong architecture. Since the _p.c file is generated by the MIDL compiler based on the idl file the dependency checking for subsequent builds doesn’t find a need to rebuild the file as it’s up to date. When you switch architectures the file is still considered up to date but doesn’t build any code as the marshalling code is for the wrong architecture.

This took a while to track down…

Anyway, the fix is either to have the _p.c file generated in the output directory (which is correctly differentiated by architecture) or to append the architecture to the file name. I decided on the latter as it’s easier to work with in the dlldatax.c file that compiles the _p.c file. Once the MIDL rule is changed to build a file that looks like MyTypeLib_p-x86.c and MyTypeLib_p-x64.c the dlldatax.c can be made conditional on the _WIN64 define and can pull in the correct marshalling code for the architecture that’s being compiled. Note that the other files that the MIDL step generates are not architecture specific.

Update: Unfortunately it seems that the dependency check that the MIDL tool uses doesn’t check all of the output files that it’s set to produce. So now I’m in the (slightly better) position of the build failing sometimes because the architecture specific proxy code file doesn’t exist… Looks like I may have to write a custom build rule after all.