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. java读写

    IO流下分为字节流与字符流,每个流又分为输入输出以及读写. 字节流的两个基类为InputStream与OutputStream. 字符流为Reader和Writer

  2. 说说读卡应用那点事儿,以SCL010为例

    前一阵子的项目, 跟读卡应用有关,这篇博客算是我学习智能卡方面知识的而一个总结,也可以看作这个领域的一个很简单的简介,他写得很不书面,更像是沿着我自己认识过程的总结.所以这里面有很多我自己理解的地方, ...

  3. perl post 带上请求头

    my $url='https://www.zjcap.cn/business/dispatch_post.do?action=submitAdminLogin'; my $res = $ua-> ...

  4. libpng causes error concerning pngconf.h

    Bug Description Ubuntu Gutsy Gibbon 7.10 - libpng 1.2.15~beta5-2ubuntu0.1 (bug probably concerned wi ...

  5. hdu 4730 We Love MOE Girls

    http://acm.hdu.edu.cn/showproblem.php?pid=4730 直接用string类处理字符串. AC代码: #include<iostream> #incl ...

  6. git 使用过程(三、文件的添加 修改)

    1.库中添加文件 在目录下新建一个文件 如 testfile.txt .输入命令:① git add testfile.txt  ②git commit -m "这里是你提交的说明" ...

  7. IF的使用

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. 内核printk打印等级

    为了确认内核打印等级以及prink 参数对打印的分级,在led驱动初始化代码[以及exit出口]加入如下代码. 每次insmod .rmmod led模块时,根据打印等级的设置,得到不同的打印结果: ...

  9. Genymotion Unable to create Virtual Device:Connection timeout

    1.进入C:\Users\[UserName]\AppData\Local\Genymobile,打开genymotion.log,找到最后几句话:     九月 2 14:29:45 [Genymo ...

  10. 编译原理Tiny语言的定义

    Here is the definition for Tiny language The Tiny lexicon is as follows: Keywords:   IF ELSE WRITE R ...