您的表单Canvas
被“损坏”的原因是因为 DLL 的TCanvas
对象正在替换原始HFONT
的HBRUSH
和/或HPEN
已分配给 的对象,HDC
但随后在其销毁期间分配了库存GDI 对象(来自先前分配的 GDI 对象。当属性更改值(包括销毁期间)时,方法中会发生这种情况:GetStockObject()
TCanvas.DeselectHandles()
TCanvas.Handle
var
...
StockPen: HPEN;
StockBrush: HBRUSH;
StockFont: HFONT;
...
procedure TCanvas.DeselectHandles;
begin
if (FHandle <> 0) and (State - [csPenValid, csBrushValid, csFontValid] <> State) then
begin
SelectObject(FHandle, StockPen); // <-- STOCK PEN!
SelectObject(FHandle, StockBrush); // <-- STOCK BRUSH!
SelectObject(FHandle, StockFont); // <-- STOCK FONT!
State := State - [csPenValid, csBrushValid, csFontValid];
end;
end;
...
initialization
...
StockPen := GetStockObject(BLACK_PEN);
StockBrush := GetStockObject(HOLLOW_BRUSH);
StockFont := GetStockObject(SYSTEM_FONT);
...
要在 DLL 函数退出后使表单“重置”它Canvas
,您必须欺骗它Canvas
知道它的 GDI 对象不再分配给它,HDC
以便它可以从其内部State
成员中清除相关标志并根据需要重新分配它的 GDI 对象。您可以:
手动触发,和属性的OnChange
事件处理程序:Canvas.Font
Canvas.Brush
Canvas.Pen
procedure TMyForm.FormPaint(Sender: TObject);
begin
try
CallDllFunc(Canvas.Handle);
finally
Canvas.Font.OnChange(nil);
Canvas.Brush.OnChange(nil);
Canvas.Pen.OnChange(nil);
end;
end;
或者:
type
TGraphicObjectAccess = class(TGraphicObject)
end;
procedure TMyForm.FormPaint(Sender: TObject);
begin
try
CallDllFunc(Canvas.Handle);
finally
TGraphicObjectAccess(Canvas.Font).Changed;
TGraphicObjectAccess(Canvas.Brush).Changed;
TGraphicObjectAccess(Canvas.Pen).Changed;
end;
end;
您可以暂时删除然后重新分配原始的HDC
,这对State
标志有类似的影响:
procedure TMyForm.FormPaint(Sender: TObject);
var
DC: HDC;
begin
try
CallDllFunc(Canvas.Handle);
finally
DC := Canvas.Handle;
Canvas.Handle := 0;
Canvas.Handle := DC;
end;
end;
使用SaveDC()
and RestoreDC()
,如Sertac 的答案所示。