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

Parameters

wParam

This parameter is not used.

lParam

This parameter is not used.

Delphi里去掉句柄之后重定义:

  TWMPaint = packed record
Msg: Cardinal;
DC: HDC;
Unused: Longint;
Result: Longint;
end;

经过测试,其大小为16:

procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage(IntToStr(sizeof(TWMPaint)));
end;

重定义之后的利用过程,看这里:

procedure TWinControl.WMPaint(var Message: TWMPaint);
var
DC, MemDC: HDC;
MemBitmap, OldBitmap: HBITMAP;
PS: TPaintStruct;
begin
if not FDoubleBuffered or (Message.DC <> ) then // 消息里已经自带DC,用这个绘制就可以了
begin
if not (csCustomPaint in ControlState) and (ControlCount = ) then // 针对Windows自带控件,其包含的子控件数量为0,且没有自绘标记。
inherited // 走向1,主要是针对Windows系统原生控件,微软定义的基本控件,总不会有错,应该内含BeginPaint了吧?
else
PaintHandler(Message); // 走向2,主要是针对Delphi的自绘控件,内含BeginPaint
end
else
begin
DC := GetDC(); // 走向3,消息里没有自带DC,那么就现取,内含BeginPaint
MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
ReleaseDC(, DC);
MemDC := CreateCompatibleDC();
OldBitmap := SelectObject(MemDC, MemBitmap);
try
DC := BeginPaint(Handle, PS);
Perform(WM_ERASEBKGND, MemDC, MemDC);
Message.DC := MemDC; // 其实这有这里进行赋值
WMPaint(Message); // 中间有了DC,赶紧使用
Message.DC := 0;
BitBlt(DC, , , ClientRect.Right, ClientRect.Bottom, MemDC, , , SRCCOPY);
EndPaint(Handle, PS);
finally
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
DeleteObject(MemBitmap);
end;
end;
end;

继续传递:

procedure TWinControl.PaintHandler(var Message: TWMPaint);
var
I, Clip, SaveIndex: Integer;
DC: HDC;
PS: TPaintStruct;
begin
DC := Message.DC; // 使用消息带来的句柄(没准在别处赋值的),比如子控件挨个向父控件发送重绘请求,这样就不用每次都重新给DC赋值了。但是这里不是引用,出了这个函数,Message.DC的值并没有被改变。fixme 还是没全懂
if DC = then DC := BeginPaint(Handle, PS); // 如果DC是空的,就要取得它(如果是单独的控件,肯定要执行)
try
if FControls = nil then PaintWindow(DC) else
begin
SaveIndex := SaveDC(DC);
Clip := SimpleRegion;
for I := to FControls.Count - do
with TControl(FControls[I]) do
if (Visible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and
(csOpaque in ControlStyle) then
begin
Clip := ExcludeClipRect(DC, Left, Top, Left + Width, Top + Height);
if Clip = NullRegion then Break;
end;
if Clip <> NullRegion then PaintWindow(DC);
RestoreDC(DC, SaveIndex);
end;
PaintControls(DC, nil); // 还要把自己的DC带给子控件
finally
if Message.DC = then EndPaint(Handle, PS);
end;
end; procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
if Message.DC <> then // 注意,如果DC为零,根本就不自绘(没法自绘)
begin
Canvas.Lock;
try
Canvas.Handle := Message.DC; // 可见的本质上,DC就是一个控件的Canvas句柄,而且是父控件的DC句柄
try
Paint;
finally
Canvas.Handle := 0;
end;
finally
Canvas.Unlock;
end;
end;
end; procedure TCustomControl.WMPaint(var Message: TWMPaint);
begin
Include(FControlState, csCustomPaint);
inherited;
Exclude(FControlState, csCustomPaint);
end; procedure TWinControl.WMPrintClient(var Message: TWMPrintClient);
begin
with Message do
if Result <> then
if ((Flags and PRF_CHECKVISIBLE) = ) or Visible then
PaintHandler(TWMPaint(Message))
else
inherited
else
inherited;
end;

回头做个实验,一个TWinControl包含多个TCustomControl子控件。WM_PAINT第一次会发给父控件,然后依次重绘TCustomControl子控件,但是每个TCustomControl子控件都会通过inherited把消息传回来,当第一次传回来的时候,这个消息的DC就应该不是0了。

WM_PAINT在微软官方定义中,wParam和lParam都没有使用,所以就被Delphi给重定义了这个消息,还增加了DC(Delphi可任意改写消息的结构)的更多相关文章

  1. 自定义消息中如果需要定义WPARAM和LPARAM,该怎么使用和分配?

    写Windows程序不可避免要使用自定义的消息,也就是从WM_USER开始定义的消息.在定义一个消息后,往往我们还要定义针对该消息的WPARAM甚至是LPARAM.WPARAM和LPARAM是什么,可 ...

  2. MVC4学习之官方教程中迁移版本库报错

    因工作需要,学习MVC4,但是微软官方教程中迁移版本库步骤在本地测试报错 官方教程地址:http://www.asp.net/mvc/overview/older-versions/getting-s ...

  3. C++中重定义的问题——问题的实质是声明和定义的关系以及分离式编译的原理

    这里的问题实质是我们在头文件中直接定义全局变量或者函数,却分别在主函数和对应的cpp文件中包含了两次,于是在编译的时候这个变量或者函数被定义了两次,问题就出现了,因此,我们应该形成一种编码风格,即: ...

  4. C++中的继承详解(3)作用域与重定义,赋值兼容规则

    作用域与同名隐藏 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A" ...

  5. C++中的继承(3)作用域与重定义,赋值兼容规则

    作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A& ...

  6. C++中的继承(3)作用域与重定义,赋值兼容规则

    1.作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << " ...

  7. LRESULT与wParam和lParam的问题

    在微软vc提供的头文件中有定义在winnt.h中typedef long LONG;在windef.h中typedef LONG LRESULT; 所以LRESULT就是long,也就是长整形之所以取 ...

  8. wParam与lParam的区别

    wParam与lParam的区别 lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数. LRESULT CALLBACK WindowProc(H ...

  9. WPARAM和LPARAM的含义

    lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uM ...

随机推荐

  1. 我的ubuntu

    题外话:不知不觉也已经大三,最近思考了很多.在腾讯网看到了对李嘉诚的一篇专访,感触颇深. 想起来我从第一次接触ubuntu到现在也有一年了,记得第一个版本还是12.04,不过很快就换成了12.10,在 ...

  2. 转:JavaScript定时机制、以及浏览器渲染机制 浅谈

    昨晚,朋友拿了一道题问我: a.onclick = function(){ setTimeout(function() { //do something ... },0); }; //~~~ 我只知道 ...

  3. python:利用asyncio进行快速抓取

    web数据抓取是一个经常在python的讨论中出现的主题.有很多方法可以用来进行web数据抓取,然而其中好像并没有一个最好的办法.有一些如scrapy这样十分成熟的框架,更多的则是像mechanize ...

  4. JAVA 中URL链接中文参数乱码的若干处理方法

    方法一: http://xxx.do?ptname='我是中国人' String strPtname = request.getParameter("ptname"); strPt ...

  5. Chapter 9 原型模式

    原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 简单的说就是clone一个对象实例.使得clone出来的copy和原有的对象一模一样. 插一个简单使用clone的例子,如果 ...

  6. ASP.NET MVC 5 学习教程:通过控制器访问模型的数据

    原文 ASP.NET MVC 5 学习教程:通过控制器访问模型的数据 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连 ...

  7. php前端控制器2

    Front Controllers act like centralized agents in an application whose primary area of concern is to ...

  8. hdu 1251 统计难题 初识map

    Problem Description Ignatius近期遇到一个难题,老师交给他非常多单词(仅仅有小写字母组成,不会有反复的单词出现),如今老师要他统计出以某个字符串为前缀的单词数量(单词本身也是 ...

  9. hdu1853解题报告

    题意和解决回路匹配的思路如同hdu3488 (这里我第一次想到最短路,但是对于有回路这个不知道怎么处理,后来看了别人的解题报告才知道KM匹配,但是看到KM之后就自己想...想了很久....还是不知道回 ...

  10. http 连接复用

    定义 Http/1.0每次请求都需要建立新的TCP连接,连接不能复用.Http/1.1新的请求可以在上次建立的tcp连接之上发送,连接可以复用. 优点 减少重复进行tcp三次握手的开销,提高效率.注意 ...