Winmain与main有何区别?

99ANYc3cd6
预计阅读时长 18 分钟
位置: 首页 C语言 正文

WinMain 是 Windows 程序的入口点,相当于控制台程序中的 main 函数,当一个 Windows 桌面应用程序被加载到内存中并由操作系统执行时,操作系统会首先查找并调用 WinMain 函数。

c语言 winmain
(图片来源网络,侵删)

WinMain 的基本结构

WinMain 函数有固定的签名,它接收四个参数,并返回一个 int 类型的值。

int WINAPI WinMain(
  HINSTANCE hInstance,     // 当前实例的句柄
  HINSTANCE hPrevInstance, // 旧版Windows的遗留,总为NULL
  LPSTR     lpCmdLine,    // 命令行参数
  int       nCmdShow      // 窗口的显示方式
);

参数详解

HINSTANCE hInstance

  • 类型: HINSTANCE (Handle to an INSTANCE,实例句柄)
  • 含义: 这是一个句柄,它唯一标识了当前正在运行的程序实例,在 Windows 中,句柄是一个指向操作系统内部数据结构的指针,你的程序通过这个句柄来请求操作系统服务,当你需要加载资源(如图标、位图)时,就需要用到这个句柄。
  • 类比: 可以把它想象成你程序的“身份证号”。

HINSTANCE hPrevInstance

  • 类型: HINSTANCE
  • 含义: 在 16 位 Windows 环境下,这个参数用于判断是否已经有另一个实例正在运行,但在 32 位和 64 位的 Windows 中,每个进程都有自己独立的地址空间,所以这个参数总是 NULL
  • 建议: 在现代 Windows 编程中,你可以完全忽略这个参数。

LPSTR lpCmdLine

  • 类型: LPSTR (Long Pointer to a STRing,指向字符串的长指针)
  • 含义: 这是一个指向命令行参数的字符串,它包含了用户在启动程序时在程序名后面输入的所有内容。
  • 注意: 它不包含程序自身的名称,并且参数之间通常用空格分隔,如果你需要解析复杂的命令行(例如带引号的参数),最好使用 Windows API 提供的 CommandLineToArgvW 函数,而不是自己手动分割。

int nCmdShow

  • 类型: int
  • 含义: 这个参数指定了主窗口应该如何被显示,它是一个预定义的常量,
    • SW_SHOW: 正常显示窗口。
    • SW_HIDE: 隐藏窗口。
    • SW_MINIMIZE: 最小化窗口。
    • SW_MAXIMIZE: 最大化窗口。
  • 用途: 当你从快捷方式启动程序时,可以设置其“运行方式”为“最大化”或“最小化”,nCmdShow 的值就会相应地改变,你的程序应该尊重这个设置。

WinMain vs. main

特性 main WinMain
用途 控制台应用程序 (命令行程序) Windows 桌面 GUI 应用程序
入口点 C/C++ 标准规定 Windows 操作系统规定
参数 int argc, char *argv[] HINSTANCE, HINSTANCE, LPSTR, int
返回值 int,返回给父进程或操作系统 int,返回给操作系统
GUI 通常没有图形界面,使用 printf 等函数 必须使用 Windows API 创建和管理窗口

一个最简单的 WinMain 示例

这个示例创建一个窗口,显示一个消息框,然后退出,这是理解 Windows 程序工作流程的经典入门程序。

#include <windows.h> // 必须包含 Windows API 头文件
// 窗口过程函数的声明 (LRESULT 是返回值类型,HWND 是窗口句柄等)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // 1. 注册窗口类
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WindowProc;         // 窗口过程函数的地址
    wc.hInstance = hInstance;            // 实例句柄
    wc.lpszClassName = "MyWindowClass";  // 窗口类名
    // 如果注册失败
    if (!RegisterClass(&wc)) {
        MessageBox(NULL, "窗口类注册失败!", "错误", MB_ICONERROR);
        return 1;
    }
    // 2. 创建窗口
    HWND hwnd = CreateWindow(
        "MyWindowClass",    // 窗口类名
        "我的第一个 WinMain 程序", // 窗口标题
        WS_OVERLAPPEDWINDOW, // 窗口样式
        CW_USEDEFAULT, CW_USEDEFAULT, // 初始位置 (x, y)
        500, 300,            // 窗口大小 (width, height)
        NULL,                // 父窗口句柄
        NULL,                // 菜单句柄
        hInstance,           // 实例句柄
        NULL                 // 附加数据
    );
    if (hwnd == NULL) {
        MessageBox(NULL, "窗口创建失败!", "错误", MB_ICONERROR);
        return 1;
    }
    // 3. 显示和更新窗口
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    // 4. 消息循环
    MSG msg = {0};
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg); // 翻译键盘消息
        DispatchMessage(&msg);  // 将消息发送到窗口过程函数
    }
    // 5. 程序结束,返回消息码
    return (int)msg.wParam;
}
// 窗口过程函数:负责处理发送到该窗口的所有消息
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY: // 当窗口被销毁时发送此消息
            PostQuitMessage(0); // 发送一个 WM_QUIT 消息,使 GetMessage 返回 0
            break;
        // 对于其他我们不关心的消息,交给系统默认处理
        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

代码流程解析:

  1. 注册窗口类: 在创建窗口之前,必须先告诉 Windows 你的窗口长什么样、有什么行为。WNDCLASS 结构体就是用来定义这些信息的,最重要的就是 lpfnWndProc,它指定了一个函数地址,所有发给这个窗口的消息(如鼠标点击、键盘按下、窗口移动等)都会由这个函数来处理。
  2. 创建窗口: CreateWindow 函数根据注册的窗口类信息,在内存中创建一个窗口实例,如果成功,它会返回一个窗口句柄 HWND,后续所有对这个窗口的操作(如显示、绘制、销毁)都通过这个句柄来完成。
  3. 显示窗口: ShowWindowUpdateWindow 负责将刚刚创建的窗口真正显示在屏幕上。
  4. 消息循环: 这是 Windows GUI 程序的核心。GetMessage 会一直等待,直到有消息(如鼠标点击、键盘输入)被放入应用程序的消息队列,一旦获取到消息,程序就会通过 TranslateMessageDispatchMessage 将它“派发”到对应的窗口过程函数 (WindowProc) 中进行处理。
  5. 窗口过程: WindowProc 是一个回调函数,由系统调用,它通过 switch 语句判断消息类型并执行相应操作,当用户点击窗口的关闭按钮时,系统会向你的窗口发送一个 WM_DESTROY 消息,在 WM_DESTROY 的处理分支中,我们调用 PostQuitMessage(0),这会向消息队列中放入一个 WM_QUIT 消息,从而使 GetMessage 循环结束,程序退出。

现代开发中的 WinMain

虽然 WinMain 是经典的 Windows 程序入口,但在现代 Windows 开发中,尤其是在使用微软的现代桌面应用程序开发框架时,你可能会看到 main 函数作为入口点。

  • C++/WinRT: 这是微软推荐的用于编写 UWP 和 Windows App SDK 应用的新 C++ 语言投影,它使用标准的 main 函数作为入口点。
  • Windows App SDK (Project Reunion): 同样,它也使用 main 函数。

在这些框架中,main 函数内部会初始化 Windows 运行时环境,然后启动一个类似消息循环的事件泵,并最终调用你的 UI 代码,框架在底层处理了 WinMain 的所有细节,让你可以更专注于业务逻辑。

c语言 winmain
(图片来源网络,侵删)
  • WinMain传统 Windows GUI 应用程序的入口点。
  • 它接收四个特定于 Windows 的参数,用于获取程序实例、命令行和窗口显示方式。
  • 一个典型的 WinMain 程序流程是:注册窗口类 -> 创建窗口 -> 显示窗口 -> 进入消息循环
  • 对于学习 Windows API 的工作原理,WinMain 是一个不可或缺的起点。
  • 在使用现代框架(如 C++/WinRT)时,入口点可能变为标准的 main,但底层机制依然是基于 Windows 消息循环的。
c语言 winmain
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
dede需要php哪个版本?
« 上一篇 04-18
dede网页访问权限如何正确设置?
下一篇 » 04-18

相关文章

取消
微信二维码
支付宝二维码

目录[+]