LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
This parameter is not used.
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 <> 0) then // 消息里已经自带DC,用这个绘制就可以了 begin if not (csCustomPaint in ControlState) and (ControlCount = 0) then // 针对Windows自带控件,其包含的子控件数量为0,且没有自绘标记。 inherited // 走向1,主要是针对Windows系统原生控件,微软定义的基本控件,总不会有错,应该内含BeginPaint了吧? else PaintHandler(Message); // 走向2,主要是针对Delphi的自绘控件,内含BeginPaint end else begin DC := GetDC(0); // 走向3,消息里没有自带DC,那么就现取,内含BeginPaint MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom); ReleaseDC(0, DC); MemDC := CreateCompatibleDC(0); 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, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, 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 = 0 then DC := BeginPaint(Handle, PS); // 如果DC是空的,就要取得它(如果是单独的控件,肯定要执行) try if FControls = nil then PaintWindow(DC) else begin SaveIndex := SaveDC(DC); Clip := SimpleRegion; for I := 0 to FControls.Count - 1 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 = 0 then EndPaint(Handle, PS); end; end; procedure TGraphicControl.WMPaint(var Message: TWMPaint); begin if Message.DC <> 0 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 <> 1 then if ((Flags and PRF_CHECKVISIBLE) = 0) or Visible then PaintHandler(TWMPaint(Message)) else inherited else inherited; end;
回头做个实验,一个TWinControl包含多个TCustomControl子控件。WM_PAINT第一次会发给父控件,然后依次重绘TCustomControl子控件,但是每个TCustomControl子控件都会通过inherited把消息传回来,当第一次传回来的时候,这个消息的DC就应该不是0了。
原文:http://www.cnblogs.com/findumars/p/5183638.html