Trouble with linker when .lib defines wWinMain()

Hi,

I am trying to set up a situation like the SDLs SDLMain2.lib, where a user can link to a .lib that contains WinMain() however, I would like to use wWinMain() instead of WinMain(). Here is what I have:

libwithmain.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#ifdef MAIN_NEEDED
#define main foo
#endif

#ifdef __cplusplus
extern "C" {
#endif

int foo();

#ifdef __cplusplus
}
#endif



libwithmain.cpp

1
2
3
4
5
6
7
#include "libwithmain.h"

int WINAPI
wWinMain(HINSTANCE instance, HINSTANCE pInstance, PWSTR cmdLine, int cmdShow) {
    foo();
    return 0;
}


build libwithmain:

cl %compiler_options% /c libwithmain.cpp /Fo
lib libwithmain.obj


someuser.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "libwithmain.h"

#ifdef CRT_OK
#include <cstdio>
#endif

// Use .lib entry point
#ifdef MAIN_NEEDED

extern "C" int main(){

#ifdef CRT_OK
    printf("\nHello from main");
#endif

    return 0;
}

// Do not use .lib entry point
#else

int foo(){
    return 0;
}

int main(){
    printf("Hello from main()");
    foo();
    return 0;
}
#endif


And a variety of ways to build someuser:

1) Works but requires not using CRT
cl %compiler_options% /D MAIN_NEEDED someuser.cpp /link Kernel32.lib libwithmain.lib /ENTRY:wWinMain

2) Works but uses libwithmain.obj instead of libwithmain.lib. CRT is okay to use.
cl %compiler_options% /D MAIN_NEEDED /D CRT_OK someuser.cpp /link libwithmain.obj

3) The case that I want but can't get to work with wWinMain(). If libwithmain.cpp uses WinMain() instead of wWinMain() this works just fine. If wWinMain() is used the linker gives

error LNK2019 unresolved external symbol WinMain referenced in function "int __cdecl __scrt_common_main_seg(void)" (?__scrt_common_main_seh@@YAHXZ)

when linking someuser.

cl %compiler% /DMAIN_NEEDED /D CRT_OK someuser.cpp /link libwithmain.lib /SUBSYSTEM:WINDOWS

This leaves me with two questions.
1) My understanding is that a .lib in this scenario is simply combining a bunch of .obj files into one. If this is correct then why does building someuser with linking to libwithmain.obj work but linking to libwithmain.lib not work.

2) Can I have crt main() call wWinMain instead of WinMain to resolve the link error and if so, how do I tell crt to do that?

Thanks!

Edited by Jason on Reason: add [code]
Please put your code in [ code ] tags, otherwise your post is very hard to read.

My guess it that compiler looks only in .obj files to determine if you need unicode or ansi CRT entry point. If it doesn't find WinMain or wWinMain I guess it assumes ansi entry point.

To force it to use unicode CRT entry point pass "/ENTRY:wWinMainCRTStartup" argument to linker (in 3rd step).

2) Can I have crt main() call wWinMain instead of WinMain to resolve the link error and if so, how do I tell crt to do that?
CRT main doesn't call wWinMain or WinMain.
CRT runtime starts at WinMainCRTStartup, wWinMainCRTStartup, mainCRTStartup or wmainCRTStartup functions. Which one linker picks is up to /SUBSYSTEM setting + some magic how it knows which one unicode or ansi to pick up (not sure exactly how).
You can see source for these function in "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime" folder. Look for exe_main.cpp, exe_winmain.cpp, exe_wmain.cpp and exe_wwinmain.cpp files. They all call __scrt_common_main function in exe_common.inl include that gets included in those four files. Define before include overrides which user function to call after all the internal CRT stuff is set up.

Edited by Mārtiņš Možeiko on
Added [code] and you sir are money!

mmozeiko


To force it to use unicode CRT entry point pass "/ENTRY:wWinMainCRTStartup" argument to linker (in 3rd step).



Worked perfect. Thank you for the additional info about the startup functions too.