blob: 5623421b92ea6b6a7cc113238a478190bd675566 [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- VNC Server 4.0 for Windows (WinVNC4)
20
21#include <string.h>
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000022
23#include <winvnc/VNCServerWin32.h>
24#include <winvnc/VNCServerService.h>
25#include <winvnc/AddNewClientDialog.h>
26
27#include <rfb/Logger_stdio.h>
28#include <rfb/Logger_file.h>
29#include <rfb/LogWriter.h>
30#include <rfb_win32/AboutDialog.h>
31#include <rfb_win32/MsgBox.h>
32#include <network/TcpSocket.h>
33
34using namespace winvnc;
35using namespace rfb;
36using namespace win32;
37
38static LogWriter vlog("main");
39
Pierre Ossmanbc84faa2015-05-04 15:04:21 +020040TStr rfb::win32::AppName("TigerVNC Server");
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000041
42
Samuel Mannehed60c41932014-02-07 14:53:24 +000043extern bool runAsService;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000044static bool runServer = true;
45static bool close_console = false;
46
47
48//
49// -=- processParams
50// Read in the command-line parameters and interpret them.
51//
52
53static void programInfo() {
54 win32::FileVersionInfo inf;
55 _tprintf(_T("%s - %s, Version %s\n"),
56 inf.getVerString(_T("ProductName")),
57 inf.getVerString(_T("FileDescription")),
58 inf.getVerString(_T("FileVersion")));
59 printf("%s\n", buildTime);
60 _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
61}
62
63static void programUsage() {
64 printf("Command-line options:\n");
65 printf(" -connect [<host[::port]>] - Connect an existing WinVNC server to a listening viewer.\n");
66 printf(" -disconnect - Disconnect all clients from an existing WinVNC server.\n");
67 printf(" -register <options...> - Register WinVNC server as a system service.\n");
68 printf(" -unregister - Remove WinVNC server from the list of system services.\n");
69 printf(" -start - Start the WinVNC server system service.\n");
70 printf(" -stop - Stop the WinVNC server system service.\n");
71 printf(" -status - Query the WinVNC service status.\n");
72 printf(" -help - Provide usage information.\n");
73 printf(" -noconsole - Run without a console (i.e. no stderr/stdout)\n");
74 printf(" <setting>=<value> - Set the named configuration parameter.\n");
75 printf(" (Parameter values specified on the command-line override those specified by other configuration methods.)\n");
76 printf("\nLog names:\n");
77 LogWriter::listLogWriters();
78 printf("\nLog destinations:\n");
79 Logger::listLoggers();
80 printf("\nAvailable configuration parameters:\n");
Peter Åstrand (astrand)90afb1c2017-10-17 08:21:30 +020081 Configuration::listParams(79, 14);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000082}
83
84static void MsgBoxOrLog(const char* msg, bool isError=false) {
85 if (close_console) {
86 MsgBox(0, TStr(msg), (isError ? MB_ICONERROR : MB_ICONINFORMATION) | MB_OK);
87 } else {
88 if (isError) {
89 try {
Pierre Ossmancd5c82a2015-03-03 16:48:58 +010090 vlog.error("%s", msg);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000091 return;
92 } catch (...) {
93 }
94 }
95 fprintf(stderr, "%s\n", msg);
96 }
97}
98
Adam Tkac8fb6ac02010-06-25 11:24:27 +000099static void processParams(int argc, char** argv) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000100 for (int i=1; i<argc; i++) {
101 try {
102
103 if (strcasecmp(argv[i], "-connect") == 0) {
104 runServer = false;
105 CharArray host;
106 if (i+1 < argc) {
107 host.buf = strDup(argv[i+1]);
108 i++;
109 } else {
110 AddNewClientDialog ancd;
111 if (ancd.showDialog())
112 host.buf = strDup(ancd.getHostName());
113 }
114 if (host.buf) {
115 HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
116 if (!hwnd)
117 throw rdr::Exception("Unable to locate existing VNC Server.");
118 COPYDATASTRUCT copyData;
119 copyData.dwData = 1; // *** AddNewClient
120 copyData.cbData = strlen(host.buf);
121 copyData.lpData = (void*)host.buf;
122 printf("Sending connect request to VNC Server...\n");
123 if (!SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&copyData))
124 MsgBoxOrLog("Connection failed.", true);
125 }
126 } else if (strcasecmp(argv[i], "-disconnect") == 0) {
127 runServer = false;
128 HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
129 if (!hwnd)
130 throw rdr::Exception("Unable to locate existing VNC Server.");
131 COPYDATASTRUCT copyData;
132 copyData.dwData = 2; // *** DisconnectClients
133 copyData.lpData = 0;
134 copyData.cbData = 0;
135 printf("Sending disconnect request to VNC Server...\n");
136 if (!SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&copyData))
137 MsgBoxOrLog("Failed to disconnect clients.", true);
138 } else if (strcasecmp(argv[i], "-start") == 0) {
139 printf("Attempting to start service...\n");
140 runServer = false;
141 if (rfb::win32::startService(VNCServerService::Name))
142 MsgBoxOrLog("Started service successfully");
143 } else if (strcasecmp(argv[i], "-stop") == 0) {
144 printf("Attempting to stop service...\n");
145 runServer = false;
146 if (rfb::win32::stopService(VNCServerService::Name))
147 MsgBoxOrLog("Stopped service successfully");
148 } else if (strcasecmp(argv[i], "-status") == 0) {
149 printf("Querying service status...\n");
150 runServer = false;
Pierre Ossmanba6fbfe2015-03-03 16:41:29 +0100151 CharArray result;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000152 DWORD state = rfb::win32::getServiceState(VNCServerService::Name);
Pierre Ossmanba6fbfe2015-03-03 16:41:29 +0100153 result.format("The %s Service is in the %s state.",
154 (const char*)CStr(VNCServerService::Name),
155 rfb::win32::serviceStateName(state));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000156 MsgBoxOrLog(result.buf);
157 } else if (strcasecmp(argv[i], "-service") == 0) {
158 printf("Run in service mode\n");
Samuel Mannehed60c41932014-02-07 14:53:24 +0000159 runServer = false;
160 runAsService = true;
161
162 } else if (strcasecmp(argv[i], "-service_run") == 0) {
163 printf("Run in service mode\n");
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000164 runAsService = true;
165
166 } else if (strcasecmp(argv[i], "-register") == 0) {
167 printf("Attempting to register service...\n");
168 runServer = false;
169 int j = i;
170 i = argc;
Pierre Ossmaned920792016-06-13 13:05:21 +0200171
172 // Try to clean up earlier services we've had
Pierre Ossmanc7860c22016-08-18 16:48:55 +0200173 try {
174 rfb::win32::unregisterService("WinVNC4");
175 } catch (rdr::SystemException) {
176 // Do nothing as we might fail simply because there was no
177 // service to remove
178 }
179 try {
180 rfb::win32::unregisterService("TigerVNC Server");
181 } catch (rdr::SystemException) {
182 }
Pierre Ossmaned920792016-06-13 13:05:21 +0200183
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000184 if (rfb::win32::registerService(VNCServerService::Name,
Pierre Ossman018c67e2016-01-12 10:13:17 +0100185 _T("TigerVNC Server"),
Pierre Ossmanbc84faa2015-05-04 15:04:21 +0200186 _T("Provides remote access to this machine via the VNC/RFB protocol."),
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000187 argc-(j+1), &argv[j+1]))
188 MsgBoxOrLog("Registered service successfully");
189 } else if (strcasecmp(argv[i], "-unregister") == 0) {
190 printf("Attempting to unregister service...\n");
191 runServer = false;
192 if (rfb::win32::unregisterService(VNCServerService::Name))
193 MsgBoxOrLog("Unregistered service successfully");
194
195 } else if (strcasecmp(argv[i], "-noconsole") == 0) {
196 close_console = true;
197 vlog.info("closing console");
198 if (!FreeConsole())
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100199 vlog.info("unable to close console:%lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000200
201 } else if ((strcasecmp(argv[i], "-help") == 0) ||
202 (strcasecmp(argv[i], "--help") == 0) ||
203 (strcasecmp(argv[i], "-h") == 0) ||
204 (strcasecmp(argv[i], "/?") == 0)) {
205 runServer = false;
206 programUsage();
207 break;
208
209 } else {
210 // Try to process <option>=<value>, or -<bool>
211 if (Configuration::setParam(argv[i], true))
212 continue;
213 // Try to process -<option> <value>
214 if ((argv[i][0] == '-') && (i+1 < argc)) {
215 if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
216 i++;
217 continue;
218 }
219 }
220 // Nope. Show them usage and don't run the server
221 runServer = false;
222 programUsage();
223 break;
224 }
225
226 } catch (rdr::Exception& e) {
227 MsgBoxOrLog(e.str(), true);
228 }
229 }
230}
231
232
233//
234// -=- main
235//
236
Adam Tkac01345fc2010-06-25 11:29:22 +0000237int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000238 int result = 0;
239
240 try {
241 // - Initialise the available loggers
242 //freopen("\\\\drupe\\tjr\\WinVNC4.log","ab",stderr);
Adam Tkacd41d4be2011-01-26 19:09:03 +0000243#ifdef _DEBUG
244 AllocConsole();
245 freopen("CONIN$", "rb", stdin);
246 freopen("CONOUT$", "wb", stdout);
247 freopen("CONOUT$", "wb", stderr);
248 setbuf(stderr, 0);
249 initStdIOLoggers();
250 initFileLogger("C:\\temp\\WinVNC4.log");
251 logParams.setParam("*:stderr:100");
252#else
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000253 initFileLogger("C:\\temp\\WinVNC4.log");
Adam Tkacd41d4be2011-01-26 19:09:03 +0000254 logParams.setParam("*:stderr:0");
255#endif
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000256 rfb::win32::initEventLogLogger(VNCServerService::Name);
257
Adam Tkac0c4dcd22010-11-11 11:29:55 +0000258 Configuration::enableServerParams();
259
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000260 // - By default, just log errors to stderr
Adam Tkacd41d4be2011-01-26 19:09:03 +0000261
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000262
263 // - Print program details and process the command line
264 programInfo();
Adam Tkac01345fc2010-06-25 11:29:22 +0000265
266 int argc = __argc;
267 char **argv = __argv;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000268 processParams(argc, argv);
269
270 // - Run the server if required
271 if (runServer) {
272 // Start the network subsystem and run the server
273 VNCServerWin32 server;
Samuel Mannehed60c41932014-02-07 14:53:24 +0000274 result = server.run();
275 } else if (runAsService) {
276 VNCServerService service;
277 service.start();
278 result = service.getStatus().dwWin32ExitCode;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000279 }
280
281 vlog.debug("WinVNC service destroyed");
282 } catch (rdr::Exception& e) {
283 MsgBoxOrLog(e.str(), true);
284 }
285
286 vlog.debug("WinVNC process quitting");
287 return result;
288}