我正在使用Windows 7(x64)和Windows 8(x64)上的C ++编写远程桌面应用程序,如TeamViewer 。
1.什么让我卡住了
我已经通过使用SendInput()实现了鼠标input和键盘input。 当进程在winsta0\desktop
下运行时,我发现SendInput()完美工作。 但是,用户locking电脑或屏幕保护程序启动后,它不起作用。
如果我在winsta0\winlogon
下运行该进程, SendInput()
在winsta0\default
下winsta0\default
。
2.我所尝试过的
我已经尝试使用SetThreadDesktop()从winsta0\desktop
切换到winsta0\winlogon
,但我得到错误170:“请求的资源正在使用”,我stucked。
3.我想知道的
我注意到,TeamViewer有一个名为TeamViewer_Desktop.exe
的进程,可以在Winlogon,Default和Screensaver下控制鼠标和键盘。 它是如何做到的?
你能提供代码来帮助我理解如何解决我的问题吗?
我想知道**如何使我的应用程序在默认的桌面和Winlogon桌面之间切换。 所以我可以在安全的桌面上控制鼠标和键盘,而无需在winlogon.exe
下创build另一个进程。
你做了正确的事情: SetThreadDesktop
是正确的。 这个错误告诉你,当前桌面上有一些资源打开,比如一个窗口,这样可以防止你切换。 如果你试图制作一个最小的测试案例(就像你在这里问问题时所要做的那样),你会发现这一点。
删除程序的某些部分,直到找到阻止切换桌面的块。 一些Windows API是讨厌的,并且阻止你切换桌面,所以需要在专用线程中调用。
正如@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); } }