我在这段代码中遇到了Range检查错误:
{ 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 +}放在产生错误的行周围,代码现在正在运行,但我不确定会产生什么后果。我以后不想要一些奇怪的错误。
Delphi,Win 7 32bit
答案 0 :(得分:9)
Perform
过程期望其第二个参数具有类型WParam
,这是一个有符号整数类型。从Delphi 3开始,实际参数的HDC
类型是无符号的(与大多数其他句柄类型一样)。在基于NT的系统上,句柄的值通常高于MaxInt,这超出了WParam
的范围。这是你的范围检查错误的来源。
输入参数,你会没事的:
Perform(wm_EraseBkgnd, WParam(DC), 0);
Perform
方法只会将高无符号值解释为较大的负值。它会将参数值发送到消息处理程序,消息处理程序会将其类型转换回它想要的HDC
类型。所有类型都是相同的大小,所以没有危险。
答案 1 :(得分:2)
应该没问题,这是通常的Cardinal / Integer类型转换。 WM_ERASEBKGND在整个VCL中都是这样使用的,例如在Controls.pas中,使用{$ R-}指令。