blob: 59e2d00b649038058d6b39af693c7e57a173aa33 [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 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 Viewer for Win32
20
21#include <string.h>
22#ifdef WIN32
23#define strcasecmp _stricmp
24#endif
25#include <list>
26
27#include <vncviewer/resource.h>
28#include <vncviewer/CViewManager.h>
29#include <vncviewer/CView.h>
30#include <vncviewer/OptionsDialog.h>
31
32#include <rfb/Logger_stdio.h>
33#include <rfb/Logger_file.h>
34#include <rfb/LogWriter.h>
35#include <rfb/Exception.h>
36
37#include <rfb_win32/RegConfig.h>
38#include <rfb_win32/TrayIcon.h>
39#include <rfb_win32/Win32Util.h>
40#include <rfb_win32/AboutDialog.h>
41
42#include <network/TcpSocket.h>
43
44#ifdef _DIALOG_CAPTURE
45#include <extra/LoadBMP.h>
46#endif
47
48using namespace rfb;
49using namespace rfb::win32;
50using namespace rdr;
51using namespace network;
52
53static LogWriter vlog("main");
54
55TStr rfb::win32::AppName("VNC Viewer");
56
57
58#ifdef _DIALOG_CAPTURE
59BoolParameter captureDialogs("CaptureDialogs", "", false);
60#endif
61
62//
63// -=- Listener
64// Class to handle listening on a particular port for incoming connections
65// from servers, and spawning of clients
66//
67
68static BoolParameter acceptIncoming("Listen", "Accept incoming connections from VNC servers.", false);
69
70
71//
72// -=- AboutDialog global values
73//
74
75const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
76const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
77const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
78const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
79const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
80
81
82//
83// -=- VNCviewer Tray Icon
84//
85
86class CViewTrayIcon : public TrayIcon {
87public:
88 CViewTrayIcon(CViewManager& mgr) : manager(mgr) {
89 setIcon(IDI_ICON);
90 setToolTip(_T("VNC Viewer"));
91 }
92 virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
93 switch(msg) {
94
95 case WM_USER:
96 switch (lParam) {
97 case WM_LBUTTONDBLCLK:
98 SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
99 break;
100 case WM_RBUTTONUP:
101 HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
102 HMENU trayMenu = GetSubMenu(menu, 0);
103
104 // First item is New Connection, the default
105 SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
106
107 // SetForegroundWindow is required, otherwise Windows ignores the
108 // TrackPopupMenu because the window isn't the foreground one, on
109 // some older Windows versions...
110 SetForegroundWindow(getHandle());
111
112 // Display the menu
113 POINT pos;
114 GetCursorPos(&pos);
115 TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
116 break;
117 }
118 return 0;
119
120 case WM_COMMAND:
121 switch (LOWORD(wParam)) {
122 case ID_NEW_CONNECTION:
123 manager.addClient(0);
124 break;
125 case ID_OPTIONS:
126 OptionsDialog::global.showDialog(0);
127 break;
128 case ID_ABOUT:
129 AboutDialog::instance.showDialog();
130 break;
131 case ID_CLOSE:
132 SendMessage(getHandle(), WM_CLOSE, 0, 0);
133 break;
134 }
135 return 0;
136
137 case WM_CLOSE:
138 PostQuitMessage(0);
139 return 0;
140 }
141
142 return TrayIcon::processMessage(msg, wParam, lParam);
143 }
144protected:
145 CViewManager& manager;
146};
147
148//
149// -=- processParams
150// Read in the command-line parameters and interpret them.
151//
152
153void
154programInfo() {
155 win32::FileVersionInfo inf;
156 _tprintf(_T("%s - %s, Version %s\n"),
157 inf.getVerString(_T("ProductName")),
158 inf.getVerString(_T("FileDescription")),
159 inf.getVerString(_T("FileVersion")));
160 printf("%s\n", buildTime);
161 _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
162}
163
164void
165programUsage() {
166 printf("usage: vncviewer <options> <hostname>[:<display>]\n");
167 printf("Command-line options:\n");
168 printf(" -help - Provide usage information.\n");
169 printf(" -config <file> - Load connection settings from VNCViewer 3.3 settings file\n");
170 printf(" -console - Run with a console window visible.\n");
171 printf(" <setting>=<value> - Set the named configuration parameter.\n");
172 printf(" (Parameter values specified on the command-line override those specified by other configuration methods.)\n");
173 printf("\nLog names:\n");
174 LogWriter::listLogWriters();
175 printf("\nLog destinations:\n");
176 Logger::listLoggers();
177 printf("\nParameters:\n");
178 Configuration::listParams();
179}
180
181
182bool print_usage = false;
183bool close_console = true;
184std::list<char*> hosts;
185std::list<char*> configFiles;
186
187void
188processParams(int argc, char* argv[]) {
189 for (int i=1; i<argc; i++) {
190 try {
191
192 if (strcasecmp(argv[i], "-console") == 0) {
193 close_console = false;
194
195 } else if (((strcasecmp(argv[i], "-config") == 0) ||
196 (strcasecmp(argv[i], "/config") == 0)) && (i < argc-1)) {
197 configFiles.push_back(strDup(argv[i+1]));
198 i++;
199
200 } else if ((strcasecmp(argv[i], "-help") == 0) ||
201 (strcasecmp(argv[i], "--help") == 0) ||
202 (strcasecmp(argv[i], "-h") == 0) ||
203 (strcasecmp(argv[i], "/?") == 0)) {
204 print_usage = true;
205 close_console = false;
206 break;
207
208 } else {
209 // Try to process <option>=<value>, or -<bool>
210 if (Configuration::setParam(argv[i], true))
211 continue;
212 // Try to process -<option> <value>
213 if ((argv[i][0] == '-') && (i+1 < argc)) {
214 if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
215 i++;
216 continue;
217 }
218 }
219 // If it's -<option> then it's not recognised - error
220 // If it's <host> then add it to the list to connect to.
221 if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
222 const char* fmt = "The option %s was not recognized. Use -help to see VNC Viewer usage";
223 CharArray tmp(strlen(argv[i])+strlen(fmt)+1);
224 sprintf(tmp.buf, fmt, argv[i]);
225 MsgBox(0, TStr(tmp.buf), MB_ICONSTOP | MB_OK);
226 exit(1);
227 } else {
228 hosts.push_back(strDup(argv[i]));
229 }
230 }
231
232 } catch (rdr::Exception& e) {
233 vlog.error(e.str());
234 }
235 }
236}
237
238
239//
240// -=- main
241//
242
243int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
244
245 try {
246
247 // - Initialise the available loggers
248 initStdIOLoggers();
249 initFileLogger("C:\\temp\\vncviewer4.log");
250
251 // - By default, just log errors to stderr
252 logParams.setDefault("*:stderr:0");
253
254 // - Process the command-line
255 int argc = __argc;
256 char** argv = __argv;
257 processParams(argc, argv);
258
259 // - By default the console will be closed
260 if (close_console) {
261 if (!FreeConsole())
262 vlog.info("unable to close console:%u", GetLastError());
263 } else {
264 AllocConsole();
265 freopen("CONIN$","rb",stdin);
266 freopen("CONOUT$","wb",stdout);
267 freopen("CONOUT$","wb",stderr);
268 setbuf(stderr, 0);
269 }
270
271#ifdef _DIALOG_CAPTURE
272 if (captureDialogs) {
273 CView::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\RealVNC\\VNCViewer4"));
274 OptionsDialog::global.showDialog(0, true);
275 return 0;
276 }
277#endif
278
279 // - If no clients are specified, bring up a connection dialog
280 if (configFiles.empty() && hosts.empty() && !acceptIncoming && !print_usage)
281 hosts.push_back(0);
282
283 programInfo();
284
285 // - Connect to the clients
286 if (!configFiles.empty() || !hosts.empty() || acceptIncoming) {
287 // - Configure the registry configuration reader
288 win32::RegistryReader reg_reader;
289 reg_reader.setKey(HKEY_CURRENT_USER, _T("Software\\RealVNC\\VNCViewer4"));
290
291 // - Tell the rest of VNC Viewer where to write config data to
292 CView::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\RealVNC\\VNCViewer4"));
293
294 // - Start the Socket subsystem for TCP
295 TcpSocket::initTcpSockets();
296
297 // Create the client connection manager
298 CViewManager view_manager;
299
300 if (acceptIncoming) {
301 int port = 5500;
302
303 // Listening viewer
304 if (hosts.size() > 1) {
305 programUsage();
306 exit(2);
307 }
308 if (!hosts.empty()) {
309 port = atoi(hosts.front());
310 }
311
312 vlog.debug("opening listener");
313
314 CViewTrayIcon tray(view_manager);
315
316 view_manager.addDefaultTCPListener(port);
317
318 // Run the view manager
319 // Also processes the tray icon if necessary
320 MSG msg;
321 while (GetMessage(&msg, NULL, 0, 0) > 0) {
322 TranslateMessage(&msg);
323 DispatchMessage(&msg);
324 }
325
326 vlog.debug("quitting viewer");
327 } else {
328 // Read each config file in turn
329 while (!configFiles.empty()) {
330 char* filename = configFiles.front();
331 view_manager.addClient(filename, true);
332 strFree(filename);
333 configFiles.pop_front();
334 }
335
336 // Connect to each client in turn
337 while (!hosts.empty()) {
338 char* hostinfo = hosts.front();
339 view_manager.addClient(hostinfo);
340 strFree(hostinfo);
341 hosts.pop_front();
342 }
343
344 // Run the view manager
345 MSG msg;
346 while (GetMessage(&msg, NULL, 0, 0) > 0) {
347 TranslateMessage(&msg);
348 DispatchMessage(&msg);
349 }
350
351 vlog.debug("quitting viewer");
352 }
353
354 }
355
356 // - If necessary, print the program's usage info
357 if (print_usage)
358 programUsage();
359
360 if (!close_console) {
361 printf("Press Enter/Return key to continue\n");
362 char c = getchar();
363 }
364
365 } catch (rdr::Exception& e) {
366 MsgBox(0, TStr(e.str()), MB_ICONSTOP | MB_OK);
367 }
368
369 return 0;
370}