I just added a C++ Windows DLL project to a Visual Studio (2022) solution. The wizard put a DllMain in there. That jumped out at me; I didn’t remember my other DLLs having DllMain functions;
Searching my code, it turns out that none of my 9 DLLs have DllMain functions. Yet they all build and work fine. I checked the project settings for all of these projects:
- None of them have the linker
/NOENTRYoption set. - They all have
/SUBSYSTEM:WINDOWSset. - None of them have the linker
/NODEFAULTLIBoption set - They are certainly all DLLS.
So I commented out that DllMain in the new project I just added. It still built just fine.
My knowledge is clearly out of date. I thought a DllMain used to be required. I remember years ago getting linker errors in my DLLs when I failed to add a DllMain.
So my questions are:
- Why do my DLLs not require DllMain? Is there some build setting I did not check?
- Is there any downside to not having one?
(Note that these DLLS all export C++ classes. None of them are resource DLLs. All have been working fine for 6 years. Some of them use thread-local storage. Some of them have static variables inside of functions. I always thought that using things like these necessitated a DllMain)
>Solution :
The runtime library ("CRT" = C/C++ Runtime Library) provides the real DLL entry point _DllMainCRTStartup, that does things like initializing global variables before calling your DllMain. There’s documentation on MSDN that describes this:
Documentation of the linker /ENTRY option is also relevant:
There’s also a library-provided weak symbol for your DllMain, so the call from the real entrypoint to DllMain doesn’t fail at link time with an unresolved external. From the first document above:
By default, if you do not provide a
DllMainfunction, Visual Studio provides one for you and links it in so that_DllMainCRTStartupalways has something to call.
The things you mentioned like thread-local storage do require using the library-provided entrypoint; they’ll break if you use the /ENTRY option to link.exe to replace the library entrypoint with your own or /NOENTRY to disable it. None of them require anything to be done by the DllMain that the library entrypoint calls.