如何将入口点过程从“WinMain”更改为“main”或任何自定义函数?
Posted
技术标签:
【中文标题】如何将入口点过程从“WinMain”更改为“main”或任何自定义函数?【英文标题】:How can I change the entry point procedure from "WinMain" to "main" or any custom function? 【发布时间】:2020-08-30 15:39:54 【问题描述】:我已经阅读了很多关于如何更改 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;
我该怎么做?
【问题讨论】:
使用main
或WinMain
以外的东西会很棘手,因为这些是运行时库在完成初始化后调用的入口点。 MSVC 链接器确实允许您在命令行上指定入口点(请参阅here,但那样会绕过运行时库初始化代码并破坏您的应用程序。
我想要一种任何方式来替换/更改 Windows 上 GUI 应用程序的入口点过程 - 感觉?你想得到什么?这是干什么用的?
@RbMm:我正在尝试创建一个 GUI 库,但我不想让库变得复杂,所以我想让入口点成为用户熟悉的东西,例如 int main(int argc, char *argv[])
函数int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdParam, int cmdShow)
.
@LionKing - 如果说真的,我根本不了解你。 main
或 WinMain
有什么不同?一些用户在这里是如何相关的,为什么 lib 完全实现入口点.. 但是如果你理解我的回答,你想要做的很容易 - /ENTRY: mainCRTStartup
- 这很明显
在您的 GUI 库中包含一个 WinMain 函数,该函数执行任何操作,然后调用您未实现的名为 main 的函数。然后当库的用户创建一个 main 函数时,它就可以工作了。然后加载程序只需调用您的 WinMain 函数而无需任何特殊调味料。主要的是库的用户需要将他们的程序编译为 Windows 可执行文件而不是控制台程序,以便调用 WinMain。
【参考方案1】:
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
(对于控制台应用程序),WinMainCRTStartup
或 @987654344 @ 用于 gui 应用程序。
在所有这 4 个函数中 - 按名称称为 硬编码 函数
mainCRTStartup
致电main
wmainCRTStartup
致电wmain
WinMainCRTStartup
致电 WinMain
wWinMainCRTStartup
致电wWinMain
当然,被调用函数必须在您的代码或另一个 lib 代码中的某处实现。例如,如果您使用 MFC - 它自己实现 wWinMain
并以另一种方式调用您的代码(通过在您覆盖的对象上调用虚函数 - InitApplication
和InitInstance
)
如果回过头来质疑如何更改自定义入口点的名称 - 但是为了什么?你真的不需要改变名字。您只需要了解如何调用您的入口点。如果你明白这一点 - 你几乎可以做所有事情。
假设我们想使用 main
作为“入口点”。我把它用引号引起来,因为我们真的希望在 CRT 代码中有真正的入口点,并且我们希望 CRT 代码准确地调用 main
函数。
可能吗?简单地 !
设置/ENTRY: mainCRTStartup
链接器选项。所以 mainCRTStartup
将是真正的入口点,它调用 main
。
另一个问题,我个人认为这是毫无意义的把戏,没有任何改变,也没有给予
也可以简单地从WinMain
调用main
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;
【讨论】:
评论不用于扩展讨论;这个对话是moved to chat。【参考方案2】:它必须与(MS、GCC、Clang)编译器兼容
如何做到这一点取决于您的编译器。他们中的大多数都会有一些标志来选择您所针对的“子系统”(Windows 术语),甚至可以手动自定义入口点。
换句话说,没有这样做的标准方法,因为这超出了 C++ 标准的范围。
话虽如此,一些编译器提供了模拟其他编译器标志的方法。例如,Clang 可以模仿微软的。
【讨论】:
以上是关于如何将入口点过程从“WinMain”更改为“main”或任何自定义函数?的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ 中,主函数是编程的入口点,我如何将其更改为其他函数?