当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 //窗口显示的样式
);
- 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
