窗口创建的六要素:
- 设计注册窗口类
- 创建窗口实例
- 显示窗口
- 更新窗口
- 消息循环
- 窗口过程函数
设计注册窗口类
typedef struct _WNDCLASS {
UINT style; //风格
WNDPROC lpfnWndProc; //函数过程
int cbClsExtra; //默认为0
int cbWndExtra; //默认为0
HINSTANCE hInstance; //实例句柄
HICON hIcon; //图标
HCURSOR hCursor; //光标
HBRUSH hbrBackground; //背景
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
#include <Windows.h>
void ShowError();
LRESULT CALLBACK WndProc
(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
return 1;
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
//设计注册窗口类函数
WNDCLASS wc = { };
wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
wc.lpfnWndProc = WndProc;//窗口过程函数
wc.cbClsExtra = 0;//默认给0
wc.cbWndExtra = 0;//默认给0
wc.hInstance = hInstance;//实例句柄
wc.hIcon = NULL;//图标
wc.hCursor = NULL;//光标
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
wc.lpszMenuName = NULL;//菜单
wc.lpszClassName = "窗口";//窗口类名
if (!RegisterClass(&wc))
{
MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
}
if (!RegisterClass(&wc))
{
DWORD nRet = GetLastError();
ShowError();
}
return 0;
}
void ShowError()
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}
总结:风格、标志用位运算存储
创建窗口实例
HWND CreateWindow(
LPCTSTR lpClassName, // registered class name
LPCTSTR lpWindowName, // window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // menu handle or child identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // window-creation data
);
#include <Windows.h>
void ShowError();
LRESULT CALLBACK WndProc
(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
return 1;
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
//设计注册窗口类函数
WNDCLASS wc = { };
wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
wc.lpfnWndProc = WndProc;//窗口过程函数
wc.cbClsExtra = 0;//默认给0
wc.cbWndExtra = 0;//默认给0
wc.hInstance = hInstance;//实例句柄
wc.hIcon = NULL;//图标
wc.hCursor = NULL;//光标
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
wc.lpszMenuName = NULL;//菜单
wc.lpszClassName = "窗口";//窗口类名
if (!RegisterClass(&wc))
{
MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
}
/*if (!RegisterClass(&wc))
{
DWORD nRet = GetLastError();
ShowError();
}*/
//2、创建窗口实例
HWND hWnd = CreateWindow("窗口", // 窗口类类名
"第一个窗口", // 窗口标题
WS_OVERLAPPEDWINDOW,//重叠窗口、带标题、系统菜单
CW_USEDEFAULT,//默认位置
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,//父窗口
NULL,//菜单
hInstance,//实例句柄
NULL //消息参数
);
if (hWnd == NULL)
{
ShowError();
return 0;
}
return 0;
}
void ShowError()
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}
显示窗口
BOOL ShowWindow( HWND hWnd, // handle to window
int nCmdShow // show state);
更新窗口
BOOL UpdateWindow( HWND hWnd // handle to window);
消息循环
消息和消息队列
1、消息
在Windows中,不仅用户程序可以调用系统的API函数,反过来,系统也会调用用户程序,这个调用是通过消息来进行的。将响应的事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。这个处理的过程就是操作系统调用程序中一个专门负责处理消息的函数,这个函数就称为窗口过程函数。
BOOL GetMessage(
LPMSG lpMsg, // message information
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message);
消息是由MSG结构体来表示的
typedef struct tagMSG {
HWND hwnd; //标识窗口
UINT message; //消息的标识符 例如:WM_KEYDOWN
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
wParam和lParam 用于指定消息的附加消息。
time 和 pt表示消息投递到消息队列中的时间和鼠标的当前位置。
2、消息队列
当一个Windows程序执行时,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建窗口的消息。Windows将产生的消息依次放到消息队列中,应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。
3、进队消息和不进队消息
进队消息将由系统放入应用程序的消息队列中,由应用程序取出并发送。不进队的消息在系统调用窗口过程时直接发送给窗口。不管是进队消息还是不进队消息,最终都由系统调用窗口过程函数对消息队列进行处理。
LRESULT DefWindowProc( HWND hWnd, // handle to window
UINT Msg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter);
LRESULT DispatchMessage( CONST MSG *lpmsg // message information);
VOID PostQuitMessage( int nExitCode // exit code);
窗口过程函数
LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter);
WM_DESTROY消息是在窗口被销毁时发送的。 在窗口从屏幕上删除后,它被发送到正在被销毁的窗口的窗口过程。
此消息首先发送到被销毁的窗口,然后发送到被销毁的子窗口(如果有的话)。 在处理消息期间,可以假定所有子窗口仍然存在。
LRESULT CALLBACK WndProc
(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (uMsg)
{
case WM_DESTROY: //销毁窗口的消息
PostQuitMessage(0);//退出消息循环
break;
default:
break;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
实例总代码:
#include <Windows.h>
void ShowError();
LRESULT CALLBACK WndProc
(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (uMsg)
{
case WM_DESTROY: //销毁窗口的消息
PostQuitMessage(0);//退出消息循环
break;
default:
break;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
//设计注册窗口类函数
WNDCLASS wc = { };
wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
wc.lpfnWndProc = WndProc;//窗口过程函数
wc.cbClsExtra = 0;//默认给0
wc.cbWndExtra = 0;//默认给0
wc.hInstance = hInstance;//实例句柄
wc.hIcon = NULL;//图标
wc.hCursor = NULL;//光标
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
wc.lpszMenuName = NULL;//菜单
wc.lpszClassName = "窗口";//窗口类名
if (!RegisterClass(&wc))
{
MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
}
/*if (!RegisterClass(&wc))
{
DWORD nRet = GetLastError();
ShowError();
}*/
//2、创建窗口实例
HWND hWnd = CreateWindow("窗口", // 窗口类类名
"第一个窗口", // 窗口标题
WS_OVERLAPPEDWINDOW,//重叠窗口、带标题、系统菜单 WS_VISIBLE显示窗口
CW_USEDEFAULT,//默认位置
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,//父窗口
NULL,//菜单
hInstance,//实例句柄
NULL //消息参数
);
if (hWnd == NULL)
{
ShowError();
return 0;
}
//显示窗口
ShowWindow(hWnd, SW_SHOW);
//更新窗口
UpdateWindow(hWnd ); //立即绘制
//消息循环
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return 0;
}
void ShowError()
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}
窗口销毁
LRESULT CALLBACK WndProc
(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (uMsg)
{
case WM_DESTROY: //销毁窗口的消息
PostQuitMessage(0);//退出消息循环
return 0;
case WM_CLOSE:
int Ret = MessageBox(hwnd, "是否确认退出", "提示", MB_YESNO);
switch (Ret)
{
case IDYES:
DestroyWindow(hwnd);
break;
case IDNO:
break;
}
return 0;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
鼠标消息
当用户按下鼠标左键而光标位于窗口的客户端区域时,WM_LBUTTONDOWN消息被发布。 如果鼠标未被捕获,则消息将被发送到光标下方的窗口。 否则,消息将被发送到捕获鼠标的窗口。
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
WORD nX = LOWORD(lParam);
WORD nY = HIWORD(lParam);
键盘消息:
当按下非系统键时,WM_KEYDOWN消息被发送到带有键盘焦点的窗口。 非系统键是指未按下ALT键时按下的键。
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_KEYDOWN
WPARAM wParam, // virtual-key code
LPARAM lParam // key data
);
只能显示大写字母,使用WM_CHAR可转化大写
当WM_KEYDOWN消息被TranslateMessage函数翻译时,WM_CHAR消息被发送到带有键盘焦点的窗口。 WM_CHAR消息包含被按下的键的字符代码。
BOOL TranslateMessage(
CONST MSG *lpMsg // message information
);
TranslateMessage(&msg);
实列代码
HINSTANCE hinst;
HWND hwndMain;
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
BOOL bRet;
WNDCLASS wc;
UNREFERENCED_PARAMETER(lpszCmdLine);
// Register the window class for the main window.
if (!hPrevInstance)
{
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon((HINSTANCE) NULL,
IDI_APPLICATION);
wc.hCursor = LoadCursor((HINSTANCE) NULL,
IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWndClass";
if (!RegisterClass(&wc))
return FALSE;
}
hinst = hInstance; // save instance handle
// Create the main window.
hwndMain = CreateWindow("MainWndClass", "Sample",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL,
(HMENU) NULL, hinst, (LPVOID) NULL);
// If the main window cannot be created, terminate
// the application.
if (!hwndMain)
return FALSE;
// Show the window and paint its contents.
ShowWindow(hwndMain, nCmdShow);
UpdateWindow(hwndMain);
// Start the message loop.
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Return the exit code to the system.
return msg.wParam;
}
总代码:
#include <Windows.h>
void ShowError();
LRESULT CALLBACK WndProc
(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (uMsg)
{
case WM_CHAR:
{
char szBuff[MAXBYTE] = {};
wsprintf(szBuff, "虚拟码:%d 字符:%c ", wParam, wParam);
MessageBox(hwnd, szBuff, "WM_CHAR", MB_OK);
return 0;
}
/*case WM_KEYDOWN:
{
char szBuff[MAXBYTE] = {};
wsprintf(szBuff, "虚拟码:%d 字符:%c ", wParam, wParam);
MessageBox(hwnd, szBuff, "WM_KEYDOWN", MB_OK);
return 0;
}*/
case WM_LBUTTONDOWN:
{
WORD nX = LOWORD(lParam);
WORD nY = HIWORD(lParam);
char szBuff[MAXBYTE] = {};
wsprintf(szBuff, "x:%d y:%d ", nX, nY);
MessageBox(hwnd, szBuff, "鼠标坐标", MB_OK);
return 0;
}
case WM_DESTROY: //销毁窗口的消息
{
PostQuitMessage(0);//退出消息循环
return 0;
}
case WM_CLOSE:
{
int Ret = MessageBox(hwnd, "是否确认退出", "提示", MB_YESNO);
switch (Ret)
{
case IDYES:
{
DestroyWindow(hwnd);
break;
}
case IDNO:
{
break;
}
}
return 0;
}
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
//设计注册窗口类函数
WNDCLASS wc = { };
wc.style = CS_VREDRAW | CS_HREDRAW;//默认,当尺寸修改时,通知函数
wc.lpfnWndProc = WndProc;//窗口过程函数
wc.cbClsExtra = 0;//默认给0
wc.cbWndExtra = 0;//默认给0
wc.hInstance = hInstance;//实例句柄
wc.hIcon = NULL;//图标
wc.hCursor = NULL;//光标
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//背景色
wc.lpszMenuName = NULL;//菜单
wc.lpszClassName = "窗口";//窗口类名
if (!RegisterClass(&wc))
{
MessageBox(NULL, "注册窗口失败", "提示", MB_OK);
}
/*if (!RegisterClass(&wc))
{
DWORD nRet = GetLastError();
ShowError();
}*/
//2、创建窗口实例
HWND hWnd = CreateWindow("窗口", // 窗口类类名
"第一个窗口", // 窗口标题
WS_OVERLAPPEDWINDOW,//重叠窗口、带标题、系统菜单 WS_VISIBLE显示窗口
CW_USEDEFAULT,//默认位置
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,//父窗口
NULL,//菜单
hInstance,//实例句柄
NULL //消息参数
);
if (hWnd == NULL)
{
ShowError();
return 0;
}
//显示窗口
ShowWindow(hWnd, SW_SHOW);
//更新窗口
UpdateWindow(hWnd ); //立即绘制
//消息循环
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
void ShowError()
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}