- 公开视频 -> 链接点击跳转公开课程
- 博客首页 -> 链接点击跳转博客主页
目录
入口函数
窗口注册
窗口创建
窗口显示
窗口更新
消息循环
窗口过程
窗口销毁
调试信息
示例代码
入口函数
- 在Windows应用程序中,
WinMain
是主函数,作为应用程序的入口点。这与许多其他平台上的main
函数类似。 - 函数原型
-
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
- 参数解析
-
HINSTANCE hInstance
:当前实例的句柄(IMAGEBASE)。 -
HINSTANCE hPrevInstance
:在32位Windows应用程序中,这个参数总是为NULL。在早期版本的Windows中,用于标识程序的前一个实例。 -
LPSTR lpCmdLine
:指向一个以null终止的字符串,该字符串包含命令行参数。请注意,它不包含程序的名称。 -
int nCmdShow
:指定窗口如何显示。
-
窗口注册
- 在Windows应用程序中,每个窗口都需要一个窗口类,这个类包含了窗口的属性和一个事件处理函数(窗口过程)。要创建窗口,必须先注册一个窗口类。
- 函数原型
-
ATOM RegisterClassEx(const WNDCLASSEX *lpwcx);
- 参数解析
-
lpwcx
:指向WNDCLASSEX
结构的指针,该结构包含了窗口类的信息。 -
WNDCLASSEX
结构定义了窗口的特征,包括背景颜色、光标、图标、菜单名和窗口过程等。-
cbSize: 指定了结构体的大小,必须设置为
sizeof(WNDCLASSEX)
。 -
style: 类型的风格。可以是任何窗口类风格的组合,比如
CS_HREDRAW
和CS_VREDRAW
。 - lpfnWndProc: 指向窗口过程的指针。这是一个函数指针,指向一个由系统调用以处理窗口消息的函数。
- cbClsExtra: 指定分配给窗口类结构后面的额外字节数。通常这个值设为0。
- cbWndExtra: 指定分配给每个窗口实例的额外字节数。例如,可以使用额外的空间存储一个指向窗口数据的指针。
- hInstance: 一个句柄,标识了包含窗口过程的应用程序实例。
- hIcon: 一个图标的句柄,这是与窗口类关联的图标。
- hCursor: 一个光标的句柄,这是与窗口类关联的光标。
-
hbrBackground: 设置窗口背景色的画刷句柄。可以是一个颜色值的句柄,前面加上
COLOR_
的前缀。 - lpszMenuName: 指向一个以 null 结束的字符串,该字符串指定类菜单,为资源名称。如果使用类菜单,所有由该类创建的窗口都将使用这个菜单。
- lpszClassName: 指向一个以 null 结束的字符串或是一个原子,如果此参数是一个原子,则它必须是一个全局原子。
-
hIconSm: 与窗口类关联的小图标的句柄。如果这个成员是 NULL,系统会从
hIcon
成员指定的大图标中提取一个小图标。
-
cbSize: 指定了结构体的大小,必须设置为
-
窗口创建
- 注册了窗口类之后,可以用
CreateWindowEx
函数创建窗口。 - 函数原型
-
HWND CreateWindowEx( DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );
- 函数参数
- dwExStyle: 扩展窗口样式。这些样式控制各种扩展的窗口特征,例如带有边界阴影的窗口或者无边框的窗口等。
- lpClassName: 注册的窗口类名。这可以是一个指向以 null 结尾的字符串的指针,或一个由
RegisterClassEx
函数返回的原子。 - lpWindowName: 窗口的标题文字。如果窗口是一个控件,这个参数是一个指向以 null 结尾的字符串的指针,表示控件的文本。
- dwStyle: 窗口的风格。这些风格控制着窗口的一般外观和行为。
- X: 窗口创建时水平位置的坐标。如果参数是
CW_USEDEFAULT
,系统会选择窗口的默认位置。 - Y: 窗口创建时垂直位置的坐标。如果参数是
CW_USEDEFAULT
,系统会选择窗口的默认位置。 - nWidth: 窗口的宽度。如果设置为
CW_USEDEFAULT
,系统会选择窗口的默认宽度。 - nHeight: 窗口的高度。如果设置为
CW_USEDEFAULT
,系统会选择窗口的默认高度。 - hWndParent: 父窗口句柄。如果没有父窗口,此参数应为
NULL
。弹出窗口和消息框将使用此参数指定的窗口作为它们的所有者。 - hMenu: 窗口菜单句柄或子窗口标识符。如果是一个子窗口,此参数是一个菜单的句柄;如果是顶层窗口,此参数指定窗口的菜单;如果是子窗口,此参数是子窗口的标识符。
- hInstance: 拥有窗口过程的应用程序的实例句柄。
- lpParam: 指向一个值的指针,该值将被传递给窗口通过
WM_CREATE
消息。如果不需要传递值,此参数可以为NULL
。
窗口显示
-
ShowWindow
函数设置窗口的显示状态。在一个窗口被创建后,它不会自动显示;必须调用此函数来控制窗口的显示。 - 函数原型
-
BOOL ShowWindow( HWND hWnd, int nCmdShow );
- 函数参数
-
hWnd
:窗口句柄,标识要设置显示状态的窗口。 -
nCmdShow
:指定窗口如何被显示。常用参数包括:-
SW_SHOW
:显示窗口。 -
SW_HIDE
:隐藏窗口,活动状态给另一个窗口。 -
SW_MINIMIZE
:最小化窗口,活动状态给另一个窗口。 -
SW_RESTORE
:激活并显示窗口。如果窗口最小化或最大化,系统会将其恢复到原始尺寸和位置。 -
SW_SHOWMAXIMIZED
:激活窗口并将其最大化。 -
SW_SHOWMINIMIZED
:激活窗口并将其最小化。 -
SW_SHOWMINNOACTIVE
:窗口最小化,类似SW_SHOWMINIMIZED
,但窗口不被激活。
-
-
窗口更新
-
UpdateWindow
函数用于更新客户区的无效区域,即发送一个WM_PAINT
消息给窗口过程,如果客户区没有无效区域,则不发送消息。 - 函数原型
-
BOOL UpdateWindow( HWND hWnd );
- 函数参数
-
hWnd
:窗口句柄,标识要更新的窗口。 - 该函数通常在
ShowWindow
后调用,以便立即更新窗口的客户区而无需等待WM_PAINT
消息的正常排队。
-
消息循环
- Windows应用程序是事件驱动的。在
WinMain
中,程序必须不断检查和处理消息。这就是所谓的消息循环或消息处理机制。每个GUI应用程序都有一个消息队列,Windows操作系统使用它来存储对该应用程序的所有输入(如鼠标点击、键盘输入等)。 - 示例代码
-
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
- 函数解析
-
GetMessage
从消息队列检索消息。如果没有消息,它会等待,直到有消息为止。如果返回0,意味着接收到WM_QUIT消息,循环会结束。 -
TranslateMessage
将虚拟键消息转换为字符消息。 -
DispatchMessage
将消息发送到窗口程序。
-
窗口过程
- 窗口过程是一个函数,它处理发送到窗口的消息。每个窗口都有一个与之关联的窗口过程。当事件发生(比如用户点击按钮),Windows会将相应的消息发送到窗口过程。窗口过程根据消息的类型执行相应的操作,并返回结果。
-
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
HWND hwnd
: 窗口的句柄。 -
UINT uMsg
: 消息的标识。 -
WPARAM wParam
: 消息特定的附加信息。 -
LPARAM lParam
: 消息特定的附加信息。 -
// 实现窗口过程函数 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hwnd, uMsg, wParam, lParam); }
-
窗口销毁
- 窗口的销毁 通常通过调用
DestroyWindow
函数来完成。当窗口被销毁后,Windows会发送WM_DESTROY
消息给窗口过程,窗口过程可以在接收到此消息时执行清理操作。
调试信息
-
OutputDebugStringA
函数是 Windows API 中的一个函数,它用于将一个字符串输出到调试器。
#include <windows.h>
#include <stdio.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
char buffer[256];
int value1 = 42;
int value2 = 100;
// 使用 sprintf 格式化字符串
sprintf_s(buffer, sizeof(buffer), "Value 1: %d, Value 2: %d\n", value1, value2);
// 输出格式化后的字符串到调试器
OutputDebugStringA(buffer);
return 0;
}
示例代码
#include <Windows.h>
LRESULT CALLBACK MainWindowProc (HWND, UINT, WPARAM, LPARAM);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// 注册窗口
WNDCLASSEX wndclass = { 0 };
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = NULL;
wndclass.lpfnWndProc = MainWindowProc;
wndclass.cbClsExtra = NULL;
wndclass.cbWndExtra = NULL;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TEXT("0xCC");
wndclass.hIconSm = NULL;
if (!RegisterClassEx(&wndclass))
{
MessageBox(NULL, TEXT("RegisterClassEx Failed"), TEXT("Error"), MB_OK);
return 1;
}
// 创建窗口
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
TEXT("0xCC"),
TEXT("CreateWindowEx"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
960,
540,
NULL,
NULL,
hInstance,
NULL
);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("CreateWindowEx Failed"), TEXT("Error"), MB_OK);
return 1;
}
// 显示窗口
ShowWindow(hwnd, SW_SHOWDEFAULT);
// 更新窗口
UpdateWindow(hwnd);
// 消息处理
MSG msg = { 0 };
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// 窗口过程
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
MoveWindow(hwnd, 0, 0, 500, 500, FALSE);
CREATESTRUCT* Cs = (CREATESTRUCT*)lParam;
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_SIZE:
{
TCHAR szBuffer[0xFF] = { 0 };
wsprintf(szBuffer, TEXT("WM_SIZE -> %d %d\r\n"), HIWORD(lParam), LOWORD(lParam));
OutputDebugString(szBuffer);
break;
}
case WM_MOVE:
{
TCHAR szBuffer[0xFF] = { 0 };
wsprintf(szBuffer, TEXT("WM_MOVE -> %d %d\r\n"), HIWORD(lParam), LOWORD(lParam));
OutputDebugString(szBuffer);
break;
}
case WM_LBUTTONDOWN:
{
TCHAR szBuffer[0xFF] = { 0 };
wsprintf(szBuffer, TEXT("WM_LBUTTONDOWN -> %d %d\r\n"), HIWORD(lParam), LOWORD(lParam));
OutputDebugString(szBuffer);
break;
}
case WM_KEYDOWN:
{
TCHAR szBuffer[0xFF] = { 0 };
wsprintf(szBuffer, TEXT("WM_KEYDOWN -> %d\r\n"), wParam);
OutputDebugString(szBuffer);
break;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}