一、窗口结构体WNCLASS
这个结构体存储的是一些关于窗口类信息的结构,
成员如下:
typedef struct tagWNDCLASSA {
UINT style;//窗口类型
WNDPROC lpfnWndProc;//窗口处理函数(回调函数)
int cbClsExtra;//窗口扩展(一般为0)
int cbWndExtra;//窗口实例扩展(一般为0)
HINSTANCE hInstance;//实例句柄
HICON hIcon;//窗口的最小化图标
HCURSOR hCursor;//窗口鼠标光标
HBRUSH hbrBackground;//窗口背景颜色
LPCSTR lpszMenuName;//窗口菜单
LPCSTR lpszClassName;//窗口类名
} WNDCLASSA, *PWNDCLASSA, *NPWNDCLASSA, *LPWNDCLASSA;
类风格 | 含义 |
CS_VREDRAW | 移动或者调整窗口的高度(垂直方向)时,重绘整个窗口 |
CS_HREDRAW | 移动或者调整窗口的宽度(水平方向)时,重绘整个窗口 |
CS_DBLCLKS | 当用户光标在窗口内双击时,允许发送双击消息给窗口过程 |
CS_OWNDC | 给予每个窗口实例分配一个唯一的 DC(注意,尽管这样是很方便,但它必须慎重使用,因为每个 DC 大约要占 800 个字节的内存) |
CS_CLASSDC | 该窗口类的所有窗口实例都共享一个窗口类 DC |
CS_PARENTDC | 1. 将子窗口的裁剪区域设置到父窗口的 DC 中去,这样子窗口便可以在父窗口上绘制自身。(注意,这是子窗口还是从系统缓存中获取 DC,而不是使用父窗口的 DC。) 2. 指定该风格可以提高系统性能 |
CS_NOCLOSE | 禁止系统菜单的关闭选项 |
CS_SAVEBITS | 1. 以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息 2. 该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失 3. 设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存 |
CS_BYTEALIGNCLIENT | 在字节边界上(在 x 方向上)定位窗口的用户区域的位置 |
CS_BYTEALIGNWINDOW | 在字节边界上(在 x 方向上)定位窗口的位置 |
CS_GLOBALCLASS | 1. 当调用 CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的 hInstance 参数和注册窗口类时传递给 RegisterClass 的 hInstance 参数不同 2. 如果不指定该风格,则这两个 hInstance 必须相同 |
下面是我自己在程序中对窗口类信息结构体的填充,可以当做参考:
// WNDCCASS :窗口类,用来处理窗口的某一类信息
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
// 回调函数
wc.lpfnWndProc = (WNDPROC)d3d::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
// 函数传进来的窗口的句柄
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "DX9App";
二、对相关窗口进行注册
我们使用RegidsterClass函数对我们刚才填充的窗口结构进行注
// 将窗口的信息填充完成之后,使用该函数,对窗口进行注册
if (!RegisterClass(&wc))
{
::MessageBox(0, "RegisterClass() - FAILED", 0, 0);
return false;
}
三、注册完成之后,我们就要开始利用现有的属性进行窗口的创建,使用函数:CreateWindow
函数原型:
HWND CreateWindow(
LPCTSTR lpClassName,//窗口类的名称
LPCTSTR lpWindowName,//窗口的标题
DWORD dwStyle,//窗口风格
int x,//初始x坐标
int y,//初始y坐标
int nWidth,//初始x方向的尺寸
int nHeight,//初始y方向的尺寸
HWND hWndParent,//父窗口句柄
HMENU hMenu,//窗口菜单句柄
HANDLE hlnstance,//程序实例句柄
LPVOID lpParam//创建参数
)
参数 |
含义 |
lpClassName |
1. 窗口类名称,可以是一个指向 NULL 结束的字符串或一个整型数值 |
lpWindowName |
1. 窗口标题,一个指向 NULL 结束的字符串指针 |
dwStyle |
指定创建窗口的风格(可选值见下一个表格) |
x |
1. 指定窗口的初始水平位置(x 坐标) |
y |
1. 指定窗口的初始垂直位置(y 坐标) |
nWidth |
1. 以设备单元指明窗口的宽度 |
nHeight |
1. 以设备单元指明窗口的高度 |
hWndParent |
1. 指向被创建窗口的父窗口或所有者窗口的句柄 |
hMenu |
1. 指向窗口菜单句柄,或依据窗口风格指明一个子窗口标识 |
hInstance |
与窗口相关联的模块实例的句柄 |
lpParam |
1. 指向一个值的指针,该值传递给窗口 WM_CREATE 消息。该值通过在 IParam 参数中的 CREATESTRUCT 结构传递 |
dwStyle可选值:
窗口风格 |
含义 |
WS_BORDER |
创建一个带边框的窗口 |
WS_CAPTION |
创建一个有标题框的窗口(包含了 WS_BODER 风格) |
WS_CHILD |
创建一个子窗口,这个风格的窗口不能拥有菜单也不能与 WS_POPUP 风格合用 |
WS_CHILDWINDOW |
与 WS_CHILD 相同 |
WS_CLIPCHILDREN |
当在父窗口内绘图时,排除子窗口区域,在创建父窗口时使用这个风格 |
WS_CLIPSIBLINGS |
1. 排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到 WM_PAINT 消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口 |
WS_DISABLED |
1. 创建一个初始状态为禁止的子窗口,一个禁止状态的窗口不能接受来自用户的输入信息 |
WS_DLGFRAME |
创建一个带对话框边框风格的窗口,这种风格的窗口不能带标题条 |
WS_GROUP |
1. 指定一组“控制窗口”的第一个“控制窗口” |
WS_HSCROLL |
创建一个有水平滚动条的窗口 |
WS_ICONIC |
创建一个初始状态为最小化状态的窗口,与 WS_MINIMIZE 风格相同 |
WS_MAXIMIZE |
创建一个初始状态为最大化状态的窗口 |
WS_MAXIMIZEBOX |
创建一个具有最大化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格 |
WS_MINIMIZE |
创建一个初始状态为最小化状态的窗口,与 WS_ICONIC 风格相同 |
WS_MINIMIZEBOX |
创建一个具有最小化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格 |
WS_OVERLAPPED |
产生一个层叠的窗口,一个层叠的窗口有一个标题条和一个边框,与 WS_TILED 风格相同 |
WS_OVERLAPPEDWINDOW |
相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_TILEDWINDOW 风格相同 |
WS_POPUP |
创建一个弹出式窗口,该风格不能与 WS_CHILD 风格同时使用。 |
WS_POPUPWINDOW |
相当于(WS_POPUP | WS_BORDER | WS_SYSMENU),但 WS_CAPTION 和 WS_POPUPWINDOW 必须同时设定才能使窗口某单可见 |
WS_SIZEBOX |
创建一个可调边框的窗口,与 WS_THICKFRAME 风格相同 |
WS_SYSMENU |
创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格 |
WS_TABSTOP |
1. 创建一个“控制窗口”,在用户按下 Tab 键时可以获得键盘焦点。 |
WS_THICKFRAME |
创建一个具有可调边框的窗口,与 WS_SIZEBOX 风格相同 |
WS_TILED |
产生一个层叠的窗口,一个层叠的窗口有一个标题和一个边框,与 WS_OVERLAPPED 风格相同 |
WS_TILEDWINDOW |
相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_OVERLAPPEDWINDOW 风格相同 |
WS_VISIBLE |
创建一个初始状态为可见的窗口 |
WS_VSCROLL |
创建一个有垂直滚动条的窗口 |
该函数成功则返回新的窗口句柄,失败,则返回空。
实例:
hwnd = ::CreateWindow("DX9App", "DX9App",
WS_EX_TOPMOST,
0, 0, width, height,
0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);
// 判断一下这个创建是不是成功
if (!hwnd)
{
::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
return false;
}
四、创建完成之后,就开始展示窗口,使用函数:ShowWindow
函数声明如下:
BOOL ShowWindow(HWND hWnd, int nCmdShow);
第一个参数是窗口的句柄,第二个参数是窗口展示的类型,可选值如下:
值 | 含义 |
SW_FORCEMINIMIZE | 强制窗口最小化,主要使用在非窗口主线程的其它线程来操作 |
SW_HIDE | 显示窗口为隐藏状态 |
SW_MAXIMIZE | 显示窗口为最大化 |
SW_MINIMIZE | 显示窗口为最小化 |
SW_RESTORE | 从任务里恢复窗口显示 |
SW_SHOW | 激活窗口为当前窗口,并且显示为当前的大小和位置 |
SW_SHOWDEFAULT | 创建进程时显示窗口的值 |
SW_SHOWMAXIMIZED | 激活窗口为当前窗口,并且显示最大化 |
SW_SHOWMINIMIZED | 激活窗口为当前窗口,并且显示最小化 |
SW_SHOWMINNOACTIVE | 显示窗口为最小化,但不激活它作为当前窗口v |
SW_SHOWNA | 显示为当前的大小和位置,但不激活它作为当前窗口显示为当前的大小和位置,但不激活它作为当前窗口 |
SW_SHOWNOACTIVATE | 显示当前窗口,但不激活它作为当前窗口 |
SW_SHOWNORMAL | 显示当前窗口,但窗口是最小化或最大化时会恢复窗口为原来的大小和位 |
五、UpdateWindow函数,更新窗口
函数原型:
BOOL UpdateWindow(HWND hWnd // 窗口的句柄);
一般在创建窗口之后,调用ShowWindow,然后就会使用该函数进行窗口的更新。
PS:但是在我自己的程序中使用与否感觉差别不大,估计是没有搞清楚这个函数的实现机制到底是什么~
六、MSG结构体
typedef struct tagMSG{
HWND hwnd; //窗口句柄
UINT message; //消息类型
WPARAM wParam; //附加消息1
LPARAM lParam; //附加消息2
DWORD time; //消息被传递时候的时间
POINT pt; //消息被传递时光标在屏幕上的位置
} MSG;
1) 最后两个字段 time 和 pt 一般由系统使用,我们很少用到。
2) message 为消息类型,也就是以 WM 开头的消息(WM 是 Window Message 的缩写 ),例如 WM_CREATE、WM_PAINT、WM_DESTROY、WM_COMMAND 等。
3)至于wParam和lParam,MSDN上给的解释,两个参数是完全一样的
查了一些资料,我的理解是如果是自己定义的message的类型,那么怎么填写wParam和lParam就怎么取message,如果使用的是系统message类型,那么每一个系统的message类型都会有自己对应的wParam和lParam,此时找出来,填充即可,不过我感觉大多数系统的message类型的已经够用。
七、PeekMessage、TranslateMessage、DispatchMessage
BOOL PeekMessage(
LPMSG lpMsg,//
HWND hWnd,//
UINT wMsgFilterMin,//
UINT wMsgFilterMax,//
UINT wRemoveMsg//
);
参数说明:
lpMsg:指向一个MSG结构的指针,该结构中保存着从线程消息队列中取得的消息信息。
hWnd:被测试消息的相关窗口句柄。该窗口必须属于正在调用的线程。
如果hWnd值为NULL:PeekMessage检索任何属于调用线程窗口的消息。如果hWnd的值为INVALID_HANDLE_VALUE,PeekMessage会检索那些hWnd值为NULL的消息,并作为由PostThreadMessage投递的消息来对待。
wMsgFilterMin:指定被检索的最小消息值的整数。使用WM_KEYFIRST指定第一个键盘消息或WM_MOUSEFIRST指定第一个鼠标消息。
wMsgFilterMax:指定被检索的最大消息值的整数。使用WM_KEYLAST指定最后的键盘消息或WM_MOUSEFIRST指定最后的鼠标消息。
wRemoveMsg:指定消息的处理方式。该参数的值可以为下列的值之一。
值 | 含义 |
PM_NOREMOVE | 消息经PeekMessage处理后并不从消息队列中移除。 |
PM_REMOVE | 消息经PeekMessage处理后从消息队列中移除 |
PM_QS_INPUT | Windows 98/Me,Windows 2000/XP: 处理鼠标和键盘消息。 |
PM_QS_PAINT | Windows 98/Me,Windows 2000/XP:处理绘图消息。 |
PM_QS_POSTMESSAGE | Windows 98/Me,Windows 2000/XP:处理所有投递消息,包括定时器和热键消息 |
PM_QS_SENDMESSAGE | Windows 98/Me,Windows 2000/XP: 处理所有发送消息。 |
返回值:
如果有可用的消息,则返回值为非0;
如果没有可用的消息,则返回值为0;
BOOL TranslateMessage( CONST MSG*lpMsg );
参数:lpMsg是检查需要转换的消息。
返回值:
如果消息被转换(即,字符消息被送到线程的消息队列中),返回非零值。
如果消息是 WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, 或 WM_SYSKEYUP,返回非零值,不考虑转换。
如果消息没有转换(即,字符消息没被送到线程的消息队列中),返回值是零。
TranslateMessage是用来把虚拟键消息转换为字符消息。
由于Windows对所有键盘编码都是采用虚拟键的定义,这样当按键按下时,并不得字符消息,需要键盘映射转换为字符的消息。
LONG DispatchMessage(CONST MSG*lpmsg);
参数:lpmsg:指向含有消息的MSG结构的指针。
返回值:返回值是窗口程序返回的值。尽管返回值的含义依赖于被调度的消息,但返回值通常被忽略。
总结:TranslateMessage函数将键盘消息转化,DispatchMessage函数将消息传给窗体函数去处理.
处理代码像下面这样子:
if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
八、PostQuitMessage
当你点击窗口右上角的关闭时,Windows就会把窗口从系统里删除,这时就会发出消息WM_DESTROY给窗口消息处理函数WindowProc,WindowProc收到这条消息后,最需要做的一件事情就是调用PostQuitMessage发出退出消息,让消息循环结束。
函数PostQuitMessage声明如下:
VOID PostQuitMessage( int nExitCode);
nExitCode是退出标识码,它被放到WM_QUIT消息的参数wParam里。
九、DestroyWindow
调用DestroyWindow函数后,操作系统就会进行一系列的删除动作,先发送WM_DESTROY消息,接着发送WM_NCDESTROY消息。如果这个窗口还有子窗口或者是其它窗口的所有者,就需要给所有子窗口发送删除消息。
函数DestroyWindow声明如下:
BOOL DestroyWindow( HWND hWnd);
hWnd是要删除的窗口句柄。
十、DefWindowProc
在Windows操作系统里,当窗口显示之后,它就可以接收到系统源源不断地发过来的消息,然后窗口就需要处理这些消息,因此就需要一个函数来处理这些消息。在API里定义了一个函数为回调函数,当系统需要向窗口发送消息时,就会调用窗口给出的回调函数WindowProc,如果WindowProc函数不处理这个消息,就可以把它转向DefWindowProc函数来处理,这是系统的默认消息处理函数。当你按下菜单,或者点击窗口时,窗口需要运行这个消息处理函数。
函数DefWindowProc声明如下:
LRESULT DefWindowProc(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
hwnd是当前窗口的句柄。
uMsg是系统发过来的消息。
wParam是消息参数。
lParam是消息参数。
以上就是创建窗口涉及到的一些函数和概念,以后有在接触到,还会在这里补充~