Graphics.CopyFromScreen()和GetDC(0)出现“句柄无效”的错误

9
我有一个应用程序,可以从本地计算机截取屏幕截图。多年来一切正常,直到我的同事报告说他从我的应用程序中得到了“句柄无效”的错误。
此错误来自.NET框架内的Graphics.CopyFromScreen()
为了解决这个问题,我使用GetDC(GetDesktopWindow())/GetDC(NULL)BitBlt()将此功能替换为C++代码来复制屏幕到位图。现在我得到了ERROR_INVALID_HANDLE
这是在Windows 7上发生的。
那里发生了什么? 我无法独自调查这个问题,因为我无法重现它,而我的同事则在另一个国家。
我在Google中搜索并且很多人报告此错误。 但我找到的所有帖子都是来自试图通过服务器上的ASP代码从客户端计算机中获取屏幕截图的人们。我不明白人们怎么会有奇怪的愿望从网站抓取客户端计算机。这显然行不通。
但是我找不到一个单一的案例,其中有人报告说无法从相同会话中的SAME计算机捕捉屏幕的应用程序遇到此问题。

1
这个异常几乎总是由句柄泄漏引起的,当操作系统阻止进程创建更多句柄或桌面堆耗尽时,程序就会崩溃。在任务管理器的“进程”选项卡中可以很容易地诊断出来。使用“查看”>“选择列”并选中“用户对象”和“GDI对象”。不断上升的数字预示着厄运的到来。 - Hans Passant
似乎你没有阅读我的回答。 - Elmue
远程桌面会话共享您的屏幕。这意味着,例如当您最小化远程桌面应用程序时,就没有屏幕可以捕获了。您确定问题确实一直发生吗?只要您正确连接并且远程桌面应用程序可见和活动,它应该能正常工作。也许您只需要优雅地处理故障,并在再次获取屏幕时恢复操作? - Luaan
这个问题也发生在我身上。只有在WINDOWS10上出现。这个程序已经运行了好几年。而且我没有使用远程桌面连接! - 8vtwo
2个回答

9
经过与同事的进一步调查并给他一些尝试的建议后,他告诉我他是通过远程桌面会话启动我的应用程序的。
远程桌面会话创建了一个虚拟桌面(例如,您会发现桌面壁纸缺失)。
我告诉同事安装VNC客户端来远程控制计算机,而不是使用远程桌面会话,现在一切都正常了。他安装了TightVNC,它使用真实的桌面用户会话,而不是创建虚拟会话并锁定机器屏幕。
因此,如果有人在进行屏幕截图时收到“句柄无效”的报告,请问您的用户是否使用远程桌面会话。
要在代码中检测远程桌面会话,您可以编写:
在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上测试时,它是可以正常工作的。因此可能存在其他系统设置或其他因素触发“句柄无效”错误(服务包/热修复程序等)。
但是我的同事报告说,他停止使用远程桌面连接后再也没有看到过这个错误。

你的回答有点像是 TightVNC 的宣传。除非 TightVNC 是目前和未来唯一能够像你描述的软件,否则你应该让它更加通用。我不是那个给你投反对票的人。此外,你永远无法知道某个人为什么会这样做。我甚至也犯过几次错误。虽然很令人沮丧,但最好还是继续前进。如果你能让答案更加通用,就会有回报。 - Bill Woodger
1
我不是 TightVNC 的作者。但如果有人正在寻找远程桌面会话的替代方案,为什么不立即给他一个被证明可行的解决方案呢?我看不出引用一个有效的解决方案有什么问题。我不确定所有的 VNC 客户端是否都工作方式相同。 - Elmue
包括“我不确定……”这一部分的问题翻译成中文:有意图,还有无论意图如何看起来都可能存在的问题。另一个问题是,对于回答来说,有些人可能会把它看作是“软件推荐”问题而被关闭。随着真正想要推广VNC客户端的人在互联网上搜寻,他们会找到你的问题,并发布垃圾信息。这是一个棘手的问题。 - Bill Woodger
好的。结束这个讨论:我不参与TightVNC的开发,也不感兴趣去推广它。我只是为那些需要一个良好工作的VNC程序的人提供了一个提示,以节省他们在谷歌上搜索的时间。如果Stackoverflow因为我给出了一个好的提示而惩罚我,那将是非常遗憾的。Stackoverflow的初衷是帮助他人,而我所做的正是这一点。 - Elmue
我可以确认这个问题发生在远程桌面上,但它并不依赖于机器。在我的设置中,有时会出现这个问题,有时则不会(同一台机器、同一程序、同一设置、同一天、同一启动等)。使用Windows Server 2019标准版进行测试。 - Guillermo Prandi
显示剩余4条评论

6

这种情况发生的原因有几种,但根本原因是在调用该方法时桌面窗口不可用。

除了上述提到的原因,另一个可能导致此问题的原因是在屏幕锁定时调用该方法。

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或不可用的桌面窗口是必须处理的用例,以免应用程序崩溃。


这段代码在许多不同的计算机上完美运行了多年,突然间每秒都会抛出“无效句柄”的错误???刚刚升级到WIN 10。 - 8vtwo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接