First question on here, so if I can improve this posting feel free to tell me :) I'm currently programming a rather simple .Net application in C# that uses "PrintWindow" from "user32.dll" in order to take screenshots of an other application even if it runs behind another window.
I aim to let my program run endlessly / for a long period of time, but I encounter I problem I cannot solve.
At around 10.000 Screenshots my application always crashes. Here is the Code I used in a console application to reproduce the bug and the error that comes with it:
class Program
{
/* Get Image even if Process is running behind another window ******************* */
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
/* ****************************************************************************** */
static void Main(string[] args)
{
Process process = ReturnProcess();
int counter = 0;
Console.WriteLine(RotMG.ToString());
while (true)
{
Bitmap bmpTest = CaptureWindow(RotMG.MainWindowHandle);
bmpTest.Dispose();
counter++;
Console.WriteLine(counter.ToString());
}
}
private static Process ReturnProcess()
{
Process[] processes = Process.GetProcessesByName("desiredProcess");
return processes[0];
}
public static Bitmap CaptureWindow(IntPtr hWnd)
{
Rectangle rctForm = System.Drawing.Rectangle.Empty;
using (Graphics grfx = Graphics.FromHdc(GetWindowDC(hWnd)))
{
rctForm = Rectangle.Round(grfx.VisibleClipBounds);
}
Bitmap pImage = new Bitmap(rctForm.Width, rctForm.Height);
Graphics graphics = Graphics.FromImage(pImage);
IntPtr hDC = graphics.GetHdc();
try
{
PrintWindow(hWnd, hDC, (uint)0);
}
finally
{
graphics.ReleaseHdc(hDC);
graphics.Dispose();
}
return pImage;
}
}
IntPtr hDC = graphics.GetHdc(); System.ArgumentException: Parameter not valid
In my real application it obviously is not supposed to capture images that fast, but the same error occurs after an a few hours.
I code the important code from here: https://codereview.stackexchange.com/questions/29364/capturing-and-taking-a-screenshot-of-a-window-in-a-loop
Do I have to ditch PrintWindow for my project? I would rather stick to it as it is the only way I found so far to capture a window which is in background.
All right! I found the problem, hopefully this helps someone in the future. With the help of GDIView I found that my application leaked "DC" objects. GDI refuses to work if more than 10.000 Objects are created (which I should have looked up in the first place). The DC that is not being deleted afterwards hides in the following line:
using (Graphics grfx = Graphics.FromHdc(GetWindowDC(hWnd)))
If you add the following reference:
[DllImport("gdi32.dll")]
static extern IntPtr DeleteDC(IntPtr hDc);
and modify the code like this:
IntPtr WindowDC = GetWindowDC(hWnd);
using (Graphics grfx = Graphics.FromHdc(WindowDC))
{
rctForm = Rectangle.Round(grfx.VisibleClipBounds);
}
DeleteDC(WindowDC);
Then the DC object is deleted correctly, the program no longer exceeds 10.000 DC objects and thus does not crash anymore.