我有一个从本地计算机获取屏幕截图的应用程序。自从多年以来,这种方法一直有效,直到一个同事突然告诉我他从我的应用程序中收到“句柄无效”错误。
此错误来自.NET框架内部 Graphics.CopyFromScreen()。
要解决这个我用C ++代码此功能使用替换GetDC(GetDesktopWindow())/ GetDC(NULL)和BitBlt()屏幕复制到一个位图。现在我得到了ERROR_INVALID_HANDLE。
在Windows 7上会发生这种情况。
那是怎么回事?我无法独自研究此问题,因为我无法重现此问题,并且我的同事在另一个国家。
我在Google中搜索,很多人报告此错误。但是我发现的所有帖子都来自试图通过服务器上的ASP代码从客户端计算机获取屏幕截图的人员。我不明白人们怎么会有从网站捕获客户计算机的奇怪愿望。显然,这是行不通的。
但是我无法找到一种情况,即有人从无法在运行应用程序本身的SAME会话中捕获SAME计算机屏幕的应用程序报告此问题。
After investigating more with my colleague and giving him ideas what he can try, he told me that he starts my application through a remote desktop session.
The remote desktop session creates a virtual desktop (you see for example that the desktop wallpaper is missing).
I told my colleague to install a VNC client to remote control the computer instead of a remote desktop session and now all works fine. He installed TightVNC which uses the REAL desktop user session instead of creating a virtual session and locking the screen of the machine.
So if anyone gets reports of "The handle is invalid" while taking a screen capture, ask your users if they use a remote desktop session.
To detect a remote desktop session in code you can write:
in C++:
if (GetSystemMetrics(SM_REMOTESESSION) > 0)
{
MessageBox(m_hWnd, L"This application may not work correctly in a remote desktop session", "Error", MB_ICONSTOP);
}
Run Code Online (Sandbox Code Playgroud)
or in C#:
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
{
Messagebox.Show("This application may not work correctly in a remote desktop session");
}
Run Code Online (Sandbox Code Playgroud)
Note that the problem is not reproducible on all computers. When I test on my own Windows 7 it works. So there are probably any additional system settings or other factors that trigger the "The handle is invalid" error (service packs / hotfixes...?).
But my colleague reports that he has never seen the error again after he stopped using the remote desktop connection.
发生这种情况的原因有很多,但潜在的主题是调用此方法时桌面窗口不可用。
除了上述原因外,发生这种情况的另一个原因是在锁定屏幕时是否正在调用此方法。
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();
}
Run Code Online (Sandbox Code Playgroud)
在我看来,最安全的做法是,如果您使用此功能,请确保您也编写代码,并假设接收Win32Exception或不可用的Desktop Window是必须处理的用例,因此应用程序不会崩溃。