Differencebetween Wmain and Main

What is the difference between wmain and main?

"If your code adheres to the Unicode programming model, you can use the wide-character version of main, which is wmain."

http://msdn.microsoft.com/en-us/library/aa299386%28VS.60%29.aspx

main( int argc, char *argv[ ], char *envp[ ] )
{
program-statements
}

wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
{
program-statements
}

What is the difference between _tmain() and main() in C++?

_tmain does not exist in C++. main does.

_tmain is a Microsoft extension.

main is, according to the C++ standard, the program's entry point.
It has one of these two signatures:

int main();
int main(int argc, char* argv[]);

Microsoft has added a wmain which replaces the second signature with this:

int wmain(int argc, wchar_t* argv[]);

And then, to make it easier to switch between Unicode (UTF-16) and their multibyte character set, they've defined _tmain which, if Unicode is enabled, is compiled as wmain, and otherwise as main.

As for the second part of your question, the first part of the puzzle is that your main function is wrong. wmain should take a wchar_t argument, not char. Since the compiler doesn't enforce this for the main function, you get a program where an array of wchar_t strings are passed to the main function, which interprets them as char strings.

Now, in UTF-16, the character set used by Windows when Unicode is enabled, all the ASCII characters are represented as the pair of bytes \0 followed by the ASCII value.

And since the x86 CPU is little-endian, the order of these bytes are swapped, so that the ASCII value comes first, then followed by a null byte.

And in a char string, how is the string usually terminated? Yep, by a null byte. So your program sees a bunch of strings, each one byte long.

In general, you have three options when doing Windows programming:

  • Explicitly use Unicode (call wmain, and for every Windows API function which takes char-related arguments, call the -W version of the function. Instead of CreateWindow, call CreateWindowW). And instead of using char use wchar_t, and so on
  • Explicitly disable Unicode. Call main, and CreateWindowA, and use char for strings.
  • Allow both. (call _tmain, and CreateWindow, which resolve to main/_tmain and CreateWindowA/CreateWindowW), and use TCHAR instead of char/wchar_t.

The same applies to the string types defined by windows.h:
LPCTSTR resolves to either LPCSTR or LPCWSTR, and for every other type that includes char or wchar_t, a -T- version always exists which can be used instead.

Note that all of this is Microsoft specific. TCHAR is not a standard C++ type, it is a macro defined in windows.h. wmain and _tmain are also defined by Microsoft only.

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 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.


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]
> _

WinMain vs. main (C++)

Talking about the Microsoft toolchain, conventionally, Win32 graphical applications have always started with WinMain, while main is used for console applications.

The difference between the two kinds of applications actually boils down (mostly) to a single setting in the executable, and is not in capability - a GUI application can create a console, and a console application can create a window - but in the behavior of the loader: for an exe marked as GUI the loader won't allocate any console, while a console exe will attach to the parent's console or create a new one if there isn't one.

For the entrypoint name, it is all just a matter of linker/CRT defaults: the "real" entry point of the executable is just an offset into the final executable, that points to a function that takes no parameters. It's the CRT that does its stuff, determines the parameters and then calls "your" entrypoint, so, in line of principle, they both could work exactly the same way.

The point is, the name/signature of the default entrypoint that the CRT looks for depends from the type of application you are building; if the compiler and linker are set to build a console application, they will look for a main (or wmain or _tmain, depending on Unicode settings), for a GUI application they use WinMain, and DllMain for a dll.


So:

  • use WinMain if you are building a GUI (=no console created for it at startup) application;
  • main for a console application;
  • DllMain for a dll.

Again, this all isn't written in stone (and there are ways to start a GUI application from a standard main), but "when in Rome, do as the Romans do" - i.e. it's usually best to follow the uses of the platform to avoid confusing other developers and going through untested/unsupported compiler settings just to change the signature of the entrypoint.

wmain vs main C runtime

Modern versions of Windows internally use UTF-16. Therefore, when you launch an executable, all command line arguments likely are passed as UTF-16 from the onset, and the runtime library linked into the launched application either passes the arguments through unscathed (if using wmain) or converts them to the local encoding automatically (if using main). (Specifically this would be done by wmainCRTStartup/mainCRTStartup which are the actual entry points used for console Windows applications.)

What are, and what is the difference between, kmain and dmain -- main functions in C?

You seem to be referring to this tutorial on OSDev.org.

If you’ll notice, this is not a standard C program with main() as its entry point. In fact, the page shows two entry points: one written in Assembler in a way for GRUB to find & load, and which sets up & loads the second, kmain(), which is written in C. The writers use the name kmain to mean “kernel main”; presumably dmain is the entry point for drivers & would stand for “driver main”.

C makes a distinction between “freestanding” and “hosted” implementations. Hosted is what you’re probably more familiar with; the standard C library is available, and all programs start at the main function.

OS kernels are (often) good examples of freestanding environments. The C library will likely not be available, for example (except for certain headers like stddef.h & stdarg.h; see the standard for details). Also, the entry point is not defined by the standard anymore. The OSDev.org tutorial is making a special point of that fact, by explicitly defining its entry point with a different name.

You could probably run the tutorial renaming kmain to main, but note that it’s still void main(void*, unsigned int), not int main(int, char**); in fact that sort of confusion is likely part of the reason the writers chose to use a different name. But is is just a convention they’ve selected, not anything standardized.

How to force the visual studio to use the wmain instead of main

  Using the #pragma comment(linker, "/SUBSYSTEM:CONSOLE /ENTRY:mainCRTStartup")

You are getting close, not quite close enough. The CRT has four entrypoints:

  • mainCRTStartup => calls main(), the entrypoint for console mode apps
  • wmainCRTStartup => calls wmain(), as above but the Unicode version
  • WinMainCRTStartup => calls WinMain(), the entrypoint for native Windows apps
  • wWinMainCRTStartup => calls wWinMain(), as above but the Unicode version

So it is /ENTRY:wmainCRTStartup

Do beware that the command line arguments are converted to Unicode assuming the default console code page. Which is a bit unpredictable, it is the legacy 437 OEM code page only in Western Europe and the Americas. The user might need to use the CHCP command (CHange Code Page) and tinker with the console window font to keep you happy. YMMV.

Can we use wmain() with Unix compilers or it'll work only on Windows?

The only standard signatures for main are:

int main(void);
int main(int argc, char *argv[]);

However, a freestanding implementation can provide extensions/allow other signatures. But those are not guranteed to be portable. wmain looks like a Windows/VS thing. There's not much chance this will work on a *nix/GNU GCC.

C++ main vs C main

Both C and C++ require that any implementation of the language must support the forms int main(void) and int main(int, char**). However, the standards also say that additional forms may be supported by the implementation, and thus a program that uses one of those other forms is not automatically invalid -- rather, it is a valid program that only happens to be supported on certain platforms.

The only difference between C and C++ in that regard is which alternative forms of main are permitted. In C++, all forms must return int, so only the arguments are allowed to vary, and moreover, if the first two arguments of any form are int, char**, they should have the usual meaning.

C is a little more liberal, as it allows any alternative form of main. Thus a program with void main(char, double) is a valid C program that requires the implementation to support this signature, while it would unconditionally be ill-formed C++. On the other hand, int main(int, char**, char**) is a permissible signature for both C and C++, also requiring implementation support, and C++ would expect the first two arguments to have the usual meaning.



Related Topics



Leave a reply



Submit