在成功运行的MFC程序添加UNICODE支持时,编译时出现了链接错误:
>msvcrtd.lib(crtexew.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___tmainCRTStartup 中被引用
1>..\Demo.exe : fatal error LNK1120: 1 个无法解析的外部命令
首先介绍下mainCRTStartup,该函数为C运行时库程序入口函数
以下为MSDN解释,这里就不做翻译了。
The /ENTRY option specifies an entry point function as the starting address for an .exe file or DLL.
The function must be defined with the __stdcall calling convention. The parameters and return value must be defined as documented in the Win32 API for WinMain (for an .exe file) or DllEntryPoint (for a DLL). It is recommended that you let the linker set the entry point so that the C run-time library is initialized correctly, and C++ constructors for static objects are executed.
By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.
Function name | Default for |
---|---|
mainCRTStartup (orwmainCRTStartup) | An application using /SUBSYSTEM:CONSOLE; calls main (or wmain) |
WinMainCRTStartup (orwWinMainCRTStartup) | An application using /SUBSYSTEM:WINDOWS; calls WinMain (or wWinMain), which must be defined with __stdcall |
_DllMainCRTStartup | A DLL; calls DllMain, which must be defined with __stdcall, if it exists |
If the /DLL or /SUBSYSTEM option is not specified, the linker selects a subsystem and entry point depending on whether main or WinMain is defined.
The functions main, WinMain, and DllMain are the three forms of the user-defined entry point.
When creating a managed image, the function specified with /ENTRY must have a signature of (LPVOID var1, DWORD var2, LPVOID var3).
For information on how to define your own DllMain entry point, see Run-Time Library Behavior .
To set this linker option in the Visual Studio development environment
-
Open the project's Property Pages dialog box. For details, see Setting Visual C++ Project Properties.
-
Click the Linker folder.
-
Click the Advanced property page.
-
Modify the Entry Point property.
从上面可以看出,console程序、GUI程序和DLL所使用的C运行时库入口函数均不同
以下为网上找到的解释,里面说明了UNICODE程序的mainCRTStartup入口函数 Where does your console program start? Did I hear you say main
? If you did, you said what I would have said before journeying into the inner Stationworkings of the C Runtime.
Windows isn't nice enough to provide your app with a ready-made argc
and argv
. All it does is call a void function()
specified in the EXE header. And by default, that function is called mainCRTStartup
. Here is a simple example:
extern "C" void __cdecl mainCRTStartup()
{
int argc = _init_args();
_init_atexit();
_initterm(__xc_a, __xc_z); // Call C++ constructors
int ret = main(argc, _argv, 0); // Don't handle environment strings
_doexit();
ExitProcess(ret);
}
We start by creating argc
and argv
, which we later pass to main
. But before we do that we have to take care of some things, like calling the constructors for static C++ objects.
The same thing happens in GUI programs, except the function is called WinMainCRTStartup
. And for DLLs, the true entry point is _DllMainCRTStartup
. Unicode programs look for wmainCRTStartup
and wWinMainCRTStartup
respectively. DllMain
appears to stay the same.
这里,我们就知道上述错误的原因了,是选错了入口函数,对于我所写的UNICODE GUI程序应该使用wWinMainCRTStartup入口函数。上述MSDN中有提到如何更改入口函数,更改如下
重新编译,成功通过