Lion King
Lion King

Reputation: 33813

How can I change the entry point procedure from "WinMain" to "main" or any custom function?

I have read a lot about how to change the WinMain entry point procedure, some say you can change the entry point from the linker and some others say you can put the WinMain into DLL (dllMain) and so on.

Honestly, I am confused. I believe that there are one or more ways to change the entry point procedure to a custom procedure because there are some examples like MFC don't have a direct WinMain function and the Qt framework also has a custom entry point procedure it's similar to the console application main function int main(int argc, char *argv[]), so, there are ways as I expected.

I want a whatever way to replace/change the entry point procedure for GUI application on Windows from the traditional procedural WinMain to int main(int argc, char *argv[]) like Qt or even any other custom function but it must be compatible with (MS, GCC, Clang) compilers.

///////////Windows main/////////////
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdParam, int cmdShow){

}
///////////Console main and Qt framework////////////
int main(int argc, char *argv[]) {
    
}
//////////MFC////////////
class CMyFrame : public CFrameWnd {
   public:
      CMyFrame() {}
};

class CExample : public CWinApp {
   BOOL InitInstance() {}
};
CExample theApp;

How do I do that?

Upvotes: 1

Views: 1507

Answers (2)

RbMm
RbMm

Reputation: 33706

entry point of exe can by any function with signature

ULONG CALLBACK ep(void* )

possible and use ULONG CALLBACK ep() - despite on x86 will be wrong stack pointer (esp) after return, this not lead to error, because windows just call ExitThread after entry return, if it return control at all - usually it call ExitProcess instead return.

the name of this entry point of course not play any role at all - it can be any valid c/c++ name. entry point found/called not by name but by AddressOfEntryPoint offset from IMAGE_OPTIONAL_HEADER

but when we build PE - we need tell linker name of this function, for it can set AddressOfEntryPoint, but this info (name of function) used only during build process (not used in runtime)

different linkers of course have different options for do this, link.exe have option /ENTRY. this option is optional and by default, the starting address is a function name from the C run-time library.

if /ENTRY:MyEntry explicitly stated - it used as is - MyEntry will be used as entry point. if no /ENTRY option set - used default:

if /SUBSYSTEM:CONSOLE set - used mainCRTStartup or if it not found wmainCRTStartup

if /SUBSYSTEM:WINDOWS set - used WinMainCRTStartup or if it not found wWinMainCRTStartup

but in most case c/c++ developers use CRT libraries. regardless of whether static or dynamic linking used with CRT - some lib code always statically linked with your exe and this code containing function which you used as entry point. for ms windows crt - this is mainCRTStartup or wmainCRTStartup (for console apps), WinMainCRTStartup or wWinMainCRTStartup for gui apps.

in all this 4 functions - called hardcoded function by name

  • mainCRTStartup call main
  • wmainCRTStartup call wmain
  • WinMainCRTStartup call WinMain
  • wWinMainCRTStartup call wWinMain

of course called function must be implemented somewhere in your code or in another lib code. for example if you use MFC - it implement wWinMain by self and called your code in another way ( via calling virtual functions on object which you override - InitApplication and InitInstance)

if back to question how change name of your custom entry point - but for what ? you really not need change name. you need only understand how your entry point is called. if you understand this - you can do almost all.


assume we want use main as "entry point". i take this in quotes because we really want have real entry point in CRT code and we want that CRT code call exactly main function.

possible ? simply ! set /ENTRY: mainCRTStartup linker option. so mainCRTStartup will be real entry point and it call main.

another question, i personally think that this is senseless trick, which nothing change and nothing give


also possible simply call main from WinMain

typedef struct
{
    int newmode;
} _startupinfo;

 /* 
 * new mode flag -- when set, makes malloc() behave like new()
 */

EXTERN_C _CRTIMP int __cdecl _query_new_mode( );
EXTERN_C _CRTIMP int __cdecl _set_new_mode( _In_ int _NewMode);

EXTERN_C
_CRTIMP int __cdecl __getmainargs(__out int * _Argc, 
                              __deref_out_ecount(*_Argc) char *** _Argv,
                              __deref_out_opt char *** _Env, 
                              __in int _DoWildCard,
                              __in _startupinfo * _StartInfo);

int __cdecl main(__in int _Argc, __in_ecount_z(_Argc) char ** _Argv, ...);

int CALLBACK WinMain( _In_ HINSTANCE , _In_opt_ HINSTANCE , _In_ LPSTR , _In_ int  )
{
    int _Argc, r;
    char ** _Argv;
    char ** _Env;
    _startupinfo  _StartInfo { _query_new_mode( ) };
    if (!(r = __getmainargs(&_Argc, &_Argv, &_Env, 0, &_StartInfo)))
    {
        r = main(_Argc, _Argv, _Env);
        if (_Argv) free(_Argv);
    }

    return r;
}

Upvotes: 1

Acorn
Acorn

Reputation: 26066

it must be compatible with (MS, GCC, Clang) compilers

How you do that depends on your compiler. Most of them will have some flags to choose which "subsystem" (the Windows term) you are targeting and even customize the entry point manually.

Put another way, there is no standard way of doing so because this is outside the scope of the C++ standard.

Having said that, some compilers provide the means to emulate the flags of other compilers. For instance, Clang can imitate Microsoft's.

Upvotes: 0

Related Questions