2016-09-16 157 views
1

我工作在一个小型的实时项目,其中一个快速的位图渲染技术是非常必要的。我需要每秒在一个picturebox中显示很多(数百个)小块,我从pinvoke.net网站上找到bitblt示例。C#bitblt位图渲染控制

我使用while循环(现在它是无限的),检索一个特定的位图,然后调用Invalidate()方法来触发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); 

有没有人有一个想法是什么这里错了吗?我不断释放使用的资源(在绘画事件中)......为什么我得到这个错误?

在此先感谢。

+0

在例外情况下'ParamName'的值是什么?这应该给你一个提示,你有什么对象有问题:'pTarget','bmp','pSource'等 – Gabrielius

回答

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); 
} 
+0

对不起,迟到的回应..我想你是对的,但现在我要'系统.ArgumentException'在运行'bitblt'调用运行几秒钟后。 'BitBlt(pTarget,0,0,bmp.Width,bmp.Height,pSource,0,0,TernaryRasterOperations.SRCCOPY);'@Rowland Shaw – Slashy

2

有没有人有一个想法,这里有什么问题?我不断释放使用的资源(在绘画事件中)......为什么我得到这个错误?

其实你是不释放所有使用的资源,特别是位图处理由bmp.GetHbitmap()调用返回。正确的顺序是选择回到原来的默认位图句柄到设备上下文,然后删除您的位图处理,如SelectObjectdocumentation解释说:

该函数返回指定类型的先前选择的对象。一个应用程序应该总是用新对象完成绘图后用原始默认对象替换新对象。

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); 
+0

我在运行几秒后仍然收到同样的错误..哈哈@Ivan Stoev – Slashy

+0

然后你还有其他问题。例如,什么是'desktopDuplicator.GetLatestFrame();'(你将它分配给变量'框架'W/O处置以前的值。什么是“frame.DesktopImage”,并且再次将它分配给不包含前一个值的'bmp'变量。另外'bmp'变量在线程之间不受保护。所以,我在答案中写的内容仍然适用,但您需要为其他部分提供更多信息(代码)。提供一些简单的'mcve'就像我之前为您提出的问题所做的那样复制问题将有助于解决问题。 –

+0

好吧......但我必须说,像'DrawImage()'这样的gdi +方法的工作方式会更快...... – Slashy