附加数据的作用:
注册窗口时,设置这两个数据的大小,可以提供窗口类和窗口存放自己的数据的空间。
1.窗口类附加数据
int cbClsExtra //窗口类附加数据buff大小
(1)用法:
a.申请缓冲区
窗口对象.cbClsExtra = 200; //一般赋4的倍数
b.写入数据
DWORD SetClassLong ( HWND hWnd, //窗口句柄
int nIndex, //字节索引号(从哪个字节开始存)
LONG dwNewLong); //存入的数据
c.读取数据
DWORD GetClassLong ( HWND hWnd, //窗口句柄
int nIndex); //字节索引号(从哪个字节开始读)
//返回值获取读到的数据
2.窗口附加数据缓冲区
int cbWndExtra //窗口附加数据buff大小
(1)用法:
a.申请缓冲区
窗口对象.cbWndExtra = 200; //一般是4的倍数
b.写入数据
LONG SetWindowLong ( HWND hWnd, //窗口句柄
int nIndex, //字节索引号(从哪个字节开始存)
LONG dwNewLong); //写入的数据
c.读取数据
LONG GetWindowLong ( HWND hWnd, //窗口句柄
int nIndex); //字节索引号(从哪个字节开始读)
//返回值是读到的数据
3.区别
窗口类附加数据缓冲区:是所有基于该窗口类创建出来的窗口共享的缓冲区。
窗口附加数据缓冲区:是窗口自己私有的缓冲区,即便是基于同一个窗口类创建出来的窗口,相互之间也不共享。
下面是示例代码:
#include "stdafx.h" #include "stdio.h" HINSTANCE g_hInstance = 0; //接收当前程序实例句柄 //窗口处理函数 //CALLBACK即回调,我们定义函数我们不调用,操作系统调用,仅限windows系统 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); //能够使GetMessage返回0 break; } return DefWindowProc(hWnd, msg, wParam, lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName, WNDPROC wndProc) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra = 200; wce.cbClsExtra = 200; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndProc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if (0 == nAtom) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMainWindow(LPSTR lpClassName, LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL); return hWnd; } //创建子窗口 HWND CreateChildWindow(LPSTR lpClassName, LPSTR lpWndName, HWND hParent) { HWND hChild = CreateWindowEx(0, lpClassName, lpWndName, WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, hParent, NULL, g_hInstance, NULL); return hChild; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = { 0 }; while (GetMessage(&nMsg, NULL, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } } //写入数据 void SetExtra(HWND hWnd) { char* pszText = "Hello Data"; SetClassLong(hWnd, 196, (LONG)pszText); SetWindowLong(hWnd, 0, 100); } //读取数据 void GetExtra(HWND hWnd) { LONG nClass = GetClassLong(hWnd, 196); LONG nWnd = GetWindowLong(hWnd, 0); char szText[256] = { 0 }; sprintf_s(szText, "窗口类:%s, 窗口:%d", nClass, nWnd); MessageBox(NULL, szText, "Info", MB_OK); } //APIENTRY也是回调函数,APIENTRY和CALLBACK一样,都是__stdcall的别名 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance; BOOL nBool = Register("Main", WndProc); if (nBool == FALSE) { MessageBox(NULL, "注册失败", "Info", MB_OK); } HWND hWnd = CreateMainWindow("Main", "window"); Display(hWnd); BOOL nChild = Register("Child", DefWindowProc); if (nChild == FALSE) { MessageBox(NULL, "注册失败", "Info", MB_OK); } HWND hChild1 = CreateChildWindow("Child", "c1", hWnd); HWND hChild2 = CreateChildWindow("Child", "c2", hWnd); MoveWindow(hChild1, 300, 100, 200, 200, TRUE); MoveWindow(hChild2, 500, 100, 200, 200, TRUE); Display(hChild1); Display(hChild2); SetExtra(hChild1); GetExtra(hChild2); Message(); return 0; }
运行结果:
到此为止,窗口的创建已经基本结束
4.简单的说一下ShowWindow
在这个函数的内部,我们可以猜想处理过程:
通过传入的hWnd,找到保存窗口数据的那块内存,然后再根据内存中的数据绘制窗口图像(往显存中写数据)。