我已经阅读了很多有关如何更改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-这是mainCRTStartup
或wmainCRTStartup
(对于控制台应用程序),对于gui应用程序,这是WinMainCRTStartup
或wWinMainCRTStartup
。在这4个函数中-按名称称为硬编码函数
mainCRTStartup
调用main
wmainCRTStartup
调用wmain
WinMainCRTStartup
调用WinMain
wWinMainCRTStartup
调用wWinMain
当然,必须在您的代码中的某个地方或另一个lib代码中实现被调用的函数。例如,如果您使用MFC-它会自行实现
wWinMain
并以另一种方式调用您的代码(通过在您覆盖的对象上调用虚拟函数-InitApplication
和InitInstance
)如果回头问如何更改您的自定义入口点的名称-但是要做什么?您真的不需要更改名称。您只需要了解入口点的调用方式即可。如果您了解这一点-您几乎可以做的一切。
假设我们要使用
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/