/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file COPYING that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "CAppUtilWindows.h" #include "Version.h" #include "CLog.h" #include "XArchWindows.h" #include "CArchMiscWindows.h" #include "CApp.h" #include "LogOutputters.h" #include "CMSWindowsScreen.h" #include "XSynergy.h" #include "IArchTaskBarReceiver.h" #include "CMSWindowsRelauncher.h" #include "CScreen.h" #include "CArgsBase.h" #include "IEventQueue.h" #include "CEvent.h" #include #include #include CAppUtilWindows::CAppUtilWindows() : m_exitMode(kExitModeNormal) { if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE) { throw XArch(new XArchEvalWindows()); } } CAppUtilWindows::~CAppUtilWindows() { } BOOL WINAPI CAppUtilWindows::consoleHandler(DWORD) { LOG((CLOG_INFO "got shutdown signal")); EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); return TRUE; } bool CAppUtilWindows::parseArg(const int& argc, const char* const* argv, int& i) { if (app().isArg(i, argc, argv, NULL, "--service")) { LOG((CLOG_WARN "obsolete argument --service, use synergyd instead.")); app().bye(kExitFailed); } else if (app().isArg(i, argc, argv, NULL, "--exit-pause")) { app().argsBase().m_pauseOnExit = true; } else if (app().isArg(i, argc, argv, NULL, "--game-mode")) { CString mode(argv[++i]); if (mode == "xinput") { app().argsBase().m_gameDevice.m_mode = CGameDeviceInfo::kGameModeXInput; } else if (mode == "joyinfoex") { app().argsBase().m_gameDevice.m_mode = CGameDeviceInfo::kGameModeJoyInfoEx; } } else if (app().isArg(i, argc, argv, NULL, "--game-poll")) { CString mode(argv[++i]); if (mode == "dynamic") { app().argsBase().m_gameDevice.m_poll = CGameDeviceInfo::kGamePollDynamic; } else if (mode == "static") { app().argsBase().m_gameDevice.m_poll = CGameDeviceInfo::kGamePollStatic; } } else if (app().isArg(i, argc, argv, NULL, "--game-poll-freq")) { app().argsBase().m_gameDevice.m_pollFreq = atoi(argv[++i]); } else { // option not supported here return false; } return true; } static int mainLoopStatic() { return CAppUtil::instance().app().mainLoop(); } int CAppUtilWindows::daemonNTMainLoop(int argc, const char** argv) { app().initApp(argc, argv); debugServiceWait(); // NB: what the hell does this do?! app().argsBase().m_backend = false; return CArchMiscWindows::runDaemon(mainLoopStatic); } void CAppUtilWindows::exitApp(int code) { switch (m_exitMode) { case kExitModeDaemon: CArchMiscWindows::daemonFailed(code); break; default: throw XExitApp(code); } } int daemonNTMainLoopStatic(int argc, const char** argv) { return CAppUtilWindows::instance().daemonNTMainLoop(argc, argv); } int CAppUtilWindows::daemonNTStartup(int, char**) { CSystemLogger sysLogger(app().daemonName(), false); m_exitMode = kExitModeDaemon; return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic); } static int daemonNTStartupStatic(int argc, char** argv) { return CAppUtilWindows::instance().daemonNTStartup(argc, argv); } static int foregroundStartupStatic(int argc, char** argv) { return CAppUtil::instance().app().foregroundStartup(argc, argv); } void CAppUtilWindows::beforeAppExit() { // this can be handy for debugging, since the application is launched in // a new console window, and will normally close on exit (making it so // that we can't see error messages). if (app().argsBase().m_pauseOnExit) { std::cout << std::endl << "press any key to exit..." << std::endl; int c = _getch(); } } int CAppUtilWindows::run(int argc, char** argv) { // record window instance for tray icon, etc CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); CMSWindowsScreen::init(CArchMiscWindows::instanceWin32()); CThread::getCurrentThread().setPriority(-14); StartupFunc startup; if (CArchMiscWindows::wasLaunchedAsService()) { startup = &daemonNTStartupStatic; } else { startup = &foregroundStartupStatic; app().argsBase().m_daemon = false; } return app().runInner(argc, argv, NULL, startup); } CAppUtilWindows& CAppUtilWindows::instance() { return (CAppUtilWindows&)CAppUtil::instance(); } void CAppUtilWindows::debugServiceWait() { if (app().argsBase().m_debugServiceWait) { while(true) { // this code is only executed when the process is launched via the // windows service controller (and --debug-service-wait arg is // used). to debug, set a breakpoint on this line so that // execution is delayed until the debugger is attached. ARCH->sleep(1); LOG((CLOG_INFO "waiting for debugger to attach")); } } } void CAppUtilWindows::startNode() { if (app().argsBase().m_relaunchMode) { LOG((CLOG_DEBUG1 "entering relaunch mode")); CMSWindowsRelauncher relauncher(true); relauncher.startAsync(); // HACK: create a dummy screen, which can handle system events // (such as a stop request from the service controller). CScreen* dummyScreen = app().createScreen(); } else { app().startNode(); } }