1 /*
2  * synergy -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2002 Chris Schoeneman
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "synergy/win32/AppUtilWindows.h"
20 #include "synergy/Screen.h"
21 #include "synergy/ArgsBase.h"
22 #include "synergy/App.h"
23 #include "synergy/XSynergy.h"
24 #include "platform/MSWindowsScreen.h"
25 #include "arch/win32/XArchWindows.h"
26 #include "arch/win32/ArchMiscWindows.h"
27 #include "arch/IArchTaskBarReceiver.h"
28 #include "base/Log.h"
29 #include "base/log_outputters.h"
30 #include "base/IEventQueue.h"
31 #include "base/Event.h"
32 #include "base/EventQueue.h"
33 #include "common/Version.h"
34 
35 #include <sstream>
36 #include <iostream>
37 #include <conio.h>
38 #include <VersionHelpers.h>
39 
AppUtilWindows(IEventQueue * events)40 AppUtilWindows::AppUtilWindows(IEventQueue* events) :
41     m_events(events),
42     m_exitMode(kExitModeNormal)
43 {
44     if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE)
45     {
46         throw XArch(new XArchEvalWindows());
47     }
48 }
49 
~AppUtilWindows()50 AppUtilWindows::~AppUtilWindows()
51 {
52 }
53 
consoleHandler(DWORD)54 BOOL WINAPI AppUtilWindows::consoleHandler(DWORD)
55 {
56     LOG((CLOG_INFO "got shutdown signal"));
57     IEventQueue* events = AppUtil::instance().app().getEvents();
58     events->addEvent(Event(Event::kQuit));
59     return TRUE;
60 }
61 
62 static
63 int
mainLoopStatic()64 mainLoopStatic()
65 {
66     return AppUtil::instance().app().mainLoop();
67 }
68 
69 int
daemonNTMainLoop(int argc,const char ** argv)70 AppUtilWindows::daemonNTMainLoop(int argc, const char** argv)
71 {
72     app().initApp(argc, argv);
73     debugServiceWait();
74 
75     return ArchMiscWindows::runDaemon(mainLoopStatic);
76 }
77 
78 void
exitApp(int code)79 AppUtilWindows::exitApp(int code)
80 {
81     switch (m_exitMode) {
82 
83         case kExitModeDaemon:
84             ArchMiscWindows::daemonFailed(code);
85             break;
86 
87         default:
88             throw XExitApp(code);
89     }
90 }
91 
daemonNTMainLoopStatic(int argc,const char ** argv)92 int daemonNTMainLoopStatic(int argc, const char** argv)
93 {
94     return AppUtilWindows::instance().daemonNTMainLoop(argc, argv);
95 }
96 
97 int
daemonNTStartup(int,char **)98 AppUtilWindows::daemonNTStartup(int, char**)
99 {
100     SystemLogger sysLogger(app().daemonName(), false);
101     m_exitMode = kExitModeDaemon;
102     return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic);
103 }
104 
105 static
106 int
daemonNTStartupStatic(int argc,char ** argv)107 daemonNTStartupStatic(int argc, char** argv)
108 {
109     return AppUtilWindows::instance().daemonNTStartup(argc, argv);
110 }
111 
112 static
113 int
foregroundStartupStatic(int argc,char ** argv)114 foregroundStartupStatic(int argc, char** argv)
115 {
116     return AppUtil::instance().app().foregroundStartup(argc, argv);
117 }
118 
119 void
beforeAppExit()120 AppUtilWindows::beforeAppExit()
121 {
122     // this can be handy for debugging, since the application is launched in
123     // a new console window, and will normally close on exit (making it so
124     // that we can't see error messages).
125     if (app().argsBase().m_pauseOnExit) {
126         std::cout << std::endl << "press any key to exit..." << std::endl;
127         int c = _getch();
128     }
129 }
130 
131 int
run(int argc,char ** argv)132 AppUtilWindows::run(int argc, char** argv)
133 {
134     if (!IsWindowsXPSP3OrGreater()) {
135         throw std::runtime_error("Synergy only supports Windows XP SP3 and above.");
136     }
137 
138     // record window instance for tray icon, etc
139     ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
140 
141     MSWindowsScreen::init(ArchMiscWindows::instanceWin32());
142     Thread::getCurrentThread().setPriority(-14);
143 
144     StartupFunc startup;
145     if (ArchMiscWindows::wasLaunchedAsService()) {
146         startup = &daemonNTStartupStatic;
147     } else {
148         startup = &foregroundStartupStatic;
149         app().argsBase().m_daemon = false;
150     }
151 
152     return app().runInner(argc, argv, NULL, startup);
153 }
154 
155 AppUtilWindows&
instance()156 AppUtilWindows::instance()
157 {
158     return (AppUtilWindows&)AppUtil::instance();
159 }
160 
161 void
debugServiceWait()162 AppUtilWindows::debugServiceWait()
163 {
164     if (app().argsBase().m_debugServiceWait)
165     {
166         while(true)
167         {
168             // this code is only executed when the process is launched via the
169             // windows service controller (and --debug-service-wait arg is
170             // used). to debug, set a breakpoint on this line so that
171             // execution is delayed until the debugger is attached.
172             ARCH->sleep(1);
173             LOG((CLOG_INFO "waiting for debugger to attach"));
174         }
175     }
176 }
177 
178 void
startNode()179 AppUtilWindows::startNode()
180 {
181     app().startNode();
182 }
183