我已经阅读了很多有关如何更改WinMain入口点过程的信息,有人说您可以从链接器更改入口点,而另一些人则可以将WinMain放入DLL(dllMain)中,依此类推。
老实说,我很困惑。我相信有一种或多种将入口点过程更改为自定义过程的方法,因为有一些示例,例如MFC没有直接的WinMain函数,并且Qt框架也有一个自定义入口点过程,它类似于控制台应用程序main函数int main(int argc, char *argv[]),因此,有一些我所期望的方法。
我想以任何一种方式替换/更改Windows上的GUI应用程序的入口点过程,从传统的过程WinMain更改为int main(int argc, char *argv[])(例如Qt或什至其他任何自定义函数),但它必须与(MS,GCC,Clang)编译器兼容。

///////////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;
我怎么做?

最佳答案

exe的入口点可以通过带有签名的任何功能

ULONG CALLBACK ep(void* )
可能并使用ULONG CALLBACK ep()-尽管在x86上返回后将返回错误的堆栈指针(esp),但这不会导致错误,因为Windows仅在条目返回后才调用ExitThread,如果它完全返回了控件,则通常会调用ExitProcess而不是返回。
这个入口点的名称当然根本不起作用-它可以是任何有效的c / c++名称。找到/调用的入口点不是按名称而是由 AddressOfEntryPoint 偏离 IMAGE_OPTIONAL_HEADER
但是在构建PE时-我们需要告诉该函数链接器名称,因为它可以设置AddressOfEntryPoint,但是此信息(函数名称)仅在构建过程中使用(在运行时中不使用)
当然,不同的链接器具有不同的选项,link.exe具有选项 /ENTRY 。此选项是可选的,默认情况下,起始地址是C运行时库中的函数名称。
如果/ENTRY:MyEntry明确声明-按原样使用-MyEntry将用作入口点。如果未设置/ENTRY选项-使用默认值:
如果设置了/SUBSYSTEM:CONSOLE-使用了mainCRTStartup或未找到wmainCRTStartup如果设置了/SUBSYSTEM:WINDOWS-使用了WinMainCRTStartup或未找到wWinMainCRTStartup但大多数情况下,c / c++开发人员使用CRT库。无论CRT使用的是静态链接还是动态链接-某些lib代码始终与exe静态链接,并且此代码包含用作入口点的函数。对于ms windows crt-这是mainCRTStartupwmainCRTStartup(对于控制台应用程序),对于gui应用程序,这是WinMainCRTStartupwWinMainCRTStartup
在这4个函数中-按名称称为硬编码函数
  • mainCRTStartup调用main
  • wmainCRTStartup调用wmain
  • WinMainCRTStartup调用WinMain
  • wWinMainCRTStartup调用wWinMain

  • 当然,必须在您的代码中的某个地方或另一个lib代码中实现被调用的函数。例如,如果您使用MFC-它会自行实现wWinMain并以另一种方式调用您的代码(通过在您覆盖的对象上调用虚拟函数-InitApplicationInitInstance)
    如果回头问如何更改您的自定义入口点的名称-但是要做什么?您真的不需要更改名称。您只需要了解入口点的调用方式即可。如果您了解这一点-您几乎可以做的一切。

    假设我们要使用main作为“入口点”。我将其用引号引起来,因为我们确实希望CRT代码中具有真正的入口点,并且我们希望CRT代码完全调用main函数。
    可能吗?简单地!
    设置/ENTRY: mainCRTStartup链接器选项。因此mainCRTStartup将是真正的入口点,它称为main
    另一个问题,我个人认为这是无意义的把戏,什么也不会改变,也不会给

    也可以简单地从main调用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;
    }
    

    关于c++ - 如何将入口点过程从 “WinMain”更改为 “main”或任何自定义函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63659160/

    10-11 18:45