Я пишу приложение для удаленного рабочего стола, как TeamViewer в C ++ на Windows 7 (x64) и Windows 8 (x64).
1. Что заставило меня застрять
Я реализовал ввод с помощью мыши и клавиатуры с помощью SendInput (). Я обнаружил, что SendInput () работал отлично, когда процесс запущен под winsta0\desktop
, Но после того, как пользователь заблокировал компьютер или заставку запустил, он не работал.
Если я запускаю процесс под winsta0\winlogon
, SendInput()
не работает под winsta0\default
,
2. Что я пробовал
Я пытался использовать SetThreadDesktop (), чтобы переключить процесс с winsta0\desktop
в winsta0\winlogon
, но я получил ошибку 170: «Запрошенный ресурс используется», и я застрял.
3. Что я хочу знать
Я заметил, что в TeamViewer есть процесс с именем TeamViewer_Desktop.exe
который может управлять мышью и клавиатурой под Winlogon, Default и Screensaver. Как это сделать?
Можете ли вы предоставить код, который поможет мне понять, как решить мой вопрос?
Я хочу знать, ** как я могу переключать свое приложение между рабочим столом по умолчанию и рабочим столом Winlogon. Таким образом, я могу управлять мышью и клавиатурой на защищенном рабочем столе, не создавая другой процесс под управлением winlogon.exe
,
Ты поступил правильно: SetThreadDesktop
верно. Ошибка говорит вам, что у вас есть открытые ресурсы на текущем рабочем столе, такие как окно, и это не позволяет вам переключаться. Если бы вы попытались создать минимальный контрольный пример (как вы должны задавать здесь, задавая вопросы!), Вы бы это узнали.
Вырежьте части своей программы, пока не найдете кусок, который мешает вам переключиться на рабочий стол. Некоторые Windows API являются неприятными и не позволяют вам переключаться между рабочими столами, поэтому их нужно вызывать в отдельном потоке.
Как сказал @NicholasWilson, SetThreadDesktop()
это правильный способ переключения процесса между рабочим столом по умолчанию и рабочим столом winlogon.
Ошибка 170 «Запрошенный ресурс используется» произошла из-за того, что я позвонил MessageBox()
до SetThreadDesktop()
называется. Также звоню CreateWindow()
может вызвать ошибку.
Я думаю, что любая функция, связанная с созданием GUI, вызывается раньше SetThreadDesktop()
Вызванный может вызвать ошибку. Так что если вы хотите призвать SetThreadDesktop()
успешно, вы должны быть уверены, что не вызывать какую-либо функцию создания GUI, прежде чем вызывать SetThreadDesktop()
,
Код
Код здесь, как переключить процесс на указанный рабочий стол.
Использование: 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);
}
}