如何在默认桌面和 Winlogon 桌面之间切换进程?
Posted
技术标签:
【中文标题】如何在默认桌面和 Winlogon 桌面之间切换进程?【英文标题】:How to switch a process between default desktop and Winlogon desktop? 【发布时间】:2013-04-15 08:22:52 【问题描述】:我正在 Windows 7 (x64) 和 Windows 8 (x64) 上用 C++ 编写一个远程桌面应用程序,例如 TeamViewer。
1.是什么让我卡住了
我已经使用 SendInput() 实现了鼠标输入和键盘输入。我发现当进程在winsta0\desktop
下运行时,SendInput() 工作得很好。但是在用户锁定计算机或启动屏保后,它就不起作用了。
如果我在winsta0\winlogon
下运行进程,SendInput()
在winsta0\default
下不起作用。
2。我尝试过的
我尝试使用 SetThreadDesktop() 将进程从 winsta0\desktop
切换到 winsta0\winlogon
,但出现错误 170:“请求的资源正在使用中”,我卡住了。
3.我想知道的
我注意到 TeamViewer 有一个名为TeamViewer_Desktop.exe
的进程,可以在 Winlogon、Default 和 Screensaver 下控制鼠标和键盘。它是怎么做到的?
您能否提供代码以帮助我了解如何解决我的问题?
我想知道**如何让我的应用程序在默认桌面和 Winlogon 桌面之间切换。所以我可以在安全的桌面上控制鼠标和键盘,而无需创建另一个在winlogon.exe
下运行的进程。
【问题讨论】:
如果您想要示例代码,请使用开源 VNC 项目之一。在这里要求演示代码要求太多。这个问题太笼统了。 @DavidHeffernan 感谢您的建议。我将尝试从开源 VNC 项目中阅读并找出我的问题的代码。我编辑了我的问题并清楚地说明了。 【参考方案1】:你做对了:SetThreadDesktop
是正确的。该错误告诉您,您在当前桌面上打开了一些资源,例如窗口,这会阻止您切换。如果您曾尝试制作一个最小的测试用例(正如您在这里提问时应该做的那样!),您就会发现这一点。
删除程序的某些部分,直到找到阻止您切换桌面的部分。一些 Windows API 很讨厌,会阻止您切换桌面,因此需要在专用线程中调用。
【讨论】:
你是对的!非常感谢!我已经尝试并制作了一个最小的测试用例。我创建了一个控制台项目并测试了 SetThreadDesktop() 代码。有用!下一步我会找出是什么阻止了 SetThreadDesktop() 在 winform 项目中成功。 @Leon,我已经在 Delphi (question here) 中尝试过,但没有成功:-(。一些建议? 在调用 SetThreadDesktop 之前不要使用 user32.dll 中的任何内容。【参考方案2】:正如@NicholasWilson 所说,SetThreadDesktop()
是在默认桌面和 winlogon 桌面之间切换进程的正确方法。
出现错误 170,“请求的资源正在使用中”,因为我在调用 SetThreadDesktop()
之前调用了 MessageBox()
。调用CreateWindow()
也会导致错误。
我认为在调用SetThreadDesktop()
之前调用的任何与GUI 创建相关的函数都可能导致错误。所以如果要成功调用SetThreadDesktop()
,在调用SetThreadDesktop()
之前一定要确保不要调用任何GUI创建函数。
代码
这里的代码是如何将进程切换到指定的桌面。
用法: SetWinSta0Desktop(TEXT("winlogon"))
, SetWinSta0Desktop(TEXT("default"))
SetWinSta0Desktop()
函数:
BOOL SetWinSta0Desktop(TCHAR *szDesktopName)
BOOL bSuccess = FALSE;
HWINSTA hWinSta0 = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED);
if (NULL == hWinSta0) ShowLastErrorMessage(GetLastError(), TEXT("OpenWindowStation"));
bSuccess = SetProcessWindowStation(hWinSta0);
if (!bSuccess) ShowLastErrorMessage(GetLastError(), TEXT("SetProcessWindowStation"));
HDESK hDesk = OpenDesktop(szDesktopName, 0, FALSE, MAXIMUM_ALLOWED);
if (NULL == hDesk) ShowLastErrorMessage(GetLastError(), TEXT("OpenDesktop"));
bSuccess = SetThreadDesktop(hDesk);
if (!bSuccess) ShowLastErrorMessage(GetLastError(), TEXT("SetThreadDesktop"));
if (hDesk != NULL) CloseDesktop(hDesk);
if (hWinSta0 != NULL) CloseWindowStation(hWinSta0);
return bSuccess;
ShowLastErrorMessage()
函数:
void ShowLastErrorMessage(DWORD errCode, LPTSTR errTitle)
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText,
0,
NULL);
if ( NULL != errorText )
WCHAR msg[512] = 0;
wsprintf(msg, TEXT("%s:\nError Code: %u\n%s\n"), errTitle, errCode, errorText);
LocalFree(errorText);
errorText = NULL;
OutputDebugString(msg);
【讨论】:
以上是关于如何在默认桌面和 Winlogon 桌面之间切换进程?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 C#/pinvoke 将输入发送到 WinSta0\Winlogon 桌面
如何在 Windows 上获取 Active Desktop 类型?