C++如何创建窗口程序?Windows API永不过时

系统 Windows
当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数( 实际是由插入到可执行文件中的启动代码调用的)。 WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain 函数结束或返回时,Windows应用程序结束。

什么是Windows API编程

  • 应用编程接口
  • Application Programming Interface

WinMain函数

当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数( 实际是由插入到可执行文件中的启动代码调用的)。 WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain 函数结束或返回时,Windows应用程序结束。

int WINAPI WinMain(
    HINSTANCE hInstance,        //应用程序实例
    HINSTANCE hPrevInstance,    //上一个应用程序实例
    LPSTR lpCmdLine,            //命令行参数
    int nShowCmd                //窗口显示的样式
);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • WINAPI:是一个宏,它代表的是__stdcall(注意是两个下划线),表示的是参数传递的顺序:从右往左入栈,同时在函数返回前自动清空堆栈。
  • hInstance:表示该程序当前运行的实例的句柄,这是一个数值。当程序在Windows下运行时,它唯一标识运行中的实例(注意,只有运行中的程序实例, 才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给 WinMain 函数。
  • hPrevInstance:表示当前实例的前一个实例的句柄。在Win32环境下,这个参数总是NULL,即在Win32环境下,这个参数不再起作用。
  • lpCmdLine:是一个以空终止的字符串, 指定传递给应用程序的命令行参数,相当于C或C++中的main函数中的参数char *argv[]
  • nShowCmd:表示一个窗口的显示,表示它是要最大化显示、最小化显示、正常大小显示还是隐藏显示。
#include <Windows.h>
#include <cstdio>
#pragma comment(linker, "/subsystem:\"console\" /entry:\"WinMainCRTStartup\"")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) {

    printf("%p %p %p\n", hInstance, hPrevInstance, GetModuleHandleA(NULL));
    printf("%d %d\n", nCmdShow, SW_SHOWNORMAL);

    printf("%s\n", lpCmdLine);

    MessageBoxA(NULL, TEXT("第一个 Windows API 程序"), TEXT("黑猫编程"), MB_OK);

    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

字符集

#include <Windows.h>
#include <cstdio>
#include <cstring>
#include <clocale>

int main() {

    const char* str1 = "Abc中国";
    printf("%s  %d\n", str1, strlen(str1));

    _wsetlocale(LC_ALL, L"chs");
    const wchar_t* str2 = L"ABC中国文字";
    wprintf(L"%s  %d\n", str2, wcslen(str2));

    MessageBoxW(NULL, TEXT("hello cat."), L"coding", MB_OK);

    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

Windows 编程模型

一个完整的Win32程序(#include <windows.h>),该程序实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

  • WinMain函数的定义
  • 创建一个窗口
  • 进行消息循环
  • 编写窗口过程函数

项目创建

窗口程序模板代码

#include <Windows.h>

// 自定义窗口过程回调函数
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) {

    switch (Msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProcA(hwnd, Msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {

    // 注册窗口类
    WNDCLASS wnd;

    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;

    wnd.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
    wnd.hCursor = LoadIcon(NULL, IDC_ARROW);
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wnd.lpfnWndProc = MyWindowProc;
    wnd.lpszClassName = TEXT("blackcat");
    wnd.lpszMenuName = NULL;
    wnd.style = CS_HREDRAW;
    wnd.hInstance = hInstance;

    RegisterClassA(&wnd);

    // 创建窗口 返回之前发送 VW_CREATE
    HWND hwnd = CreateWindowA(
        TEXT("blackcat"),
        TEXT("黑猫编程"),
        WS_OVERLAPPEDWINDOW,
        100, 100, 300, 300, NULL, NULL, hInstance, NULL
    );

    // 显示窗口
    ShowWindow(hwnd, nShowCmd);

    // 更新窗口
    UpdateWindow(hwnd);

    // 消息循环 收到 VM_QUIT 退出
    MSG msg;
    while (GetMessageA(&msg, hwnd, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }

    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

线程和窗口

在WIN32中,消息队列是与线程(Thread)相关的,一个线程只能有一个消息队列(queue)与之相对应。当一个线程里面首次调用User32.dll或GDI32.dll中的函数时,系统会为该线程创建一个消息队列,否则就没有消息队列。

在一个线程中可以产生多个窗口,所以每个窗口课共用一个线程消息队列,所有产生给某个窗口的消息,都先由创建这个窗口的线程处理,窗口在任何线程中都可以创建,但消息循环必须要和创建窗口在同一线程,否则窗口将无法从DispatchMessage()获取任何消息,为了使窗口接受这些消息,线程必须有自己的循环。

消息分类

  • 标准消息:所有以WM_开头的消息,除了WM_COMMAND
  • 命令消息:来自菜单栏、工具栏、按钮或者快捷键的消息。WM_COMMAND
  • 通告消息:由控件产生的消息,例如按钮单击、列表项的选择等,为了向其父窗口通知事件的发生。

SendMessage和PostMessage

PostThreadMessage


责任编辑:华轩 来源: 今日头条
相关推荐

2020-10-09 11:06:38

C语言桌面语法

2020-02-17 11:35:34

工程师技术程序员

2012-12-10 13:53:55

ITCIOGartner

2021-09-08 09:27:52

软件工程师技能算法

2023-09-27 23:24:50

C++链表

2020-12-11 17:42:13

混合多云

2015-04-27 09:33:02

2010-01-28 10:33:10

C++开发程序

2009-08-14 11:00:16

C#创建Windows

2010-01-25 13:31:27

C++程序

2015-02-04 10:49:13

Visual C++C++Windows API

2009-08-25 09:39:21

创建C# Window

2010-01-28 09:44:08

C++应用程序

2010-01-15 17:18:57

C++源程序

2011-07-20 17:23:29

C++持久对象

2010-01-22 14:28:24

使用C++

2020-05-26 13:25:00

语言编译代码

2010-01-14 11:14:47

C++应用程序

2010-01-25 16:41:08

C++应用程序

2009-08-14 17:27:30

C#Windows应用
点赞
收藏

51CTO技术栈公众号