我正在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
下运行另一个进程。
答案 0 :(得分:7)
你做对了:SetThreadDesktop
是正确的。该错误告诉您在当前桌面上打开了一些资源,例如窗口,这会阻止您切换。如果你曾尝试制作一个最小的测试用例(就像你在这里提问时要做的那样!)你会发现它。
删除程序的某些部分,直到找到阻止您切换桌面的块。有些Windows API很讨厌并且阻止你切换桌面,因此需要在专用线程中调用。
答案 1 :(得分:4)
正如@NicholasWilson所说,SetThreadDesktop()
是在默认桌面和winlogon桌面之间切换进程的正确方法。
错误170,“请求的资源正在使用中”,因为我在调用MessageBox()
之前调用了SetThreadDesktop()
。同时调用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);
}
}