Graphics.CopyFromScreen() 和 GetDC(0) 失败 "The handle is invalid"

Graphics.CopyFromScreen() and GetDC(0) fail with "The handle is invalid"

我有一个从本地计算机截取屏幕截图的应用程序。 这多年来一直有效,直到一位同事突然向我报告他从我的应用程序中收到 "The handle is invalid" 错误。

此错误来自 Graphics.CopyFromScreen() 的 .NET 框架内部。

为了解决这个问题,我用 C++ 代码替换了这个函数,使用 GetDC(GetDesktopWindow()) / GetDC(NULL)BitBlt() 将屏幕复制到位图中。现在我得到 ERROR_INVALID_HANDLE.

这发生在 Windows 7.

那里发生了什么事? 我无法自行调查这个问题,因为我无法重现它,而且我的同事在另一个国家。

我在Google中搜索,很多人报告这个错误。 但我发现的所有帖子都来自那些试图通过服务器上的 ASP 代码从客户端计算机截取屏幕截图的人。我不明白人们怎么会有从网站上捕获客户计算机的奇怪愿望。很明显这样不行。

但我找不到一个案例,有人报告此问题的应用程序无法在 SAME 会话中捕获同一台计算机的屏幕,而应用程序本身是 运行。

在与我的同事进行更多调查并向他提供可以尝试的想法后,他告诉我他通过远程桌面会话启动我的应用程序。

远程桌面会话创建了一个虚拟桌面(例如,您看到桌面壁纸丢失了)。

我告诉我的同事安装一个 VNC 客户端来远程控制计算机而不是远程桌面会话,现在一切正常。他安装了 TightVNC,它使用 REAL 桌面用户会话,而不是创建虚拟会话并锁定机器屏幕。

因此,如果有人在截屏时收到 "The handle is invalid" 的报告,请询问您的用户是否使用远程桌面会话。

要在代码中检测远程桌面会话,您可以编写:

在 C++ 中:

if (GetSystemMetrics(SM_REMOTESESSION) > 0)
{
    MessageBox(m_hWnd, L"This application may not work correctly in a remote desktop session", "Error", MB_ICONSTOP);
}

或在 C# 中:

if (System.Windows.Forms.SystemInformation.TerminalServerSession)
{
    Messagebox.Show("This application may not work correctly in a remote desktop session");
}

请注意,该问题并非在所有计算机上都能重现。当我自己测试时 Windows 7 它有效。所以可能有任何其他系统设置或其他因素触发 "The handle is invalid" 错误(服务包/修补程序...?)。

但是我的同事报告说他在停止使用远程桌面连接后再也没有看到错误。

发生这种情况的原因有几个,但根本原因是调用此方法时桌面 window 不可用。

除了上述原因外,还有一个原因是锁屏时调用此方法。

CopyFromScreen 的代码包含以下部分:

int result = SafeNativeMethods.BitBlt(targetDC, destinationX, destinationY, destWidth, destHeight, screenDC, sourceX, sourceY, (int) copyPixelOperation); 

//a zero result indicates a win32 exception has been thrown
if (result == 0) { 
    throw new Win32Exception();
}

在我看来,最安全的做法是,如果您使用此功能,请确保您编写的代码也假定接收到 Win32Exception 或不可用的桌面 Window一个必须处理的用例,这样应用程序才不会崩溃。