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