Reputation: 9624
Right, I have looked at this post: Difference between WinMain,main and DllMain in C++
I now know that WINMAIN
is used for window applications and main()
for consoles. But reading the post doesn't really tell me why exactly what is the difference.
I mean what's the point of having separating different mains functions to start of a program? Is it due to performance issues? Or what is it?
Upvotes: 87
Views: 120375
Reputation: 18980
For any Microsoft developers who have access to and understand the source code for the tools (including Developer Command Prompt for VS 2022) installed in this link to setup C/C++ in Visual Studio Code, which is what most modern developers use, notice how this error message only happens once when compiling (Step 2). Then the error message never appears again. So the Developer Command Prompt for VS 2022 source code must have two different sets of logic. One set of logic before this error appears and one set of logic after. Strange.
This question led me to the question we're in here.
LINK : fatal error LNK1561: entry point must be defined ERROR IN VC++
Step 1.) Install these tools:
https://visualstudio.microsoft.com/visual-cpp-build-tools/
Step 2.) Compile the hello.c program below and get error message
LINK : fatal error LNK1561: entry point must be defined
Step 3.) Add parameters to main() to look like this again (reverted) and compile again with cl hello.c, and no error results.
int main(int argc, char** argv)
Step 4.) Remove parameters from main() to look like this again and compile again with cl hello.c, and no error results.
int main()
Source code:
#include <stdio.h>
int main()
{
printf("Hello, World! This is a native C program compiled on the command line.\n");
return 0;
}
Upvotes: 0
Reputation: 4677
The Windows CRT exposes 5 symbols mainCRTStartup
, wmainCRTStartup
, wWinMainCRTStartup
, _DllMainCRTStartup
and WinMainCRTStartup
.
The w
before means the unicode version, i.e. the command line (command and argument string) passed to the process (and stored in the PPB PEB->ProcessParameters->CommandLine
) is UTF-16 (i.e. WCHAR
(Wide char)) rather than ASCII (UTF-8 or ANSI e.g. Windows-1252, Windows-850 etc.)
If the /DLL
or /SUBSYSTEM
option is not specified, the MSVC linker selects a subsystem and entry point i.e. makes the entry address one of those 5 functions based on whether main
, WinMain
or DllMain
is present in the symbol table of one of the object files. The entry point is statically linked by the MSVC linker via libcmt.lib
, which will further only include symbols that are actually used by that entry function.
mainCRTStartup
will call GetStartupInfo()
/ access the PPB to get stdin/out handles and command line arguments. _init term()
is also called, as well as _init_atexit()
. It calls main
The return value of main
is passed to ExitProcess()
after the set atexit
routine is called.
Debug symbols in a .pdb created by using the /Zi
compiler option are needed to be loaded in IDA Pro in order to reveal symbols such as mainCRTstartup
and main
, which will without debugging symbols instead be represented as start
and sub_??????
respectively.
Reference:
Upvotes: 5
Reputation: 11130
According to @RaymondChen
The name WinMain is just a convention
Although the function WinMain is documented in the Platform SDK, it's not really part of the platform. Rather, WinMain is the conventional name for the user-provided entry point to a Windows program.
The real entry point is in the C runtime library, which initializes the runtime, runs global constructors, and then calls your WinMain function (or wWinMain if you prefer a Unicode entry point).
DllMain and WinMain is different in their prototypes itself. WinMain accepts commandline argument while the other one talks about how it's attached to the process.
As per MSDN documentation
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.
mainCRTStartup
(or wmainCRTStartup
) An application using
/SUBSYSTEM:CONSOLE;
calls main (or wmain
)
WinMainCRTStartup
(or wWinMainCRTStartup
) 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
Upvotes: 15
Reputation: 145269
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 the GetModuleHandle
API function,
the hPrevInstance
argument is always 0,
the lpCmdLine
argument can alternatively be obtained from the GetCommandLine
API function, plus a bit of weird logic to skip the program name part of the command line, and
the nCmdShow
argument value can alternatively be obtained from the GetStartupInfo
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.
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] > _
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] > _
Upvotes: 229
Reputation: 29
Main vs WinMain
As I have read from many links:
WinMain()
is the C
entry point function of any windows application. Like normal DOS/console
based application which has main()
function as C
entry point, in windows we have WinMain()
instead. WinMain()
is a function which is called by system during creation of a process.
First argument is the instance handle of the current process.
Next is the previous instance.
Command line arguments comes as next argument.
Finally shell passes the show/display attribute of main window.
Note : WinMain returns success as zero and error as non zero.
Upvotes: 0
Reputation: 1
I had an exe using _tWinMain and Configuration Properties.Linker.System.Subsystem: Windows (/SUBSYSTEM:WINDOWS). Later I wanted it to support cmdline args and print to the console so I added:
// We need to printf to stdout and we don't have one, so get one
AllocConsole();
// Redirect pre-opened STDOUT to the console
freopen_s((FILE **)stdout, "CONOUT$", "w", stdout);
but that only worked by printing in another console window that went away so was not that useful. Below is the way I changed it to work with Console (/SUBSYSTEM:CONSOLE) in such a way as I could go back and forth, if I needed to.
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
UNREFERENCED_PARAMETER(envp);
return (_tWinMain(NULL, NULL, ::GetCommandLineW(), 0));
}
Upvotes: 0
Reputation: 83527
I vaguely recall reading somewhere that Windows programs have a main()
function. It is just hidden in a header or library somewhere. I believe this main()
function initializes all of the variables needed by WinMain()
and then calls it.
Of course, I'm a WinAPI noob, so I hope others who are more knowledgeable will correct me if I am wrong.
Upvotes: 2
Reputation: 67224
A standard C program is passed 2 parameters by the command line at start up:
int main( int argc, char** argv ) ;
char** argv
is an array of strings (char*
)int argc
is the number of char*
in argvThe booting function WinMain
that programmers have to write for a windows program is slightly different. WinMain
takes 4 parameters that are passed to the program by Win O/S at start up:
int WINAPI WinMain( HINSTANCE hInstance, // HANDLE TO AN INSTANCE. This is the "handle" to YOUR PROGRAM ITSELF.
HINSTANCE hPrevInstance,// USELESS on modern windows (totally ignore hPrevInstance)
LPSTR szCmdLine, // Command line arguments. similar to argv in standard C programs
int iCmdShow ) // Start window maximized, minimized, etc.
See my article How to create a basic window in C for more
Upvotes: 3