c++ - 如何将入口点过程从“WinMain”更改为“main”或任何自定义函数?
问题描述
我已经阅读了很多关于如何更改WinMain
入口点程序的内容,有人说您可以从链接器更改入口点,而另一些人说您可以将其WinMain
放入 DLL ( dllMain
) 等等。
老实说,我很困惑。我相信有一种或多种方法可以将入口点过程更改为自定义过程,因为有一些示例,例如 MFC 没有直接WinMain
功能,Qt 框架也有自定义入口点过程,它类似于控制台应用程序main
function 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
(用于控制台应用程序),WinMainCRTStartup
或wWinMainCRTStartup
用于 gui 应用程序。
在所有这 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;
}
推荐阅读
- cakephp-4.x - 如何进行下拉搜索
- delphi - 获取 65 到 90 之间的随机数
- vue.js - 无法解析组件导入 VueJS
- python - 如何过滤数据表以匹配特定列中的值
- api - 使用 Automapper 映射名称中带有冒号的字段
- r - 如何在一个循环中绘制许多回归的结果?
- amazon-web-services - 如何保证文件上传到存储?
- python - Jupyter Notebook 条形图格式
- c - Visual Studio (C) 忽略转义序列
- string - 当我运行以下代码时,终端告诉我“int. object not subscriptable error”