APIENTRY _tWinMain and WINAPI WinMain difference
_tWinMain
is just a #define
shortcut in tchar.h to the appropriate version of WinMain
.
If _UNICODE
is defined, then _tWinMain
expands to wWinMain
. Otherwise, _tWinMain
is the same as WinMain
.
The relevant macro looks something like this (there's actually a lot of other code interspersed):
#ifdef _UNICODE
#define _tWinMain wWinMain
#else
#define _tWinMain WinMain
#endif
WINMAIN and main() in C++ (Extended)
About the functions.
The C and C++ standards require any program (for a “hosted” C or C++ implementation) to have a function called main
, which serves as the program's startup function. The main
function is called after zero-initialization of non-local static variables, and possibly but not necessarily (!, C++11 §3.6.2/4) this call happens after dynamic initialization of such variables. It can have one of the following signatures:
int main()
int main( int argc, char* argv[] )
plus possible implementation-defined signatures (C++11 §3.6.1/2) except that the result type must be int
.
As the only such function in C++ main
has a default result value, namely 0. If main
returns then after the ordinary function return exit
is called with the main
result value as argument. The standard defines three values that guaranteed can be used: 0 (indicates success), EXIT_SUCCESS
(also indicates success, and is typically defined as 0), and EXIT_FAILURE
(indicates failure), where the two named constants are defined by the <stdlib.h>
header which also declares the exit
function.
The main
arguments are intended to represent the command line arguments for the command used to start the process. argc
(argument count) is the number of items in the argv
(argument values) array. In addition to those items argv[argc]
is guaranteed to be 0. If argc
> 0 – which is not guaranteed! – then argv[0]
is guaranteed to either be a pointer to an empty string, or a pointer to the “name used to invoke the program”. This name may include a path, and it may be the name of the executable.
Using the main
arguments to obtain the command line arguments works fine in *nix, because C and C++ originated with *nix. However, the de facto Windows standard for the encoding of the main
arguments is Windows ANSI, which does not support general Windows filenames (such as, for a Norwegian Windows installation, filenames with Greek or Cyrillic characters). Therefore Microsoft chose to extend the C and C++ languages with a Windows-specific startup function called wmain
, which has wide character based arguments encoded as UTF-16, which can represent any filename.
The wmain
function can have one of these signatures, corresponding to the standard signatures for main
:
int wmain()
int wmain( int argc, wchar_t* argv[] )
plus a few more that are not especially useful.
I.e., wmain
is a direct wide character based replacement for main
.
The WinMain
char
based function was introduced with Windows, in the early 1980's:
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
);
where CALLBACK
, HINSTANCE
and LPSTR
are defined by the <windows.h>
header (LPSTR
is just char*
).
Arguments:
the
hInstance
argument value is the base address of the memory image of the executable, it's primarily used to load resources from the executable, and it can alternatively be obtained from theGetModuleHandle
API function,the
hPrevInstance
argument is always 0,the
lpCmdLine
argument can alternatively be obtained from theGetCommandLine
API function, plus a bit of weird logic to skip the program name part of the command line, andthe
nCmdShow
argument value can alternatively be obtained from theGetStartupInfo
API function, but with modern Windows the first creation of a top level window does that automatically so it's not of any practical use.
Thus, the WinMain
function has the same drawbacks as standard main
, plus some (in particular the verbosity and being non-standard), and no advantages of its own, so it's really inexplicable except possibly as a vendor lock-in thing. However, with the Microsoft tool chain it makes the linker default to the GUI subsystem, which some see as an advantage. But with e.g. the GNU toolchain it does not have such an effect so this effect cannot be relied on.
The wWinMain
wchar_t
based function is a wide character variant of WinMain
, in the same way as wmain
is a wide character variant of standard main
:
int WINAPI wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PWSTR lpCmdLine,
int nCmdShow
);
where WINAPI
is the same as CALLBACK
, and PWSTR
is simply wchar_t*
.
There is no good reason to use any of the non-standard functions except the least known and least supported of them, namely wmain
, and then just for convenience: that this avoids using the GetCommandLine
and CommandLineToArgvW
API functions to pick up UTF-16 encoded arguments.
To avoid the Microsoft linker acting up (the GNU toolchain's linker doesn't), just set the LINK
environment variable to /entry:mainCRTStartup
, or specify that option directly. This is the Microsoft runtime library entry point function that, after some initialization, calls the standard main
function. The other startup functions have corresponding entry point functions named in the same systematic way.
Examples of using the standard main
function.
Common source code:
foo.cpp
#undef UNICODE
#define UNICODE
#include <windows.h>
int main()
{
MessageBox( 0, L"Press OK", L"Hi", MB_SETFOREGROUND );
}
In the examples below (first with the GNU toolchain and then with the Microsoft toolchain) this program is first built as a console subsystem program, and then as a GUI subsystem program. A console subsystem program, or in short just a console program, is one that requires a console window. This is the default subsystem for all Windows linkers I've used (admittedly not a great many), possibly for all Windows linkers period.
For a console program Windows creates a console window automatically if needed. Any Windows process, regardless of subsystem, can have an associated console window, and at most one. Also, the Windows command interpreter waits for a console program program to finish, so that the program's text presentation has finished.
Conversely, a GUI subsystem program is one that doesn't require a console window. The command interpreter does not wait for a GUI subsystem program, except in batch files. One way to avoid the completion wait, for both kinds of program, is to use the start
command. One way to present console window text from a GUI subsystem program is to redirect its standard output stream. Another way is to explicitly create a console window from the program's code.
The program's subsystem is encoded in the executable's header. It's not shown by Windows Explorer (except that in Windows 9x one could “quick view” an executable, which presented just about the same information as Microsoft's dumpbin
tool now does). There is no corresponding C++ concept.
main
with the GNU toolchain.
[D:\dev\test]
> g++ foo.cpp
[D:\dev\test]
> objdump -x a.exe | find /i "subsys"
MajorSubsystemVersion 4
MinorSubsystemVersion 0
Subsystem 00000003 (Windows CUI)
[544](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__
[612](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000003 __subsystem__
[636](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__
[D:\dev\test]
> g++ foo.cpp -mwindows
[D:\dev\test]
> objdump -x a.exe | find /i "subsys"
MajorSubsystemVersion 4
MinorSubsystemVersion 0
Subsystem 00000002 (Windows GUI)
[544](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__
[612](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000002 __subsystem__
[636](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__
[D:\dev\test]
> _
main
with Microsoft's toolchain:
[D:\dev\test]
> set LINK=/entry:mainCRTStartup
[D:\dev\test]
> cl foo.cpp user32.lib
foo.cpp
[D:\dev\test]
> dumpbin /headers foo.exe | find /i "subsys"
6.00 subsystem version
3 subsystem (Windows CUI)
[D:\dev\test]
> cl foo.cpp /link user32.lib /subsystem:windows
foo.cpp
[D:\dev\test]
> dumpbin /headers foo.exe | find /i "subsys"
6.00 subsystem version
2 subsystem (Windows GUI)
[D:\dev\test]
> _
Examples of using Microsoft’s wmain
function.
The following main code is common to both the GNU toolchain and Microsoft toolchain demonstrations:
bar.cpp
#undef UNICODE
#define UNICODE
#include <windows.h>
#include <string> // std::wstring
#include <sstream> // std::wostringstream
using namespace std;
int wmain( int argc, wchar_t* argv[] )
{
wostringstream text;
text << argc - 1 << L" command line arguments:\n";
for( int i = 1; i < argc; ++i )
{
text << "\n[" << argv[i] << "]";
}
MessageBox( 0, text.str().c_str(), argv[0], MB_SETFOREGROUND );
}
wmain
with the GNU toolchain.
The GNU toolchain doesn't support Microsoft's wmain
function:
[D:\dev\test]
> g++ bar.cpp
d:/bin/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.1/../../../libmingw32.a(main.o):main.c:(.text.startup+0xa3): undefined reference to `WinMain
@16'
collect2.exe: error: ld returned 1 exit status
[D:\dev\test]
> _
The link error message here, about WinMain
, is because the GNU toolchain does support that function (presumably because so much ancient code uses it), and searches for it as a last resort after failing to find a standard main
.
However, it's trivial to add a module with a standard main
that calls the wmain
:
wmain_support.cpp
extern int wmain( int, wchar_t** );
#undef UNICODE
#define UNICODE
#include <windows.h> // GetCommandLine, CommandLineToArgvW, LocalFree
#include <stdlib.h> // EXIT_FAILURE
int main()
{
struct Args
{
int n;
wchar_t** p;
~Args() { if( p != 0 ) { ::LocalFree( p ); } }
Args(): p( ::CommandLineToArgvW( ::GetCommandLine(), &n ) ) {}
};
Args args;
if( args.p == 0 )
{
return EXIT_FAILURE;
}
return wmain( args.n, args.p );
}
Now,
[D:\dev\test]
> g++ bar.cpp wmain_support.cpp
[D:\dev\test]
> objdump -x a.exe | find /i "subsystem"
MajorSubsystemVersion 4
MinorSubsystemVersion 0
Subsystem 00000003 (Windows CUI)
[13134](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__
[13576](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000003 __subsystem__
[13689](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__
[D:\dev\test]
> g++ bar.cpp wmain_support.cpp -mwindows
[D:\dev\test]
> objdump -x a.exe | find /i "subsystem"
MajorSubsystemVersion 4
MinorSubsystemVersion 0
Subsystem 00000002 (Windows GUI)
[13134](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__
[13576](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000002 __subsystem__
[13689](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__
[D:\dev\test]
> _
wmain
with Microsoft’s toolchain.
With Microsoft's toolchain the linker automatically infers the wmainCRTStartup
entry point if no entry point is specified and a wmain
function is present (it's unclear what happens if a standard main
is also present, I haven't checked that in recent years):
[D:\dev\test]
> set link=/entry:mainCRTStartup
[D:\dev\test]
> cl bar.cpp user32.lib
bar.cpp
LIBCMT.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup
bar.exe : fatal error LNK1120: 1 unresolved externals
[D:\dev\test]
> set link=
[D:\dev\test]
> cl bar.cpp user32.lib
bar.cpp
[D:\dev\test]
> _
With a non-standard startup function such as wmain
it is, however, probably best to specify the entry point explicitly, so as to be very clear about the intention:
[D:\dev\test]
> cl bar.cpp /link user32.lib /entry:wmainCRTStartup
bar.cpp
[D:\dev\test]
> dumpbin /headers bar.exe | find /i "subsystem"
6.00 subsystem version
3 subsystem (Windows CUI)
[D:\dev\test]
> cl bar.cpp /link user32.lib /entry:wmainCRTStartup /subsystem:windows
bar.cpp
[D:\dev\test]
> dumpbin /headers bar.exe | find /i "subsystem"
6.00 subsystem version
2 subsystem (Windows GUI)
[D:\dev\test]
> _
What is the correct way to define a UNICODE independent WinMain function?
In <tchar.h>
, the macro _tWinMain
expands to WinMain
or wWinMain
depending on project settings. This isn't enough, though; you need to declare the third argument (lpCmdLine
) with the charset-agnostic LPTSTR
too:
int APIENTRY _tWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nShowCmd
)
If Unicode is enabled on the project, this becomes LPWSTR
, giving the signature:
int APIENTRY wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nShowCmd
)
If Unicode is not enabled, you get the signature:
int APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
Replacing WinMain() with main() function in Win32 programs
You can use standard main
in a "windows" app (that is, a GUI subsystem Windows application) even with the Microsoft tools, if you add the following to the Microsoft linker options:
/subsystem:windows /ENTRY:mainCRTStartup
Note that this is not necessary for the GNU toolchain.
Still for the Microsoft tools you can alternatively add this to your main file:
#ifdef _MSC_VER
# pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
James McNellis tells you how to get the hInstance.
_tWinMain in static lib LNK2019
Your problem is that the function in the lib is called _tWinMain.
Just call it WinMain and you are good to go.
WINAPI / APIENTRY is not defined
You'll have to include windows.h to get the required definitions, that's just the way Windows development works.
Difference between WinMain and wWinMain
On Windows XP, if an application entry is WinMain, does Windows convert the command line from Unicode to Ansi and pass to the application?
Yes.
If the command line parameter must be in Unicode (for example, Unicode file name, conversion will cause some characters missing), does that mean that I must use wWinMain as the entry function?
Yes, you should, if you want to correctly handle Unicode arguments to your program.
The documentation to WinMain() on MSDN also agrees.
You can, however, also use GetCommandLineW to retrieve the command line specifically in Unicode.
Related Topics
C/C++: Static Function in Header File, What Does It Mean
C++ Objects: When Should I Use Pointer or Reference
Authenticating Users Using Active Directory in Client-Server Application
What Use Are Const Pointers (As Opposed to Pointers to Const Objects)
Error for Hash Function of Pair of Ints
Where in Memory Is Vtable Stored
How Does the C++ Compiler Know Which Implementation of a Virtual Function to Call
Does Auto Deduce the Type at Compile Time or Runtime in C++ 11
Async Wait on File Descriptor Using Boost Asio
Is It True That There Is No Need to Learn C Because C++ Contains Everything
Optimizations for Pow() with Const Non-Integer Exponent
Converting a Row of Cv::Mat to Std::Vector
How to Create and Initialize an Array of Values Using Template Metaprogramming
The Difference Between Delete and Delete[] in C++
How to Add Element by Element of Two Stl Vectors
Default Move Constructor/Assignment and Deleted Copy Constructor/Assignment
How to Enumerate/List All Installed Applications in Windows Xp