I am trying to convert one of my older C++ programs from ANSI to Unicode. I am using Visual Studio 2022. After I did all changes in the source code, my program compiles without errors but it does not link, saying that WinMain is expected, but I've got wWinMain.
LIBCMTD.lib(exe_winmain.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
My declaration:
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR cmdline, int nCmdShow)
So my question is: How does it decide whether to call WinMain or wWinMain? It seems the source code is correct, just some project settings need to be changed.
Maybe the root of my issue is somewhere else, so I try to add more information:
The program consists of a few static libraries (.lib) + main exe project , all of them C++ projects in the same .sln solution. So I set "Character Set: Use Unicode Character Set" in the project configuration of all of my projects in this solution.
After I converted the source code to use wchar_t or TCHAR and all related functions for Unicode, all lib projects compile without errors. But some .cpp files the main project do not compile and the compilation errors show that TCHAR = char. Since the TCHAR definition is based on whether _UNICODE is defined, I manually added preprocessor definition _UNICODE and also UNICODE. Now everything compiles without errors. But it does not link - it wants WinMain, but I've got wWinMain in my code.
So again, my question is: How does it decide whether to call WinMain or wWinMain?
MSDN says:
How does the compiler know to invoke wWinMain instead of the standard main function? What actually happens is that the Microsoft C runtime library (CRT) provides an implementation of main that calls either WinMain or wWinMain.
This does not really answer the question. How the compiler decides which one of them to call? What more do I need to set in the project configuration in addition to "Character Set: Use Unicode Character Set"?
At the end, I found out the problem is in the fact my wWinMain
is in a library. As I mentioned, I have a few static libraries (.lib) in the solution. So I made a simple test application which proves it.
My test program looks like this:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
int APIENTRY _tWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPTSTR, _In_ int) { }
If this code is in the main application (.exe), it can be compiled in either MBCS or Unicode without any issue. The _tWinMain
is translated to WinMain
or wWinMain
respectively and it is linked successfully.
But if I put the same code to a static library (.lib), the linker does not work as expected. MBCS works, it means it can find the WinMain
and call it. And it works. But Unicode case does not work, the linker does not find my wWinMain
, and then it outputs that confusing error message about missing WinMain
.
Solution:
Although it seems as a bug or a design flaw of the Microsoft's linker, there is a simple workaround: I simply renamed my method in the library to xWinMain
and added a proxy method called _tWinMain
to the main project (.exe) which calls my xWinMain
. And everything nicely works both in MBCS and Unicode.
(Tested with C++ toolset from Visual Studio 2015 and 2022.)