一个完整的Windows程序结构
需要注意几点:
1.win32项目
2.文件格式为.c,不是.cpp
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//窗口过程
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
//windows给我们提供了一个窗口类(WNDCLASS),所以我们直接用它
//先定义一个窗口类对象
WNDCLASS m_wndClass;
HWND m_hwnd;//窗口句柄
MSG m_msg; //消息
static TCHAR szClassName[] = TEXT("TyWin"); //窗口类名
//定义好了肯定就进行初始化,给它一些值
m_wndClass.style = CS_HREDRAW | CS_VREDRAW; //窗口风格,一般也就使用这两个
//表示当窗口大小改变时重绘窗口,这样才能保证文字始终处于窗口中间
m_wndClass.lpszClassName = TEXT("TyWin");//窗口类名
m_wndClass.cbClsExtra = 0; //暂时不需要理解
m_wndClass.cbWndExtra = 0; //暂时不需要理解
m_wndClass.hInstance = hInstance; //当前窗口句柄
m_wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //窗口图标
m_wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); //鼠标样式
m_wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //窗口背景画刷
m_wndClass.lpszMenuName = NULL; //窗口菜单
m_wndClass.lpfnWndProc = WndProc; //窗口过程
/**********第1步:注册窗口类**********/
//注册窗口
RegisterClass(&m_wndClass);
/*****第2步:创建窗口(并让窗口显示出来)*****/
m_hwnd = CreateWindow(szClassName, TEXT("Ty"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, 0);
/**********第3步:显示窗口**********/
ShowWindow(m_hwnd, SW_SHOW);
/**********第4步:更新(绘制)窗口**********/
UpdateWindow(m_hwnd);
/**********第5步:消息循环**********/
while (GetMessage(&m_msg, NULL, 0, 0)){
TranslateMessage(&m_msg); //翻译消息
DispatchMessage(&m_msg); //分派消息
}
return m_msg.wParam;
}
/**********第6步:窗口过程**********/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
HDC hdc; //设备环境句柄
PAINTSTRUCT ps;
RECT rect;
switch (message){
//窗口绘制消息
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(
hdc,
TEXT("你好,这是第二个窗口!"),
-1,
&rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER
);
EndPaint(hwnd, &ps);
return 0;
//窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
结果:
这里重点提一下窗口过程:
所谓窗口过程,就是处理窗口事件的函数,也就是上面代码中最后的 WndProc 函数。GetMessage 每获取到一条消息,最终都会丢给窗口过程去处理。
窗口过程有一个参数 message,会传入发生的事件类型,常用的有:
WM_CREATE:窗口被创建。
WM_PAINT:窗口需要更新或重绘。
WM_WM_DESTROY:窗口被销毁(关闭)。
WM_CREATE 和 WM_DESTROY 很容易理解,WM_PAINT 将在下节中详细讲解,它非常重要,不理解 WM_PAINT 可以说就没有学会Windows编程。
不同的消息往往需要进行不同的处理,所以一般通过 switch case 语句来匹配。
注意:你可以对获取到的消息进行处理,加入自己的业务逻辑;也可以不处理,让Windows自己看着办(默认处理方式)。窗口过程最后一条语句:
return DefWindowProc(hwnd, message, wParam, lParam) ;
它的作用就是让Windows自己处理应用程序没有处理的消息,必须要有该语句。
窗口过程在窗口类中指明,然后就不用管了,不需要我们显式调用。
另外,还有
/**********第5步:消息循环**********/
while (GetMessage(&m_msg, NULL, 0, 0)){
TranslateMessage(&m_msg); //翻译消息
DispatchMessage(&m_msg); //分派消息
}
GetMessage 函数用来从消息队列中获取一条消息,并保存到 MSG 结构体变量中。
获取到消息后,需要调用 TranslateMessage 函数对消息进行转换(翻译),然后再调用 DispatchMessage 函数将消息传给窗口过程去处理(调用窗口过程)。
请参考我的这篇文章操作系统-消息、消息队列