2017-03-16 28 views
1

任务:我有2个监视器。我需要在#1上展示#2发生了什么。换句话说,第一台显示器不过是第二台显示器。WPF应用程序中BitmapSource的OutOfMemory异常

当前解决方案:只需制作截图,每~100ms并重新渲染。 以下方法是负责捕捉截图:

private BitmapSource MakeScreenshot(Screen screen) 
    { 
     using (var screenBmp = new Bitmap(screen.Bounds.Width, screen.Bounds.Height, PixelFormat.Format32bppArgb)) 
     { 
      using (var bmpGraphics = Graphics.FromImage(screenBmp)) 
      { 
       bmpGraphics.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size); 

       return 
        Imaging.CreateBitmapSourceFromHBitmap(
         screenBmp.GetHbitmap(), 
         IntPtr.Zero, 
         Int32Rect.Empty, 
         BitmapSizeOptions.FromEmptyOptions()); 
      } 
     } 
    } 

从那以后,我开始USET(...)方法来运行我从第二屏幕第一 “反思”:

public void Start(int delay, int period) 
    { 
     if (_timer != null) throw new InvalidOperationException(); 

     _timer = new System.Threading.Timer(
      _ => 
      { 
       _placeholder 
        .Dispatcher 
        .Invoke(() => 
        { 
         _placeholder.Source = MakeScreenshot(_targetScreen); // re-render new screenshot 
        }); 
      }, 
      null, 
      delay, 
      period); 
    } 

问题:在大约30-40秒的相当不错的运行后,它会因OutOfMemoryException而失败。我在这里调查了一些帖子,但没有发现任何关于我的问题。

+0

你是否在不需要它们之后清理屏幕截图? – lokusking

+0

@lokusking第一:我用IDisposable使用(...)。 BitmapSource不实现IDisposable,并且没有类似.Clean()方法。 –

回答

3

那是因为你在这里泄漏内存:

Imaging.CreateBitmapSourceFromHBitmap(
    screenBmp.GetHbitmap(), // < here 
    IntPtr.Zero, 
    Int32Rect.Empty, 
    BitmapSizeOptions.FromEmptyOptions()); 

你需要释放由GDI的位图使用你叫screenBmp.GetHbitmap()后记忆。改变是这样的:

private BitmapSource MakeScreenshot(Screen screen) 
{ 
    using (var screenBmp = new Bitmap(screen.Bounds.Width, screen.Bounds.Height, PixelFormat.Format32bppArgb)) 
    { 
     using (var bmpGraphics = Graphics.FromImage(screenBmp)) 
     { 
      bmpGraphics.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size); 
      var handle = screenBmp.GetHbitmap(); 
      try { 
       return 
        Imaging.CreateBitmapSourceFromHBitmap(
         handle, 
         IntPtr.Zero, 
         Int32Rect.Empty, 
         BitmapSizeOptions.FromEmptyOptions()); 
      } 
      finally { 
       DeleteObject(handle); 
      } 
     } 
    } 
} 

[System.Runtime.InteropServices.DllImport("gdi32.dll")] 
public static extern bool DeleteObject(IntPtr hObject); 

它不应该再泄漏。

+0

谢谢你的回答。 –