您的位置:首页 > 其它

[Win32SDK基本] 窗口详解(超详细)

2015-06-05 16:20 537 查看
本文由CSDN用户zuishikonghuan所作,转载请注明出处/article/9672496.html

Win32SDK创建窗口,虽然早已经烂大街了,但是那些资料太散,都不全面,无法满足我编程的需要,因此,有必要整理一下。
这篇文章包括一下几个部分:

1。窗口类详解

2。窗口样式详解

3。窗口显示更新详解

4。窗口回调函数和常用消息详解

5。窗口常用API函数和常用控制消息详解

(这篇文章不包含关于绘制窗口的内容,以后我会发布GdiplusFlat(不是Gdiplus哦!)连载,将于那时候详细说明)

1。窗口类详解

要想创建窗口,首先要注册一个窗口类,SDK为我们提供了一个结构“WNDCLASS”,先来看看这个结构的原型

typedef struct tagWNDCLASS {
UINT      style;
WNDPROC   lpfnWndProc;
int       cbClsExtra;
int       cbWndExtra;
HINSTANCE hInstance;
HICON     hIcon;
HCURSOR   hCursor;
HBRUSH    hbrBackground;
LPCTSTR   lpszMenuName;
LPCTSTR   lpszClassName;
} WNDCLASS, *PWNDCLASS;


MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms633576(v=vs.85).aspx

style:窗口类风格(0为缺省风格)

类样式定义窗口类的其他元素。两个或多个样式可以使用位或运算。

我一般都用0,有特殊需要时用一下风格:

CS_BYTEALIGNCLIENT

Aligns the window's client area on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.

将窗口的客户区 (在 x 方向) 的字节边界上对齐。这种风格影响的窗口和其水平位置上显示的宽度。

CS_BYTEALIGNWINDOW

Aligns the window on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.

将窗口 (在 x 方向) 的字节边界上对齐。这种风格影响的窗口和其水平位置上显示的宽度。

CS_CLASSDC

Allocates one device context to be shared by all windows in the class. Because window classes are process specific, it is possible for multiple threads of an application to create a window of the same class. It is also possible for the threads to attempt to
use the device context simultaneously. When this happens, the system allows only one thread to successfully finish its drawing operation.

分配一个设备上下文类中的所有窗口共享。因为窗口类是具体的过程,有可能为多个线程的应用程序创建一个窗口在同一类。它也是可能的线程试图同时使用的设备上下文。当发生这种情况时,系统只允许一个线程能顺利完成其绘图操作。

CS_DBLCLKS

Sends a double-click message to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class.

当用户双击鼠标光标位于内属于类的窗口时,将双击消息发送到窗口过程。

CS_DROPSHADOW

Enables the drop shadow effect on a window. The effect is turned on and off through SPI_SETDROPSHADOW. Typically, this is enabled for small, short-lived windows such as menus to emphasize their Z-order relationship to other windows. Windows created from a class
with this style must be top-level windows; they may not be child windows.

使窗口上有阴影效果。效果是通过 SPI_SETDROPSHADOW 开启和关闭。通常情况下,这是为启用小而短寿的窗口,例如菜单强调他们到其他窗口的 Z 顺序关系。从具有这种风格的类创建的窗口必须是顶级窗口;他们可能不是子窗口。

CS_GLOBALCLASS

Indicates that the window class is an application global class. For more information, see the "Application Global Classes" section of About Window Classes.

指示窗口类是应用程序的全局类。更多的信息,请参阅关于窗口类的"应用程序全局类"节(MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx)。

CS_HREDRAW

Redraws the entire window if a movement or size adjustment changes the width of the client area.

如果移动或大小调整更改客户端区域的宽度将重新绘制整个窗口。

CS_NOCLOSE

Disables Close on the window menu.

在窗口菜单中禁用关闭

CS_OWNDC

Allocates a unique device context for each window in the class.

每个窗口类中分配一个唯一的设备上下文。

CS_PARENTDC

Sets the clipping rectangle of the child window to that of the parent window so that the child can draw on the parent. A window with the CS_PARENTDC style bit receives a regular device context from the system's cache of device contexts. It does not give the
child the parent's device context or device context settings. Specifying CS_PARENTDC enhances an application's performance.

这样的子窗口可以画在父到父窗口设置子窗口的裁剪的矩形。一个带有 CS_PARENTDC 样式位窗口接收常规设备上下文从系统的缓存中的设备上下文。它不给孩子父母的设备上下文或设备上下文设置。指定 CS_PARENTDC 增强应用程序的性能。

CS_SAVEBITS

Saves, as a bitmap, the portion of the screen image obscured by a window of this class. When the window is removed, the system uses the saved bitmap to restore the screen image, including other windows that were obscured. Therefore, the system does not send
WM_PAINT messages to windows that were obscured if the memory used by the bitmap has not been discarded and if other screen actions have not invalidated the stored image.

This style is useful for small windows (for example, menus or dialog boxes) that are displayed briefly and then removed before other screen activity takes place. This style increases the time required to display the window, because the system must first allocate
memory to store the bitmap.

作为一个位图保存屏幕图像被此类窗口遮盖的部分。窗口删除时,系统将使用保存的位图来还原屏幕图像,包括其他窗口遮挡。因此,系统并不发送 WM_PAINT 消息如果位图使用的内存不被丢弃,并且其他屏幕操作都不会失效所存储的图像就被遮住的窗口。

这种风格是有用的小窗口 (例如,菜单或对话框中),并简要显示然后删除其他屏幕活动发生之前。这种风格会增加因为系统必须首先分配的内存来存储位图来显示窗口,所需的时间。

CS_VREDRAW

Redraws the entire window if a movement or size adjustment changes the height of the client area.

如果移动或大小调整更改客户端区域的高度,重新绘制整个窗口。

(参考资料:https://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx)

lpfnWndProc 窗口过程(窗口回调函数指针)

窗口回调函数的原型为:

LRESULT CALLBACK WindowProc(
_In_ HWND   hwnd,
_In_ UINT   uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);

hwnd是消息响应的窗口句柄

uMsg是消息

wParam和lParam是消息附加值

cbClsExtra
额外的字节分配给窗口类结构数目。默认为零字节。

cbWndExtra

额外分配的字节后窗口实例数。系统初始化为零字节。如果应用程序使用WNDCLASS注册对话框中的资源文件中使用类指令创建的它必须将此成员设置为DLGWINDOWEXTRA。(就是说普通的窗口为0即可)

hInstance 窗口类的实例句柄。

WinMain的第一个参数,也可以用GetModuleHandle()动态获取

hIcon 图标句柄

设置窗口图标,LoadIcon(NULL,IDI_APPLICATION);是默认图标,也可以从自己的资源里面加载,那样的话LoadIcon的第一个参数用实例句柄。(我将会在下一篇的RC资源简单使用中详细说)

hCursor 光标指针句柄

默认的箭头是:LoadCursor(NULL, IDC_ARROW);

来自百度百科:http://baike.baidu.com/link?url=-GIckBl735_HY4ykNJlcEJAgpRNGBGErrTN1B1eYffn0u-sqgjQFp2_rwQYbg0umkh74yU-KN_rxX8zUa0X6fK

=======================================================

IDC_APPSTARTING 标准的箭头和小沙漏
IDC_ARROW 标准的箭头
IDC_CROSS 十字光标
IDC_HANDWindows 98/Me, Windows 2000/XP: Hand
IDC_HELP 标准的箭头和问号
IDC_IBEAM 工字光标
IDC_ICON Obsolete for applications marked version 4.0 or later.
IDC_NO 禁止圈
IDC_SIZE Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL.
IDC_SIZEALL 四向箭头指向东、西、南、北
IDC_SIZENESW 双箭头指向东北和西南
IDC_SIZENS 双箭头指向南北
IDC_SIZENWSE 双箭头指向西北和东南
IDC_SIZEWE 双箭头指向东西
IDC_UPARROW 垂直箭头
IDC_WAIT 沙漏,Windows7系统下会显示为选择的圆圈表示等待
=======================================================
同理,也可以用自己资源里的光标指针,那样的话LoadCursor的第一个参数用实例句柄。(与使用自定义图标相同)

hbrBackground 背景画刷的句柄

这个可以是一个画刷句柄,也可以用已下预定值:COLOR_ACTIVEBORDER,COLOR_ACTIVECAPTION,COLOR_APPWORKSPACE,COLOR_BACKGROUND,COLOR_BTNFACE,COLOR_BTNSHADOW,COLOR_BTNTEXT,COLOR_CAPTIONTEXT,COLOR_GRAYTEXT,COLOR_HIGHLIGHT,COLOR_HIGHLIGHTTEXT,COLOR_INACTIVEBORDER,COLOR_INACTIVECAPTION,COLOR_MENU,COLOR_MENUTEXT,COLOR_SCROLLBAR,COLOR_WINDOW,COLOR_WINDOWFRAME,COLOR_WINDOWTEXT

当此成员为NULL
时,应用程序必须绘制自己的背景,每当它请求时,在其客户区绘制。若要确定是否必须绘制背景,应用程序可以处理WM_ERASEBKGND消息或测试由BeginPaint函数的PAINTSTRUCT结构的成员。

系统窗口默认颜色使用:(HBRUSH)(COLOR_WINDOW);

使用喜欢的颜色可以用CreateSolidBrush创建一个画刷,例如黑色:CreateSolidBrush(0x00FFFFFF+1); 注意颜色值需要加1,0x00FFFFFF也可以用RGB宏

lpszMenuName 菜单名称
使用资源里的菜单,不要菜单使用NULL即可

lpszClassName 窗口类名

如果lpszClassName是一个字符串,它指定窗口类的名称。类名称可以是任何注册与RegisterClass或RegisterClassEx,或任何预定义的控件类名称的名称。

LpszClassName的最大长度为256。如果lpszClassName是大于最大长度,RegisterClass函数将失败。

下面演示一下如何注册一个窗口类:

注册窗口类,就是使用RegisterClass或RegisterClassEx函数,我习惯使用RegisterClass,此API函数的原型:
ATOM WINAPI RegisterClass(
_In_ const WNDCLASS *lpWndClass
);


只有一个参数,就是一个WNDCLASS结构的指针。

注册窗口类 代码:

#include "stdafx.h"
#include <windows.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

const TCHAR* AppName = TEXT("MyWindowClass");

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR    lpCmdLine,
_In_ int       nCmdShow)
{
WNDCLASS wc;

//这里是在构建窗口类结构
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;//窗口回调函数指针
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;//实例句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//默认图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW);//默认指针
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);//默认背景颜色
wc.lpszMenuName = NULL;
wc.lpszClassName = AppName;//窗口类名

//注册窗口类
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
}

//这是窗口回调函数,暂时什么也不做
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}


下面开始创建窗口。

我喜欢使用CreateWindowEx函数,当然你也可以使用CreateWindow函数。

CreateWindowEx函数原型如下:
HWND WINAPI CreateWindowEx(
_In_     DWORD     dwExStyle,
_In_opt_ LPCTSTR   lpClassName,
_In_opt_ LPCTSTR   lpWindowName,
_In_     DWORD     dwStyle,
_In_     int       x,
_In_     int       y,
_In_     int       nWidth,
_In_     int       nHeight,
_In_opt_ HWND      hWndParent,
_In_opt_ HMENU     hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID    lpParam
);


CreateWindowEx函数返回我们创建的窗口的窗口句柄,失败返回NULL,调用GetLastError获取错误码。

MSDN:https://msdn.microsoft.com/en-us/library/ms632680(VS.85).aspx

dwExStyle 窗口扩展风格

WS_EX_ACCEPTFILES

窗口接受拖放文件。

WS_EX_APPWINDOW
把顶层的并且可见的窗口放到任务栏上。

WS_EX_CLIENTEDGE
该窗口有一个边界与凹下的边缘。

WS_EX_COMPOSITED
涂料中使用双缓冲的底部到顶部绘画顺序的窗口的所有后代。有关详细信息,请参见备注。如果窗口类样式的CS_OWNDC或CS_CLASSDC,这不能使用。
Windows2000:这种风格是不受支持。

WS_EX_CONTEXTHELP
窗口的标题栏包含一个问号。当用户单击问号,问号指针光标将发生变化。如果用户然后点击一个子窗口,孩子接受WM_HELP消息。子窗口应将消息传递给父窗口过程,应调用WinHelp函数使用HELP_WM_HELP命令。帮助应用程序将显示一个弹出窗口,通常包含的子窗口的帮助。

WS_EX_CONTROLPARENT

允许用户使用Tab键在窗口的子窗口间搜索。

WS_EX_DLGMODALFRAME
该窗口有双边框;可以(可选)创建窗口标题栏与通过捕获参数中指定的WS_CAPTION样式。

WS_EX_LAYERED
窗口是一个分层的窗口。如果该窗口有CS_OWNDC或CS_CLASSDC
的类样式,不能使用这种风格。
Windows8:WS_EX_LAYERED样式支持的顶级窗口和子窗口。以前的Windows版本支持WS_EX_LAYERED仅用于顶级窗口。

WS_EX_LAYOUTRTL
如果shell语言是希伯来语、阿拉伯语或支持阅读顺序排列,窗口的水平起源是右边缘上的另一种语言。增加水平值前进到左边。

WS_EX_LEFT
该窗口有泛型左对齐属性。这是默认设置。

WS_EX_LEFTSCROLLBAR
如果shell语言是希伯来语,阿拉伯语或另一种语言,支持阅读顺序排列,垂直滚动条(如果存在)是左边的客户端区域。对于其他语言,该样式将被忽略。

WS_EX_LTRREADING
使用从左到右的阅读顺序属性显示窗口文本。这是默认设置。

WS_EX_MDICHILD
窗口是一个MDI子窗口。(MDI是一个窗口中的一个窗口容器,就像VC6那种IDE里有很多小窗口)

WS_EX_NOACTIVATE
用这种方式创建一个顶级窗口不成为前台窗口,当用户单击它时。该系统并不到前台带来此窗口,当用户最小化或关闭前台窗口。(让一个窗口不能激活。)
要激活的窗口,使用SetActiveWindow。
窗口在不在默认情况下会出现在任务栏上。若要强制窗口在任务栏上显示,请使用WS_EX_APPWINDOW风格。

WS_EX_NOINHERITLAYOUT
窗口没有传递给其子窗口的窗口布局。

WS_EX_NOPARENTNOTIFY
用这种方式创建的子窗口当它创建或销毁不向它的父窗口发送WM_PARENTNOTIFY消息。

WS_EX_NOREDIRECTIONBITMAP
窗口不呈现到重定向的曲面。这是为windows没有可见的内容,或使用其他表面机制来提供他们的视觉。

WS_EX_OVERLAPPEDWINDOW(WS_EX_WINDOWEDGE |WS_EX_CLIENTEDGE)
该窗口是重叠的窗口。

WS_EX_PALETTEWINDOW(WS_EX_WINDOWEDGE |WS_EX_TOOLWINDOW|WS_EX_TOPMOST)
窗口为组件面板窗口,是一个非模态的对话框,提出了一系列的命令。

WS_EX_RIGHT
该窗口有泛型"右对齐"属性。这取决于窗口类。这种风格有影响,只有当壳语言是希伯来语,阿拉伯语或另一种语言,它支持阅读顺序排列;否则,将忽略该样式。
使用静态WS_EX_RIGHT样式或编辑控件已分别在使用SS_RIGHT或ES_RIGHT
的风格,相同的效果。使用这种风格与按钮控件已使用BS_RIGHT和BS_RIGHTBUTTON样式相同的效果。

WS_EX_RIGHTSCROLLBAR
垂直滚动条(如果存在)是右侧的工作区。这是默认设置。

WS_EX_RTLREADING
如果shell语言希伯来语、阿拉伯语或支持阅读顺序排列的另一种语言,使用从右到左阅读顺序属性显示窗口文本。对于其他语言,该样式将被忽略。

WS_EX_STATICEDGE0x00020000L
该窗口有打算三维边框样式

WS_EX_TOOLWINDOW
窗口被打算用于作为一个浮动的工具栏。工具窗口具有小于正常的标题栏,标题栏和使用较小的字体绘制窗口标题。工具窗口不会出现在任务栏中或在当用户按下ALT
+ TAB时出现的对话框中
。如果一个工具窗口的系统菜单,其图标不会显示在标题栏上。但是,你可以显示系统菜单,通过右键单击或键入ALT
+ 空格。

WS_EX_TOPMOST
窗口应放置高于一切非最顶层的窗口,并应该呆在上面,甚至当窗口被停用。要添加或删除此样式,请使用SetWindowPos函数。(让窗口始终处于Z序顶端,说白了就是总在最前面,对Win8
Metro界面和应用无效,据说需要uiAccess和组策略许可(正在研究中,这只是我的一些猜测))

WS_EX_TRANSPARENT

窗口对于消息是透明的,比方说,鼠标点击此窗口时鼠标消息会穿透到下一个窗口。

WS_EX_WINDOWEDGE
窗口有一个凸起的边缘带有边框。

加红色的是我经常用的,其他的我一般用不着

lpClassName 窗口类名

就是我们创建窗口类时的类名

lpWindowName 窗口标题

dwStyle 窗口风格
WS_BORDER
该窗口有一个细线边框。

WS_CAPTION
该窗口有标题栏(包括WS_BORDER样式)。

WS_CHILD
窗口是一个子窗口。使用这种样式的窗口不能有一个菜单栏。这种风格不能用的WS_POPUP样式。

WS_CHILDWINDOW
WS_CHILD样式相同。

WS_CLIPCHILDREN
不包括在父窗口中绘图时,子窗口所占据的区域。创建父窗口时,将使用这种风格。

WS_CLIPSIBLINGS
剪辑子窗口相对于彼此;那就是,当一个特定的子窗口收到WM_PAINT消息时,WS_CLIPSIBLINGS风格剪辑出子窗口要更新该地区所有其他重叠的子窗口。如果未指定WS_CLIPSIBLINGS和子窗口重叠,它是可能的绘制一个子窗口,绘制一个相邻的子窗口客户端区域内客户端区域内时。

WS_DISABLED
最初禁用窗口。禁用的窗口不能接收用户的输入。要更改此设置在创建窗口后,请使用EnableWindow函数。

WS_DLGFRAME
该窗口有边框的样式通常用于对话框。使用这种样式的窗口不能有一个标题栏。

WS_GROUP
窗口为一组控件的第一个控件。该小组包括这第一个控件和在它以后,到下一个控件与WS_GROUP样式定义的所有控件。每个组中的第一个控件通常具有WS_TABSTOP风格以便用户可以移动到组。用户随后可以更改键盘焦点从一个控件组到组中的下一个控件的使用方向下,键。
你可以打开这种风格和关闭更改对话框框导航。要在创建窗口后,请更改此样式,请使用可以函数。

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_MAXIMIZEBOX)
该窗口是重叠的窗口。WS_TILEDWINDOW样式相同。

WS_POPUP
Windows是一个弹出式窗口。这种风格不能用WS_CHILD风格。

WS_POPUPWINDOW(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
窗口是一个弹出式窗口。WS_CAPTION和WS_POPUPWINDOW样式必须结合起来,使窗口菜单中可见。

WS_SIZEBOX
该窗口有大小调整边框。WS_THICKFRAME样式相同。

WS_SYSMENU
窗口具有其标题栏上的窗口菜单。此外必须指定WS_CAPTION风格。

WS_TABSTOP
窗口是一个控件,当用户按TAB键可以接收键盘焦点。按TAB键将键盘焦点更改到下一个控件具有WS_TABSTOP风格。
你可以打开这种风格和关闭更改对话框框导航。要在创建窗口后,请更改此样式,请使用可以函数。为用户创建windows和非模态对话框选项卡与工作停止,改变消息循环调用IsDialogMessage函数。

WS_THICKFRAME
该窗口有大小调整边框。WS_SIZEBOX样式相同。

WS_TILED
该窗口是重叠的窗口。重叠的窗口具有标题栏和边框。WS_OVERLAPPED样式相同。

WS_TILEDWINDOW(WS_OVERLAPPED |WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|带有最小|WS_MAXIMIZEBOX)
该窗口是重叠的窗口。WS_OVERLAPPEDWINDOW样式相同。

WS_VISIBLE
窗口是最初可见。这种风格可以打开和关闭利用橱窗或SetWindowPos函数。

WS_VSCROLL
该窗口有一个垂直滚动条。

注意不是所有的风格组合都可以直接在CreateWindowEx里面使用的,有的风格即使用了也相当于没用,用Spy++看就根本没有这些风格,只能用SetWindowLong手动设置。

我比较常用的风格:
WS_OVERLAPPED:产生一个层叠的窗口,一个层叠的窗口有一个标题栏和一个边框。
WS_CAPTION:创建一个有标题栏的窗口。
WS_SYSMENU:创建一个在标题栏上带有系统菜单的窗口,要和WS_CAPTION类型一起使用。
WS_THICKFRAME:创建一个具有可调边框的窗口。
WS_MINIMIZEBOX:创建一个具有最小化按钮的窗口,必须同时设定WS_ SYSMENU类型。
WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口,必须同时设定WS_ SYSMENU类型。
WS_OVERLAPPEDWINDOW=WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME WS_MINIMIZEBOX|WS_MAXIMIZEBOX

创建无边框窗口:

SetWindowLong(hwnd,GWL_STYLE,WS_OVERLAPPED|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);

x,y,nWidth,nHeight 窗口位置

x::相对于屏幕左上角的横坐标

y:相对于屏幕左上角的纵坐标

nWidth:宽度

nHeight:高度

hWndParent 父窗口句柄

hMenu 菜单句柄,一般为NULL

hInstance 实例句柄

lpParam

(MSDN解释:Pointer to a value to be passed to the window through the CREATESTRUCT structure (lpCreateParams member) pointed to by the lParam param of the WM_CREATE message. This message is sent to the created window by this function before it returns.If an
application calls CreateWindow to create a MDI client window, lpParam should point to a CLIENTCREATESTRUCT structure. If an MDI client window calls CreateWindow to create an MDI child window, lpParam should point to a MDICREATESTRUCT structure. lpParam may
be NULL if no additional data is needed.)

一般为NULL即可。

显示窗口(ShowWindow)

MSDN:https://msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx

BOOL WINAPI ShowWindow(
_In_ HWND hWnd,
_In_ int  nCmdShow
);


第一个参数:窗口句柄

第二个参数:显示窗口的方式

WinMain函数传来的nCmdShow参数是系统希望窗口显示方式,比如我们使用ShellExcute运行一个exe时预设的显示方式,因此我们可以直接使用

ShowWindow(hwnd, nCmdShow);

但是我们可以使用我们自己喜欢的方法显示窗口,比如 SW_HIDE(隐藏窗口) SW_MAXIMIZE(最大化) SW_MINIMIZE(最小化) SW_SHOWMAXIMIZED(激活窗口并将其最大化) SW_SHOWMINIMIZED(激活窗口并将其最小化)SW_SHOW(正常显示)等等

更新窗口(UpdateWindow)

MSDN:https://msdn.microsoft.com/en-us/library/dd145167(v=vs.85).aspx

BOOL UpdateWindow(
_In_  HWND hWnd
);

让窗口立即重画无效区域,一般创建完窗口都调用这个让窗口立即显示。

消息循环

如果我们直接这样创建窗口,那么就会看到窗口一闪即逝,因为我们创建完窗口后,WinMain函数直接返回,程序退出,因此,我们需要守护进程,使用消息将主线程驻留内存。因此,我们需要加入一下代码,这些代码可以从消息队列中取出消息,并发送到回调函数(队列消息)

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;


创建窗口 代码:

#include "stdafx.h"
#include <windows.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

const TCHAR* AppName = TEXT("MyWindowClass");

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR    lpCmdLine,
_In_ int       nCmdShow)
{
WNDCLASS wc;
HWND hwnd;

//这里是在构建窗口类结构
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;//窗口回调函数指针
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;//实例句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//默认图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW);//默认指针
wc.hbrBackground =  (HBRUSH)(COLOR_WINDOW);//默认背景颜色
wc.lpszMenuName = NULL;
wc.lpszClassName = AppName;//窗口类名

//注册窗口类
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}

//创建窗口
int style = WS_OVERLAPPEDWINDOW;
hwnd = CreateWindowEx(NULL,AppName,TEXT("窗口标题"),style,50,50,500,500,0,0,hInstance,0);
if (hwnd==NULL)
{
MessageBox(NULL, TEXT("创建窗口失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
//无边框窗口
SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPED | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

//显示、更新窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

//消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

//这是窗口回调函数,暂时什么也不做
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}


但是,此时窗口没有处理任何消息,所以你会发现即使关掉窗口程序也不会退出!!因为我们用消息循环让进程驻留内存了。如果想让窗口关闭时退出程序,就要在回调函数里做文章了。

效果图:

WS_OVERLAPPEDWINDOW风格:



无边框窗口:





其他风格,例如WS_EX_TOOLWINDOW,WS_EX_TOPMOST啥的就不再一一演示了,自己试试吧

窗口回调函数(窗口过程) WndProc

MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx

函数原型
LRESULT CALLBACK WindowProc(
_In_ HWND   hwnd,
_In_ UINT   uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
CALLBACK,WINAPI,APIENTRY等宏都是__stdcall标准调用约定,在我的第一篇文章中就已经提到这一点了(/article/9672492.html

hwnd是窗口句柄,uMsg是消息,wParam和lParam是消息附加值。

常用的消息:

WM_PAINT:窗口绘制消息(这篇文章不包含关于绘制窗口的内容,以后我会发布GdiplusFlat(不是Gdiplus哦!)连载,将于那时候详细说明)

WM_DESTROY:窗口销毁后(调用DestroyWindow()后),消息队列得到的消息。

WM_CLOSE:用户点击关闭按钮后收到的消息。

WM_LBUTTONDOWN:在窗口客户区域点击鼠标左键的时候发送。

WM_RBUTTONDOWN:在窗口客户区域点击鼠标右键的时候发送。

WM_ERASEBKGND:当窗口背景必须被擦除时发送。
WM_SETFOCUS:获取焦点后产生的消息。

WM_KILLFOCUS:失去焦点后产生的消息。
WM_CTLCOLORSTATIC:静态控件设置背景和文字颜色。

WM_CREATE:窗口创建完毕。

WM_SIZE:当主窗口的客户区部分大小改变时发送。

WM_MOVE:窗口被移动。

WM_MOUSEMOVE:鼠标移动时被发送至已获焦点的窗口。

WM_SETFONT:设置字体。

WM_SYSCOMMAND;让窗口的客户区拖动窗口(其中的一种办法):在 WM_LBUTTONDOWN 里 PostMessage(hwnd, WM_SYSCOMMAND, 61458, 0);

WM_MOUSELEAVE:鼠标离开窗口时发出的消息。我随后就写一篇博文详细说这个消息(大概一两章之后)

处理消息:

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int xPos, yPos;
switch (uMsg)
{
case WM_CLOSE://询问窗口是否关闭
if (MessageBox(hwnd, TEXT("要关闭窗口吗?"), TEXT("请确认"), MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL)
{
return 0;//表示处理了此消息,系统不再处理
}
break;
case WM_DESTROY:
PostQuitMessage(0);//退出消息循环,结束应用程序
return 0;
break;
case WM_LBUTTONDOWN:
//让无边框窗口能够拖动(在窗口客户区拖动),下面两个任选其一
//PostMessage(hwnd, WM_SYSCOMMAND, 61458, 0);
//PostMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
break;
case WM_MOUSEMOVE://鼠标移动
xPos = GET_X_LPARAM(lParam);//鼠标位置X坐标
yPos = GET_Y_LPARAM(lParam);//鼠标位置Y坐标
//不要用LOWORD和HIWORD获取坐标,因为坐标有可能是负的
break;
default:
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);//其他消息交给系统处理
}


完整代码
#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

const TCHAR* AppName = TEXT("MyWindowClass");

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;

//这里是在构建窗口类结构
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;//窗口回调函数指针
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;//实例句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//默认图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW);//默认指针
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);//默认背景颜色
wc.lpszMenuName = NULL;
wc.lpszClassName = AppName;//窗口类名

//注册窗口类
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}

//创建窗口
int style = WS_OVERLAPPEDWINDOW;
hwnd = CreateWindowEx(NULL,AppName,TEXT("窗口标题"),style,50,50,500,500,0,0,hInstance,0);
if (hwnd==NULL)
{
MessageBox(NULL, TEXT("创建窗口失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
//无边框窗口
SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPED | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

//显示、更新窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

//消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

//这是窗口回调函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { int xPos, yPos; switch (uMsg) { case WM_CLOSE://询问窗口是否关闭 if (MessageBox(hwnd, TEXT("要关闭窗口吗?"), TEXT("请确认"), MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL) { return 0;//表示处理了此消息,系统不再处理 } break; case WM_DESTROY: PostQuitMessage(0);//退出消息循环,结束应用程序 return 0; break; case WM_LBUTTONDOWN: //让无边框窗口能够拖动(在窗口客户区拖动),下面两个任选其一 //PostMessage(hwnd, WM_SYSCOMMAND, 61458, 0); //PostMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); break; case WM_MOUSEMOVE://鼠标移动 xPos = GET_X_LPARAM(lParam);//鼠标位置X坐标 yPos = GET_Y_LPARAM(lParam);//鼠标位置Y坐标 //不要用LOWORD和HIWORD获取坐标,因为坐标有可能是负的 break; default: break; } return DefWindowProc(hwnd, uMsg, wParam, lParam);//其他消息交给系统处理 }




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: