In previous versions of Visual Studio the bundled MFC source files could be compiled into a static library or a DLL. But since Visual Studio 2008 the necessary files to build MFC are not supplied anymore. In this article I show you how you can compile the MFC sources with Visual Studio 2022. The latest changes support ARM64 and Managed Winforms controls (thanks to the sponsoring by the kind software consultant from the Bahamas).
With the latest Visual C++ versions (since 2008) it is not possible anymore to compile the bundled MFC sources. The necessary files, ie makefiles like atlmfc.mak and a DEF file are not provided anymore
In a LOB software project I needed a x86 MFC DLL without the DAO database classes. With statically linked MFC, I provided my own versions of the DAO classes (which internally use MySQL) by overriding the dao*.obj files, but MFC object files cannot be overridden when using the DLL form of MFC.
So I took the road to build my own MFC vcxproj files.
The github project https://github.com/fobrs/MFC has all the necessary files to build the MFC sources as a DLL.
The first hurdle was the missing DEF file. The MFC DLL exports its symbols via a provided Module Definition File or DEF file. The linker uses this DEF file to create the LIB file for the DLL. I couldn't use the old VC++ 2005 DEF file because the MFC feature pack added a lot of new functions.
After some internet search I discovered the tool: dumpexts.exe. I found the source code of it and modified it a little so it could create a DEF file for all the objs created by the compiler.
The tool is run as a pre-link Build Event for the MFCDLL project. Because Visual Studio has no macro with a list of all obj files, a DOS command enumerates all obj files in the Intermediate directory before calling dumpexts.exe. Be sure to first clean the MFCDLL project so that no old obj files are hiding in it.
When building the DLL the first time, be also sure Link Time Code Generation (LTCG) is not used. The object files the compiler generates when using LTCG cannot be read by dumpexts.exe. Luckilly when we once have generated a DEF file it can be used in a future LTCG build.
When you clone the github project, and run the Solution with Visual Studio 2019, a default wizard created MFC application is compiled and run but it uses the private MFC DLL!
To overcome copyright issues, the MFC source files are not included but read during compilation from the $(VCToolsInstallDir) folder. So no original MFC source files are included in the Solution except for one file: ctlpset.cpp. The original file gave a compiler error, so a fixed version is included.
1>------ Build started: Project: MFCDLL, Configuration: Release Win32 ------
1>ctlpset.cpp
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_memcpy_s.h(50): error C4789: buffer 'var' of size 24 bytes will be overrun; 24 bytes will be written starting at offset 8
1>Done building project "MFCDLL.vcxproj" -- FAILED.
Apparently there are still bugs present in MFC after all those 28 years!
The current Character Set in the project configuration is set to UNICODE. If you use Multi Byte Character Set then the file afxtaskdialog.cpp is excluded from the built (unload and edit the project file to see this).
In the original mfcdll.mak file the source file dllmodul.cpp is compiled twice with different flags. Therefore this file is copied to dllmodulX.cpp in the MFCstatic project. This project compiles a LIB file which needs to be linked to the exe which is using the MFC DLL.
The MFCres project is a resource DLL which is a localization for German. Alltough it's use is not very well tested in this project.
One last point, which I don't understand. I needed to supply the /ENTRY point to all builds except the Release|Win32 build of the main application linker settings. It is set to wWinMainCRTStartup for UNICODE builds.
For a successfull compilation for ARM64 the file dispimpl_supporting.h was reconstructed. armasm.exe is used on objcall_.s to create objcall_.obj This resolves the unknown symbols:
UNSUPPORTEDPLAT_PARAMS (_ARM64_PARAMS)
UnsupportedplatParamsReset
UnsupportedplatParamsAddFloat
UnsupportedplatParamsAddDouble
To test these functions an Active X Control is added (Circ) to test passing floats and doubles on ARM64. Open the Aboutbox and click 'Circle Active X control', then click outside the circle. Reg free COM is used to load the active X control when running the app. on ARM64 a MessageBox is shown if the float and double tests passes. The x86 version of circ.dll file has to be registered in an admin console with regsvr32 circ.dll before Visual Studio shows the control.
Before building for ARM64 please build first for x64 (Debug and Release). The x64 dumpexts.exe is used in the ARM64 build.
The new MFCMLIB project is added as a reference to the MFCApplication. The CAboutBox class is put in its own cpp file which is compiled with /clr. A Winforms Button control is placed onto the Aboutbox.