我正在开展一个小型实时项目,其中非常需要快速位图渲染技术。我需要每秒在图片框中显示许多(数百个)小块,我在pinvoke.net网站上找到了Invalidate()
示例。
我使用while循环(现在它是无限的)来检索特定的位图,然后调用Paint
方法来触发 protected override void OnPaint(PaintEventArgs e)
{
IntPtr pTarget = e.Graphics.GetHdc();
IntPtr pSource = CreateCompatibleDC(pTarget);
IntPtr pOrig = SelectObject(pSource, bmp.GetHbitmap());
BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);
DeleteObject(pOrig);
DeleteDC(pSource);
e.Graphics.ReleaseHdc(pTarget);
}
private void Display()
{
while (true)
{
frame = desktopDuplicator.GetLatestFrame();
if (frame != null)
{
bmp = frame.DesktopImage;//retrieve image.
this.Invoke(new Action(() => this.Invalidate()));//trigger the repaint event
}
}
}
事件。
这是我的代码:
System.ArgumentException
它可以正常工作几秒钟,然后我在这一行得到 BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);
:
{{1}}
有没有人知道这里有什么问题?我一直在释放使用过的资源(在油漆事件中)......为什么我会收到这个错误?
提前致谢。
答案 0 :(得分:2)
有没有人知道这里有什么问题?我一直在释放使用过的资源(在油漆事件中)......为什么我会收到这个错误?
实际上你不释放所有使用的资源,特别是bmp.GetHbitmap()
调用返回的位图句柄。正确的顺序是选择将原始默认位图句柄返回到设备上下文中,然后删除位图句柄,如SelectObject
documentation中所述:
此函数返回先前选定的指定类型的对象。应用程序应该在使用新对象完成绘制后,始终用原始的默认对象替换新对象。
IntPtr targetDC = e.Graphics.GetHdc();
IntPtr sourceDC = CreateCompatibleDC(targetDC);
IntPtr sourceBitmap = bmp.GetHbitmap();
IntPtr originalBitmap = SelectObject(sourceDC, sourceBitmap);
BitBlt(targetDC, 0, 0, bmp.Width, bmp.Height, sourceDC, 0, 0, TernaryRasterOperations.SRCCOPY);
SelectObject(sourceDC, originalBitmap);
DeleteObject(sourceBitmap);
DeleteDC(sourceDC);
e.Graphics.ReleaseHdc(targetDC);
答案 1 :(得分:1)
来自Bitmap.GetHbitmap
方法的文档:
您负责调用GDI DeleteObject方法来释放GDI位图对象使用的内存。
您目前似乎没有调用它,这将导致泄漏。完成资源后,您应该致电DeleteObject
,所以可能会这样:
protected override void OnPaint(PaintEventArgs e)
{
IntPtr pTarget = e.Graphics.GetHdc();
IntPtr pSource = CreateCompatibleDC(pTarget);
IntPtr pOrig = SelectObject(pSource, bmp.GetHbitmap());
BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);
DeleteObject(pOrig);
DeleteDC(pSource);
e.Graphics.ReleaseHdc(pTarget);
}