2010-11-01 38 views
3

我在这段代码有一个范围检查错误:范围检查错误画布

{ This procedure is copied from RxLibrary VCLUtils } 
procedure CopyParentImage(Control: TControl; Dest: TCanvas); 
var 
    I, Count, X, Y, SaveIndex: Integer; 
    DC: HDC; 
    R, SelfR, CtlR: TRect; 
begin 
    if (Control = nil) OR (Control.Parent = nil) 
    then Exit; 

    Count := Control.Parent.ControlCount; 
    DC := Dest.Handle; 
    with Control.Parent 
    DO ControlState := ControlState + [csPaintCopy]; 

    TRY 
    with Control do 
    begin 
     SelfR := Bounds(Left, Top, Width, Height); 
     X := -Left; Y := -Top; 
    end; 

    { Copy parent control image } 
    SaveIndex := SaveDC(DC); 
    TRY 
     SetViewportOrgEx(DC, X, Y, nil); 
     IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth, Control.Parent.ClientHeight); 
     with TParentControl(Control.Parent) DO 
     begin 
     {$R-} 
     Perform(WM_ERASEBKGND, DC, 0); <--------------- HERE 
     {$R+}   
     PaintWindow(DC); 
     end; 
    FINALLY 
     RestoreDC(DC, SaveIndex); 
    END; 

    { Copy images of graphic controls } 
    for I := 0 to Count - 1 do begin 
     if Control.Parent.Controls[I] = Control then Break 
     else if (Control.Parent.Controls[I] <> nil) and 
     (Control.Parent.Controls[I] is TGraphicControl) then 
     begin 
     with TGraphicControl(Control.Parent.Controls[I]) do begin 
      CtlR := Bounds(Left, Top, Width, Height); 
      if Bool(IntersectRect(R, SelfR, CtlR)) and Visible then 
      begin 
      ControlState := ControlState + [csPaintCopy]; 
      SaveIndex := SaveDC(DC); 
      try 
       SetViewportOrgEx(DC, Left + X, Top + Y, nil); 
       IntersectClipRect(DC, 0, 0, Width, Height); 
       {$R-}    
       Perform(WM_PAINT, DC, 0); <--------------- HERE 
       {$R+} 
      finally 
       RestoreDC(DC, SaveIndex); 
       ControlState := ControlState - [csPaintCopy]; 
      end; 
      end; 
     end; 
     end; 
    end; 
    FINALLY 
    with Control.Parent DO 
    ControlState := ControlState - [csPaintCopy]; 
    end; 
end; 

有人发布的代码,而无需范围检查激活:(

我把{$ R - } {$ R +}周围已产生的差错,现在的代码工作,但我不知道有什么后果的线路,我不希望一些奇怪的错误后


德尔福,赢。 7 32bit

回答

9

Perform过程期望其第二个参数具有类型WParam,这是一个有符号的整数类型。从Delphi 3开始,实际参数的HDC类型是无符号的(与大多数其他句柄类型一样)。在基于NT的系统上,处理的值高于MaxInt,这在WParam的范围之外是很常见的。这是您的范围检查错误的来源。

类型转换的参数,你将被罚款:

Perform(wm_EraseBkgnd, WParam(DC), 0); 

Perform方法简单地解释了高无符号值作为一个大的负值来代替。它会将参数值发送到消息处理程序,并且消息处理程序将键入 - 将其返回到它想要的HDC类型。所有类型都是相同的大小,所以没有危险。

+0

非常感谢。有效。我已经看到参数之间的差异,但我不知道我可以使用WParam进行类型转换。它看起来像在Delphi 3中出现的变化,但代码是用于Delphi 2005,我最初认为是代码错误。可能开发人员关闭了“范围检查”选项。 – Ampere 2010-11-02 13:06:34

2

它应该没问题,它是通常的Cardinal/Integer类型转换。 WM_ERASEBKGND在整个VCL中都是这样使用的,例如在Controls.pas中使用{$ R-}指令。

+0

嗨。我已经尝试过整数。它没有奏效。 +1解释。 – Ampere 2010-11-02 13:11:11

+0

我的意思是,无论是像Rob建议的那样明确地进行类型转换,还是像使用{$ R-}一样,并且像在VCL中完成的那样(特别是Controls.pas)。 – 2010-11-02 19:42:16