将透明消息绘制到屏幕会产生系统资源

时间:2014-06-03 10:52:11

标签: delphi

我有一个代码,它将消息str直接绘制到屏幕的中心而没有可见的窗口。

为什么首先使用此代码可以正常工作,但经过几十次调用后,它会提供系统资源。  它似乎可以免费使用BM,而且我没有看到它根本分配其他资源。

procedure ttsplash.UpdateSplash(const Str: string);
var
  R: TRect;
  P: TPoint;
  S: TPoint;
  bm: TBitmap;
  bf: TBlendFunction;
  EXSTYLE: DWORD;
  x, y: integer;
  pixel: PRGBQuad;
  TextRed,
  TextGreen,
  TextBlue: byte;
begin

if str='' then exit;

  EXSTYLE := GetWindowLong(Handle, GWL_EXSTYLE);
  SetWindowLong(Handle, GWL_EXSTYLE, EXSTYLE or $80000);

  R := ClientRect;

  bm := TBitmap.Create;
  try
    bm.PixelFormat := pf32bit;
//    bm.SetSize(ClientWidth, ClientHeight);
    bm.Width := clientwidth;
        bm.height := clientheight;

    bm.Canvas.Brush.Color := clBlack;
    bm.Canvas.FillRect(ClientRect);

    bm.Canvas.Font.Assign(Self.Font);
    bm.Canvas.Font.Color := clWhite;
    DrawText(bm.Canvas.Handle, PChar(Str), Length(Str), R,
      DT_SINGLELINE or DT_VCENTER or DT_CENTER or DT_WORD_ELLIPSIS);

    TextRed := GetRValue(ColorToRGB(Font.Color));
    TextGreen := GetGValue(ColorToRGB(Font.Color));
    TextBlue := GetBValue(ColorToRGB(Font.Color));

    for y := 0 to bm.Height - 1 do
    begin
      pixel := bm.ScanLine[y];
      x := 0;
      while x < bm.Width do
      begin
        with pixel^ do
        begin
          rgbReserved := (rgbRed + rgbGreen + rgbBlue) div 3;

          rgbBlue := TextBlue * rgbReserved div 255;
          rgbGreen := TextGreen * rgbReserved div 255;
          rgbRed := TextRed * rgbReserved div 255;
        end;

        inc(pixel);
        inc(x);
      end;
    end;      

    P := Point(0, 0);
    S := Point(bm.Width, bm.Height);
    bf.BlendOp := AC_SRC_OVER;
    bf.BlendFlags := 0;
    bf.SourceConstantAlpha := 255;
    bf.AlphaFormat := AC_SRC_ALPHA;
    UpdateLayeredWindow(Handle, 0, nil, @S, bm.Canvas.Handle, @P, 0, @bf,      ULW_ALPHA)
  finally
    bm.Free;
  end;
end;

2 个答案:

答案 0 :(得分:12)

如何调试此内容。

  1. 在项目选项中启用调试DCU,禁用优化。
  2. 当您退出资源错误时,请点击“Break”。
  3. 检查调用堆栈:
  4. enter image description here

    调用CopyBitmap时,问题发生在GDICheck - &gt;双击GDICheck去那里。

    放一个断点。运行程序 - 计算错误出现之前所需的次数,并在预期错误之前中断。

    浏览一下可能奇怪的事情。一个好的起点是位图本身。你的第一个线索应该是,每当你调用这种方法时,你的文字就会爬到你看不见的形状的角落里。

    让我们检查位图标题,看看发生了什么:

    enter image description here

    您的位图尺寸看起来是负面的。我想知道这是怎么发生的。事实上,如果你每次调用它时都会看到,你的位图每次都在缩小。实际上,它的宽度缩小了16px,高度缩小了38px--窗框的大小。

    每次调用UpdateLayeredWindow时,您都要调整窗体(外部尺寸)的大小,使其大小为客户区的大小 - 大小窗口框架。您的新窗口将获得一个新框架,客户区域将缩小。

    最终没有任何内容,您正在尝试制作具有负尺寸的位图。因此,在构建位图时应考虑帧大小。使用表单宽度和高度而不是客户端大小:

     bm.Width := Width;
     bm.height := Height;
    

    此外,在进行API调用时,请养成检查错误返回值的习惯,如相关函数的文档中所述。如果您没有检查错误,那么您就会遇到问题。

答案 1 :(得分:2)

如果没有您的反馈,这仍然是一个猜测,但是通过表单客户区大小的设备上下文,每次调用UpdateLayeredWindow时都会缩小表单的大小。最终,当您为位图维度请求负值时,代码路径中的CreateCompatibleBitmap会返回错误。