2016-09-16 67 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