Summary
MFC’s CWinApp::InitInstance is invoked only when the module that defines the CWinApp object is loaded as an executable or as a DLL that is explicitly initialized by MFC. When the CWinApp lives in a static library (core.lib) that is linked into another DLL (api.dll), the MFC runtime does not automatically create the application object, so InitInstance never runs.
Root Cause
- The global
CWinAppobject is compiled into a static library, not into a DLL that MFC can hook. api.dlldoes not contain any MFC initialization code (noDllMainthat callsAFX_MANAGE_STATEorAfxWinInit), so the MFC framework never sees the object.- When an executable links directly against
core.lib, the linker places theCWinAppobject in the final image and the CRT startup code invokesCWinApp::InitInstance. This path is missing for the DLL case.
Why This Happens in Real Systems
- Static libraries hide symbols from the DLL loader; the loader only knows about symbols exported from the DLL itself.
- MFC’s module state mechanism (
AFX_MODULE_STATE) is per‑DLL. If a DLL does not callAfxInitExtensionModule, the framework assumes it has no MFC objects. - Many teams split code into a “core” static lib and a thin “API” DLL for versioning, inadvertently breaking MFC’s initialization contract.
Real-World Impact
- Application‑level MFC features (dialogs, document/view, message pumps) never start, leading to crashes or silent failures.
- Resource loading (strings, dialogs, icons) fails because the module state is not set.
- Third‑party plugins that expect a valid
CWinAppinstance will misbehave, causing stability problems in larger products.
Example or Code (if necessary and relevant)
// core.cpp (compiled into core.lib)
class CCoreApp : public CWinApp
{
public:
virtual BOOL InitInstance()
{
// initialization logic
return TRUE;
}
};
CCoreApp theCoreApp; // global object
// api.cpp (compiled into api.dll)
#include "afxwin.h"
#include "core.h"
extern CCoreApp theCoreApp; // reference the object from core.lib
BOOL API_APIENTRY DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
// Ensure MFC is initialized for this DLL
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Optional: force construction of the global object
(void)theCoreApp;
}
return TRUE;
}
How Senior Engineers Fix It
- Convert
core.libto a proper MFC DLL and expose theCWinAppobject viaAFX_EXTENSION_MODULE. - Add an explicit initialization routine in
api.dllthat callsAfxWinInitorAfxDllGetClassObjectto trigger MFC startup. - Force the linker to include the object file containing the
CWinApp(e.g., using/INCLUDE:theCoreApplinker option) so the CRT sees it. - Call
AfxInitExtensionModuleinDllMainand thenAfxGetStaticModuleState()before any MFC API use. - Document the requirement in the build system: any DLL that pulls in an MFC
CWinAppmust perform MFC initialization.
Why Juniors Miss It
- They assume global objects are always constructed regardless of how they are linked, ignoring the CRT startup differences between EXE and DLL.
- They are unfamiliar with MFC’s module state model, so they don’t realize that a DLL needs its own
AfxInitExtensionModulecall. - They often rely on “it worked before” without tracing the linking chain, missing the fact that moving code to a static library broke the implicit initialization step.