Windows 下的 WinMain 和标准的 main 函数有几个关键区别。

函数签名

// 标准 main
int main(int argc, char* argv[]) 
 
// Windows GUI 程序的 WinMain
int WINAPI WinMain(
    _In_ HINSTANCE hInstance,      // 当前实例句柄
    _In_opt_ HINSTANCE hPrevInstance,  // 总是 NULL,已废弃
    _In_ LPSTR lpCmdLine,         // 命令行参数
    _In_ int nCmdShow             // 窗口显示状态
)
 
// Windows Console 程序的 main
int main(int argc, char* argv[])

应用程序类型

  • main(): 通常用于控制台应用程序 (Console Application)
  • WinMain(): 用于 Windows GUI 应用程序

参数传递

  • main() 通过 argc/argv 接收命令行参数
  • WinMain() 通过 lpCmdLine 接收命令行字符串,需要自行解析
  • 如果需要在 WinMain 中获取类似 argc/argv 的参数,可以使用:
int argc;
LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);

窗口与入口点

  • main() 默认会创建控制台窗口
  • WinMain() 不会创建控制台窗口,需要自行创建应用程序窗口
  • 控制台程序默认使用 main 作为入口点
  • GUI 程序需要在链接器设置中指定 /SUBSYSTEM:WINDOWS,使用 WinMain 作为入口点

编译设置

// 控制台程序
#pragma comment(linker, "/subsystem:console")
 
// GUI 程序
#pragma comment(linker, "/subsystem:windows")

实际使用示例

// GUI 程序基本框架
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                   LPSTR lpCmdLine, int nCmdShow)
{
    // 注册窗口类
    WNDCLASSEX wc = {0};
    // 设置窗口类属性...
    
    // 创建窗口
    HWND hwnd = CreateWindowEx(
        // 窗口参数...
    );
    
    // 消息循环
    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    return msg.wParam;
}

如何选择

选择使用哪个入口点主要取决于你的应用程序类型:

  • 如果开发控制台应用程序,使用 main()
  • 如果开发 GUI 应用程序,使用 WinMain()
  • 如果需要同时支持控制台和 GUI,可以在 main() 中创建窗口