【前言】
指定应用程序的标题高度和边框的宽度的方法有很多种。其中最普遍的方法有下面的两种:
第一种:创建没有标题栏应用程序,在客户区让出一部分空间用一幅图片画一个标题栏,让人“误认为”是标题栏。
第二种:处理应用程序接收到的WM_NCCALCSIZE消息,改变客户区在窗口中的位置,从而得到合适标题栏高度。
不能说哪一种方法好,哪一种方法不好,其实第一种做法简单易行,而且也能做得很漂亮,但不爽的一点是就是每一次画客户区的时候总是计算坐标的起始位置;第二种方法有点麻烦(其实也不麻烦),但有一点很好,客户区不用负责标题栏重绘工作,响应WM_PAINT消息时候不用计算位置。
【第二种】
要想得到最准确最全面的信息得去MS的老巢去找EN文版的(GOOGLE什么的最讨厌了),别怕一句一句看(俺的英语水平(360) << CET-4(425),我都能看懂,肯定没有人看不懂的了)。
wParam:
If wParam is TRUE, it specifies that the application should indicate which part of the client area contains valid information. The system copies the valid information to the specified area within the new client area. 
If wParam is FALSE, the application does not need to indicate the valid part of the client area.
lParam:
If wParam is TRUE, lParam points to an NCCALCSIZE_PARAMS structure that contains information an application can use to calculate the new size and position of the client rectangle. 
If wParam is FALSE, lParam points to a RECT structure. On entry, the structure contains the proposed window rectangle for the window. On exit, the structure should contain the screen coordinates of the corresponding window client area.
这是MSND上一段话:意思是如wParam为TRUE,需要在新矩形中指定可用的客户区;如果wParam为FALSE应用程序不用在新矩形中指定客户区。
我这样的理解的:当窗口创建时候的wParam为FALSE,其它情况为TRUE。
【TRUE情况】
假想:窗口一开始在A位置,突然移动到B位置。

如图:
这时候Windows将会给窗口发送一个WM_NCCALCSIZE消息,通知应用程序窗口的位置或者大小变了,应用程序应当指定新的非客户区和客户区的位置。消息具体内容的是:
message:WM_NCCALCSIZE
wParam: TRUE
lParam: 一个指向三个矩形的指针(NCCALCSIZE_PARAMS *)。下面是NCCALCSIZE_PARAMS结构:
typedef struct tagNCCALCSIZE_PARAMS {
RECT rgrc[3];
PWINDOWPOS lppos;
} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS;
下面是MSDN的一段说明:
rgrc
RECT
An array of rectangles. The meaning of the array of rectangles changes during the processing of the WM_NCCALCSIZE message. 
When the window procedure receives the WM_NCCALCSIZE message, the first rectangle contains the new coordinates of a window that has been moved or resized, that is, it is the proposed new window coordinates. The second contains the coordinates of the window before it was moved or resized. The third contains the coordinates of the window's client area before the window was moved or resized. If the window is a child window, the coordinates are relative to the client area of the parent window. If the window is a top-level window, the coordinates are relative to the screen origin.
When the window procedure returns, the first rectangle contains the coordinates of the new client rectangle resulting from the move or resize. The second rectangle contains the valid destination rectangle, and the third rectangle contains the valid source rectangle. The last two rectangles are used
简易翻译一下(凑合看):
当窗口处理收到的WM_NCCALCSIZE消息是,第一个矩形包含了移动后或者改变大小后的新坐标(也就是B的坐标),它是建议的坐标。第二个矩形包含了移动或改变大小前的坐标(也就是A坐标),第三个矩形包含了客户区的移动前的坐标(也就是A坐标中的客户区坐标)。
处理这个消息返回之前(也就是WM_NCCALCSIZE处理完成后),第一个矩形应当包含新客户区的坐标(也就是B坐标中的客户区坐标),第二个矩形包含了可用的目标矩形(B坐标),第三个坐标包含了源矩形(A坐标)。后面的两个矩形也会被用到。简而言之:
我们在处理前的是:第一个矩形是B,第二个矩形是A,第三个矩形是AC,
我们在处理后的是:第一个矩形是BC,第二个矩形是B,第三个是矩形A。
于是我写下了下写的C处理代码:
int xFrame = 2; /*左右边框的厚度*/
int yFrame = 2; /*下边框的厚度*/
int nTHight = 40; /*标题栏的高度*/
NCCALCSIZE_PARAMS * p; /*TRUE是的指针*/
RECT * rc; /*FALSE是的指针*/
RECT aRect;
RECT bRect;
RECT bcRect;

if(wParam == TRUE)
{
p = (NCCALCSIZE_PARAMS *)lParam;

/*复制A B矩形位置*/
CopyRect(&aRect,&p->rgrc[1]); 
CopyRect(&bRect,&p->rgrc[0]);

/*指定BC的矩形的位置*/
bcRect.left = bRect.left + xFrame;
bcRect.top = bRect.top + nTHight;
bcRect.right = bRect.right - xFrame;
bcRect.bottom = bRect.bottom - yFrame;

/*各个矩形归位成BC B A*/
CopyRect(&p->rgrc[0],&bcRect);
CopyRect(&p->rgrc[1],&bRect);
CopyRect(&p->rgrc[2],&aRect);
}
上面是处理了wParam为TRUE的情况,再回头来看FALSE的情况,就是初始化的时候,我们知道刚刚初始化的时候不是A->B而是从没有矩形到有矩形。
【FALSE情况】
这时候,lParam是指向一个矩形,这个矩形是窗口的现在位置X,我们要返回的是XC,也是就是返回X变成XC,下面给成C代码:
else
{
rc = (RECT *)lParam;

rc->left = rc->left + xFrame;
rc->top = rc->top + nTHight;
rc->right = rc->right - xFrame;
rc->bottom = rc->bottom - yFrame;
}

至此, WM_NCCALCSIZE讲解完毕。自定义高度的窗口式样(照着QQ风格画的):

nie@song.ah.cn
niesongsong
沈阳
敬上
整个函数写法:

case WM_NCCALCSIZE:
ProcNCCalcSize(hWnd,message,wParam,lParam);

int ProcNCCalcSize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int xFrame = 2; /*左右边框的厚度*/
int yFrame = 2; /*下边框的厚度*/
int nTHight = 40; /*标题栏的高度*/
NCCALCSIZE_PARAMS * p;
RECT * rc;

RECT aRect;
RECT bRect;
RECT bcRect;

if(wParam == TRUE)
{
p = (NCCALCSIZE_PARAMS *)lParam; /*矩形是B A AC,目标是改成BC B A*/

CopyRect(&aRect,&p->rgrc[1]); 
CopyRect(&bRect,&p->rgrc[0]);

/*指定BC的矩形的位置*/
bcRect.left = bRect.left + xFrame;
bcRect.top = bRect.top + nTHight;
bcRect.right = bRect.right - xFrame;
bcRect.bottom = bRect.bottom - yFrame;

/*各个矩形归位*/
CopyRect(&p->rgrc[0],&bcRect);
CopyRect(&p->rgrc[1],&bRect);
CopyRect(&p->rgrc[2],&aRect);
}
else
{
rc = (RECT *)lParam;

rc->left = rc->left + xFrame;
rc->top = rc->top + nTHight;
rc->right = rc->right - xFrame;
rc->bottom = rc->bottom - yFrame;
}
return GetLastError();
}

WM_NCCALCSIZE消息处理详解的更多相关文章

  1. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  2. linux查看端口及端口详解

    今天现场查看了TCP端口的占用情况,如下图   红色部分是IP,现场那边问我是不是我的程序占用了tcp的链接,,我远程登陆现场查看了一下,这种类型的tcp链接占用了400多个,,后边查了一下资料,说E ...

  3. HTTP协议详解(转)

    转自:http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HTTP是一个属于应用层的面向对象的 ...

  4. HTTP协议详解

    Author :Jeffrey 引言 HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和 扩展. ...

  5. ASP.NET知识总结(3.HTTP协议详解)

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  6. 接口测试之HTTP协议详解

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  7. 【转】HTTP协议详解

    原文地址:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436.html 一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则 ...

  8. HTTP协议详解(真的很经典)

    HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和 扩展.目前在WWW中使用的是HTTP/1.0 ...

  9. HTTP协议详解--转载http://blog.csdn.net/gueter/article/details/1524447

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

随机推荐

  1. C#学习笔记(十):反射

    反射 放射是指在程序运行时动态的获取类的信息的机制,我们下面来看看C#中的反射. Type Type 为 System.Reflection 功能的根,也是访问元数据的主要方式. 使用 Type 的成 ...

  2. 解决mysql导入导出数据乱码问题

    最近在linux上面用mysqldump导出数据,放在windows系统中导入就会出现中文乱码,然后就会导致出现: Unknown MySQL server host和Can't connect to ...

  3. 在WCF中不使用svc文件直接使用cs文件

    在 配置中有个节点可以实现 此功能 <serviceHostingEnvironment multipleSiteBindingsEnabled="true" > &l ...

  4. 通过程序 VB.Net 或 C# 读取文本文件行数

    1, VB.NET 读取 (通过streamReader) ' tmpCount = 0 'Dim tmpSR As New StreamReader(fileFullName, System.Tex ...

  5. SimpleTagImageView

    https://github.com/wujingchao/SimpleTagImageView SimpleTagImageView ImageView with a tag in android. ...

  6. Android通过http协议POST传输方式

    Android通过http协议POST传输方式如下: 方式一:HttpPost(import org.apache.http.client.methods.HttpPost) 代码如下: privat ...

  7. 利用PHP生成二维码(转)

    导读:在二维码广泛应用化的今天,在web站点中自动生成对应的二维码是最基础的需求.文章介绍了使用PHP自动生成二维码的三种方式. get方法实现方式一: $urlToEncode="163. ...

  8. android143 360 短信电话拦截

    package com.itheima.mobileguard.services; import java.lang.reflect.Method; import android.app.Servic ...

  9. asp.net常用函数

    ASP.NET网络编程中常用到的27个函数集 Abs(number) 取得数值的绝对值.   Asc(String) 取得字符串表达式的第一个字符ASCII 码.   Atn(number) 取得一个 ...

  10. [Effective C++ --031]将文件间的编译依存关系降至最低

    引言:编译时间成本 在项目中我们都会碰到修改既存类的情况:某个class实现文件做了些轻微改变,修改的不是接口,而是实现,而且只改private成分. 重新build这个程序,并预计只花数秒就好,当按 ...