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

本文由CSDN用户zuishikonghuan所作,转载请注明出处 http://blog.csdn.net/zuishikonghuan/article/details/46378475

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_HAND Windows 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 使用
Windows 2000 : 风格 受支持

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

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

WS_EX_DLGMODALFRAME
窗口 边框 ; 可以 (可选) 创建 窗口 标题 通过 捕获 参数 指定 WS_CAPTION 样式

WS_EX_LAYERED
窗口一个分层窗口如果窗口CS_OWNDCCS_CLASSDC样式使用风格
Windows 8: 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风格:
[Win32SDK基本] 窗口详解(超详细)_第1张图片
无边框窗口 :
[Win32SDK基本] 窗口详解(超详细)_第2张图片
其他风格,例如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标准调用约定,在我的第一篇文章中就已经提到这一点了( http://blog.csdn.net/zuishikonghuan/article/details/46327725)

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);//其他消息交给系统处理
}




你可能感兴趣的:(Win32,windows,sdk)