C# PrintWindow - GetHdc 在多次迭代后崩溃
C# PrintWindow - GetHdc crashes after many iterations
这里是第一个问题,所以如果我可以改进此帖子,请随时告诉我 :)
我目前正在用 C# 编写一个相当简单的 .Net 应用程序,它使用 "user32.dll" 中的 "PrintWindow" 来截取其他应用程序的屏幕截图,即使它 运行 落后于另一个 window.
我的目标是让我的程序运行无休止地/很长一段时间,但我遇到了我无法解决的问题。
在大约 10.000 个屏幕截图时,我的应用程序总是崩溃。这是我在控制台应用程序中用于重现该错误及其附带的错误的代码:
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
在我的实际应用程序中,显然不应该如此快速地捕获图像,但几个小时后就会出现同样的错误。
我是否必须为我的项目放弃 PrintWindow?我宁愿坚持使用它,因为这是迄今为止我发现的唯一捕获后台 window 的方法。
好的!
我发现了问题,希望这对将来的人有帮助。在 GDIView 的帮助下,我发现我的应用程序泄漏了 "DC" 个对象。如果创建了超过 10.000 个对象(我应该首先查看),GDI 将拒绝工作。
之后没有被删除的DC隐藏在下面一行:
using (Graphics grfx = Graphics.FromHdc(GetWindowDC(hWnd)))
如果添加以下引用:
[DllImport("gdi32.dll")]
static extern IntPtr DeleteDC(IntPtr hDc);
并像这样修改代码:
IntPtr WindowDC = GetWindowDC(hWnd);
using (Graphics grfx = Graphics.FromHdc(WindowDC))
{
rctForm = Rectangle.Round(grfx.VisibleClipBounds);
}
DeleteDC(WindowDC);
然后DC对象被正确删除,程序不再超过10.000个DC对象,因此不会再崩溃。
这里是第一个问题,所以如果我可以改进此帖子,请随时告诉我 :) 我目前正在用 C# 编写一个相当简单的 .Net 应用程序,它使用 "user32.dll" 中的 "PrintWindow" 来截取其他应用程序的屏幕截图,即使它 运行 落后于另一个 window.
我的目标是让我的程序运行无休止地/很长一段时间,但我遇到了我无法解决的问题。
在大约 10.000 个屏幕截图时,我的应用程序总是崩溃。这是我在控制台应用程序中用于重现该错误及其附带的错误的代码:
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
在我的实际应用程序中,显然不应该如此快速地捕获图像,但几个小时后就会出现同样的错误。
我是否必须为我的项目放弃 PrintWindow?我宁愿坚持使用它,因为这是迄今为止我发现的唯一捕获后台 window 的方法。
好的! 我发现了问题,希望这对将来的人有帮助。在 GDIView 的帮助下,我发现我的应用程序泄漏了 "DC" 个对象。如果创建了超过 10.000 个对象(我应该首先查看),GDI 将拒绝工作。 之后没有被删除的DC隐藏在下面一行:
using (Graphics grfx = Graphics.FromHdc(GetWindowDC(hWnd)))
如果添加以下引用:
[DllImport("gdi32.dll")]
static extern IntPtr DeleteDC(IntPtr hDc);
并像这样修改代码:
IntPtr WindowDC = GetWindowDC(hWnd);
using (Graphics grfx = Graphics.FromHdc(WindowDC))
{
rctForm = Rectangle.Round(grfx.VisibleClipBounds);
}
DeleteDC(WindowDC);
然后DC对象被正确删除,程序不再超过10.000个DC对象,因此不会再崩溃。