diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 569e1a2e..08321889 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -404,6 +404,14 @@ void MainWindow::startSynergy() { // tell client/server to talk to daemon through ipc. args << "--ipc"; + +#if defined(Q_OS_WIN) + // tell the client/server to shut down when a ms windows desk + // is switched; this is because we may need to elevate or not + // based on which desk the user is in (login always needs + // elevation, where as default desk does not). + args << "--stop-on-desk-switch"; +#endif } if ((synergyType() == synergyClient && !clientArgs(args, app)) diff --git a/src/lib/platform/CMSWindowsDesks.cpp b/src/lib/platform/CMSWindowsDesks.cpp index b8fd8150..9b3f255a 100644 --- a/src/lib/platform/CMSWindowsDesks.cpp +++ b/src/lib/platform/CMSWindowsDesks.cpp @@ -92,7 +92,7 @@ CMSWindowsDesks::CMSWindowsDesks( bool isPrimary, bool noHooks, HINSTANCE hookLibrary, const IScreenSaver* screensaver, IEventQueue& eventQueue, - IJob* updateKeys) : + IJob* updateKeys, bool stopOnDeskSwitch) : m_isPrimary(isPrimary), m_noHooks(noHooks), m_is95Family(CArchMiscWindows::isWindows95Family()), @@ -110,7 +110,8 @@ CMSWindowsDesks::CMSWindowsDesks( m_mutex(), m_deskReady(&m_mutex, false), m_updateKeys(updateKeys), - m_eventQueue(eventQueue) + m_eventQueue(eventQueue), + m_stopOnDeskSwitch(stopOnDeskSwitch) { if (hookLibrary != NULL) queryHookLibrary(hookLibrary); @@ -906,6 +907,14 @@ CMSWindowsDesks::checkDesk() desk = index->second; } + // if we are told to shut down on desk switch, and this is not the + // first switch, then shut down. + if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) { + LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", name.c_str())); + EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); + return; + } + // if active desktop changed then tell the old and new desk threads // about the change. don't switch desktops when the screensaver is // active becaue we'd most likely switch to the screensaver desktop diff --git a/src/lib/platform/CMSWindowsDesks.h b/src/lib/platform/CMSWindowsDesks.h index 115791b0..86791fa4 100644 --- a/src/lib/platform/CMSWindowsDesks.h +++ b/src/lib/platform/CMSWindowsDesks.h @@ -66,7 +66,7 @@ public: CMSWindowsDesks( bool isPrimary, bool noHooks, HINSTANCE hookLibrary, const IScreenSaver* screensaver, IEventQueue& eventQueue, - IJob* updateKeys); + IJob* updateKeys, bool stopOnDeskSwitch); ~CMSWindowsDesks(); //! @name manipulators @@ -305,6 +305,9 @@ private: bool m_leaveForegroundOption; IEventQueue& m_eventQueue; + + // true if program should stop on desk switch. + bool m_stopOnDeskSwitch; }; #endif diff --git a/src/lib/platform/CMSWindowsRelauncher.cpp b/src/lib/platform/CMSWindowsRelauncher.cpp index f69fb62d..abc9480f 100644 --- a/src/lib/platform/CMSWindowsRelauncher.cpp +++ b/src/lib/platform/CMSWindowsRelauncher.cpp @@ -93,7 +93,7 @@ CMSWindowsRelauncher::getSessionId() } BOOL -CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHANDLE process) +CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHANDLE process = NULL) { // first we need to take a snapshot of the running processes HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -175,14 +175,15 @@ CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHAN CloseHandle(snapshot); if (pid) { - // now get the process so we can get the process, with which - // we'll use to get the process token. - LOG((CLOG_DEBUG "found %s in session %i", name, sessionId)); - *process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); + if (process != NULL) { + // now get the process so we can get the process, with which + // we'll use to get the process token. + LOG((CLOG_DEBUG "found %s in session %i", name, sessionId)); + *process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); + } return true; } else { - LOG((CLOG_DEBUG "could not find %s in session %i", name, sessionId)); return false; } } @@ -219,23 +220,29 @@ CMSWindowsRelauncher::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTE return newToken; } -// use either an elevated token (winlogon) or the user's session -// token (non-elevated). processes launched with a non-elevated token -// cannot interact with elevated processes. HANDLE CMSWindowsRelauncher::getUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security) { - if (m_elevateProcess) { + // always elevate if we are at the vista/7 login screen. we could also + // elevate for the uac dialog (consent.exe) but this would be pointless, + // since synergy would re-launch as non-elevated after the desk switch, + // and so would be unusable with the new elevated process taking focus. + if (m_elevateProcess || isProcessInSession("logonui.exe", sessionId)) { + + LOG((CLOG_DEBUG "getting elevated token, %s", + (m_elevateProcess ? "elevation required" : "at login screen"))); + HANDLE process; if (isProcessInSession("winlogon.exe", sessionId, &process)) { return duplicateProcessToken(process, security); } else { - LOG((CLOG_ERR "could not find token in session %d", sessionId)); + LOG((CLOG_ERR "could not find winlogon in session %i", sessionId)); return NULL; } } else { + LOG((CLOG_DEBUG "getting non-elevated token")); return getSessionToken(sessionId, security); } } diff --git a/src/lib/platform/CMSWindowsScreen.cpp b/src/lib/platform/CMSWindowsScreen.cpp index 17834fef..12c725d7 100644 --- a/src/lib/platform/CMSWindowsScreen.cpp +++ b/src/lib/platform/CMSWindowsScreen.cpp @@ -80,7 +80,11 @@ HINSTANCE CMSWindowsScreen::s_windowInstance = NULL; CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL; -CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, bool noHooks, const CGameDeviceInfo& gameDeviceInfo) : +CMSWindowsScreen::CMSWindowsScreen( + bool isPrimary, + bool noHooks, + const CGameDeviceInfo& gameDeviceInfo, + bool stopOnDeskSwitch) : m_isPrimary(isPrimary), m_noHooks(noHooks), m_is95Family(CArchMiscWindows::isWindows95Family()), @@ -124,7 +128,8 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, bool noHooks, const CGameDevi m_hookLibrary, m_screensaver, *EVENTQUEUE, new TMethodJob(this, - &CMSWindowsScreen::updateKeysCB)); + &CMSWindowsScreen::updateKeysCB), + stopOnDeskSwitch); m_keyState = new CMSWindowsKeyState(m_desks, getEventTarget()); updateScreenShape(); m_class = createWindowClass(); diff --git a/src/lib/platform/CMSWindowsScreen.h b/src/lib/platform/CMSWindowsScreen.h index edfd89f7..6039baaf 100644 --- a/src/lib/platform/CMSWindowsScreen.h +++ b/src/lib/platform/CMSWindowsScreen.h @@ -40,7 +40,11 @@ class CThread; //! Implementation of IPlatformScreen for Microsoft Windows class CMSWindowsScreen : public CPlatformScreen { public: - CMSWindowsScreen(bool isPrimary, bool noHooks, const CGameDeviceInfo &gameDevice); + CMSWindowsScreen( + bool isPrimary, + bool noHooks, + const CGameDeviceInfo &gameDevice, + bool stopOnDeskSwitch); virtual ~CMSWindowsScreen(); //! @name manipulators diff --git a/src/lib/synergy/CAppUtilWindows.cpp b/src/lib/synergy/CAppUtilWindows.cpp index a48bc397..de4a8024 100644 --- a/src/lib/synergy/CAppUtilWindows.cpp +++ b/src/lib/synergy/CAppUtilWindows.cpp @@ -87,6 +87,9 @@ CAppUtilWindows::parseArg(const int& argc, const char* const* argv, int& i) else if (app().isArg(i, argc, argv, NULL, "--game-poll-freq")) { app().argsBase().m_gameDevice.m_pollFreq = atoi(argv[++i]); } + else if (app().isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) { + app().argsBase().m_stopOnDeskSwitch = true; + } else { // option not supported here return false; diff --git a/src/lib/synergy/CArgsBase.cpp b/src/lib/synergy/CArgsBase.cpp index b856af50..31d39279 100644 --- a/src/lib/synergy/CArgsBase.cpp +++ b/src/lib/synergy/CArgsBase.cpp @@ -22,6 +22,7 @@ CArgsBase::CArgsBase() : m_daemon(false), // daemon mode not supported on windows (use --service) m_debugServiceWait(false), m_pauseOnExit(false), +m_stopOnDeskSwitch(false), #else m_daemon(true), // backward compatibility for unix (daemon by default) #endif diff --git a/src/lib/synergy/CArgsBase.h b/src/lib/synergy/CArgsBase.h index 4582e519..7db782d5 100644 --- a/src/lib/synergy/CArgsBase.h +++ b/src/lib/synergy/CArgsBase.h @@ -40,6 +40,7 @@ public: bool m_debugServiceWait; bool m_pauseOnExit; CGameDeviceInfo m_gameDevice; + bool m_stopOnDeskSwitch; #endif #if WINAPI_XWINDOWS bool m_disableXInitThreads; diff --git a/src/lib/synergy/CClientApp.cpp b/src/lib/synergy/CClientApp.cpp index e2152397..89666c66 100644 --- a/src/lib/synergy/CClientApp.cpp +++ b/src/lib/synergy/CClientApp.cpp @@ -233,7 +233,8 @@ CScreen* CClientApp::createScreen() { #if WINAPI_MSWINDOWS - return new CScreen(new CMSWindowsScreen(false, args().m_noHooks, args().m_gameDevice)); + return new CScreen(new CMSWindowsScreen( + false, args().m_noHooks, args().m_gameDevice, args().m_stopOnDeskSwitch)); #elif WINAPI_XWINDOWS return new CScreen(new CXWindowsScreen( args().m_display, false, args().m_disableXInitThreads, diff --git a/src/lib/synergy/CDaemonApp.cpp b/src/lib/synergy/CDaemonApp.cpp index b0a1757e..4a757a73 100644 --- a/src/lib/synergy/CDaemonApp.cpp +++ b/src/lib/synergy/CDaemonApp.cpp @@ -221,7 +221,7 @@ CDaemonApp::mainLoop(bool logToFile) // (such as a stop request from the service controller). CMSWindowsScreen::init(CArchMiscWindows::instanceWin32()); CGameDeviceInfo gameDevice; - CScreen dummyScreen(new CMSWindowsScreen(false, true, gameDevice)); + CScreen dummyScreen(new CMSWindowsScreen(false, true, gameDevice, false)); CString command = ARCH->setting("Command"); bool elevate = ARCH->setting("Elevate") == "1"; diff --git a/src/lib/synergy/CServerApp.cpp b/src/lib/synergy/CServerApp.cpp index dacfd3f8..26871952 100644 --- a/src/lib/synergy/CServerApp.cpp +++ b/src/lib/synergy/CServerApp.cpp @@ -645,7 +645,8 @@ CScreen* CServerApp::createScreen() { #if WINAPI_MSWINDOWS - return new CScreen(new CMSWindowsScreen(true, args().m_noHooks, args().m_gameDevice)); + return new CScreen(new CMSWindowsScreen( + true, args().m_noHooks, args().m_gameDevice, args().m_stopOnDeskSwitch)); #elif WINAPI_XWINDOWS return new CScreen(new CXWindowsScreen( args().m_display, true, args().m_disableXInitThreads, 0, *EVENTQUEUE)); diff --git a/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp b/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp index bbbb5666..a7bfb467 100644 --- a/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp +++ b/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp @@ -55,7 +55,7 @@ protected: return new CMSWindowsDesks( true, false, m_hookLibrary, m_screensaver, eventQueue, new TMethodJob( - this, &CMSWindowsKeyStateTests::updateKeysCB)); + this, &CMSWindowsKeyStateTests::updateKeysCB), false); } void* getEventTarget() const