blob: b304aececc3abff5eb2cba85ed621022a4c2b9ef [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2004 TightVNC Team. 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// -=- RFB Player for Win32
20#include <windows.h>
21#include <commdlg.h>
22#include <shellapi.h>
23
24#include <rfb/LogWriter.h>
25
26#include <rfb_win32/AboutDialog.h>
27#include <rfb_win32/DeviceContext.h>
28#include <rfb_win32/MsgBox.h>
29#include <rfb_win32/WMShatter.h>
30#include <rfb_win32/Win32Util.h>
31
32#include <rfbplayer/rfbplayer.h>
33#include <rfbplayer/ChoosePixelFormatDialog.h>
34#include <rfbplayer/GotoPosDialog.h>
35#include <rfbplayer/InfoDialog.h>
36#include <rfbplayer/SessionInfoDialog.h>
37
38using namespace rfb;
39using namespace rfb::win32;
40
41// -=- Variables & consts
42
43static LogWriter vlog("RfbPlayer");
44
45TStr rfb::win32::AppName("RfbPlayer");
46extern const char* buildTime;
47HFONT hFont = 0;
48
49char wrong_cmd_msg[] =
50 "Wrong command-line parameters!\n"
51 "Use for help: rfbplayer -help";
52
53char usage_msg[] =
54 "usage: rfbplayer <options> <filename>\r\n"
55 "Command-line options:\r\n"
56 " -help \t- Provide usage information.\r\n"
57 " -pf <mode> \t- Forces the pixel format for the session.\r\n"
58 " \t <mode>=r<r_bits>g<g_bits>b<b_bits>[le|be],\r\n"
59 " \t r_bits - size the red component, in bits,\r\n"
60 " \t g_bits - size the green component, in bits,\r\n"
61 " \t b_bits - size the blue component, in bits,\r\n"
62 " \t le - little endian byte order (default),\r\n"
63 " \t be - big endian byte order.\r\n"
64 " \t The r, g, b component is in any order.\r\n"
65 " \t Default: auto detect the pixel format.\r\n"
66 " -upf <name> \t- Forces the user defined pixel format for\r\n"
67 " \t the session. If <name> is empty then application\r\n"
68 " \t shows the list of user defined pixel formats.\r\n"
69 " \t Don't use this option with -pf.\r\n"
70 " -speed <value>\t- Sets playback speed, where 1 is normal speed,\r\n"
71 " \t is double speed, 0.5 is half speed. Default: 1.0.\r\n"
72 " -pos <ms> \t- Sets initial time position in the session file,\r\n"
73 " \t in milliseconds. Default: 0.\r\n"
74 " -autoplay \t- Runs the player in the playback mode.\r\n"
75 " -loop \t- Replays the rfb session.";
76
77// -=- RfbPlayer's defines and consts
78
79#define strcasecmp _stricmp
80#define DEFAULT_PLAYER_WIDTH 640
81#define DEFAULT_PLAYER_HEIGHT 480
82
83//
84// -=- AboutDialog global values
85//
86
87const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
88const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
89const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
90const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
91const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
92
93//
94// -=- RfbPlayerClass
95
96//
97// Window class used as the basis for RfbPlayer instance
98//
99
100class RfbPlayerClass {
101public:
102 RfbPlayerClass();
103 ~RfbPlayerClass();
104 ATOM classAtom;
105 HINSTANCE instance;
106};
107
108LRESULT CALLBACK RfbPlayerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
109 LRESULT result;
110
111 if (msg == WM_CREATE)
112 SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
113 else if (msg == WM_DESTROY) {
114 RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
115 SetWindowLong(hwnd, GWL_USERDATA, 0);
116 }
117 RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
118 if (!_this) {
119 vlog.info("null _this in %x, message %u", hwnd, msg);
120 return DefWindowProc(hwnd, msg, wParam, lParam);
121 }
122
123 try {
124 result = _this->processMainMessage(hwnd, msg, wParam, lParam);
125 } catch (rdr::Exception& e) {
126 vlog.error("untrapped: %s", e.str());
127 }
128
129 return result;
130};
131
132RfbPlayerClass::RfbPlayerClass() : classAtom(0) {
133 WNDCLASS wndClass;
134 wndClass.style = 0;
135 wndClass.lpfnWndProc = RfbPlayerProc;
136 wndClass.cbClsExtra = 0;
137 wndClass.cbWndExtra = 0;
138 wndClass.hInstance = instance = GetModuleHandle(0);
139 wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0),
140 MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
141 if (!wndClass.hIcon)
142 printf("unable to load icon:%ld", GetLastError());
143 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
144 wndClass.hbrBackground = HBRUSH(COLOR_WINDOW);
145 wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
146 wndClass.lpszClassName = _T("RfbPlayerClass");
147 classAtom = RegisterClass(&wndClass);
148 if (!classAtom) {
149 throw rdr::SystemException("unable to register RfbPlayer window class",
150 GetLastError());
151 }
152}
153
154RfbPlayerClass::~RfbPlayerClass() {
155 if (classAtom) {
156 UnregisterClass((const TCHAR*)classAtom, instance);
157 }
158}
159
160RfbPlayerClass baseClass;
161
162//
163// -=- RfbFrameClass
164
165//
166// Window class used to displaying the rfb data
167//
168
169class RfbFrameClass {
170public:
171 RfbFrameClass();
172 ~RfbFrameClass();
173 ATOM classAtom;
174 HINSTANCE instance;
175};
176
177LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
178 LRESULT result;
179
180 if (msg == WM_CREATE)
181 SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
182 else if (msg == WM_DESTROY)
183 SetWindowLong(hwnd, GWL_USERDATA, 0);
184 RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
185 if (!_this) {
186 vlog.info("null _this in %x, message %u", hwnd, msg);
187 return DefWindowProc(hwnd, msg, wParam, lParam);
188 }
189
190 try {
191 result = _this->processFrameMessage(hwnd, msg, wParam, lParam);
192 } catch (rdr::Exception& e) {
193 vlog.error("untrapped: %s", e.str());
194 }
195
196 return result;
197}
198
199RfbFrameClass::RfbFrameClass() : classAtom(0) {
200 WNDCLASS wndClass;
201 wndClass.style = 0;
202 wndClass.lpfnWndProc = FrameProc;
203 wndClass.cbClsExtra = 0;
204 wndClass.cbWndExtra = 0;
205 wndClass.hInstance = instance = GetModuleHandle(0);
206 wndClass.hIcon = 0;
207 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
208 wndClass.hbrBackground = 0;
209 wndClass.lpszMenuName = 0;
210 wndClass.lpszClassName = _T("RfbPlayerClass1");
211 classAtom = RegisterClass(&wndClass);
212 if (!classAtom) {
213 throw rdr::SystemException("unable to register RfbPlayer window class",
214 GetLastError());
215 }
216}
217
218RfbFrameClass::~RfbFrameClass() {
219 if (classAtom) {
220 UnregisterClass((const TCHAR*)classAtom, instance);
221 }
222}
223
224RfbFrameClass frameClass;
225
226//
227// -=- RfbPlayer instance implementation
228//
229
230RfbPlayer::RfbPlayer(char *_fileName, PlayerOptions *_options)
231: RfbProto(_fileName), fileName(_fileName), buffer(0), client_size(0, 0, 32, 32),
232 window_size(0, 0, 32, 32), cutText(0), seekMode(false), lastPos(0),
233 rfbReader(0), sessionTimeMs(0), sliderStepMs(0), imageDataStartTime(0),
234 rewindFlag(false), stopped(false), currentEncoding(-1) {
235
236 // Save the player options
237 memcpy(&options, _options, sizeof(options));
238
239 // Reset the full session time
240 strcpy(fullSessionTime, "00m:00s");
241
242 // Load the user defined pixel formats from the registry
243 supportedPF.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
244
245 // Create the main window
246 const TCHAR* name = _T("RfbPlayer");
247 int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
248 int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
249 mainHwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW,
250 x, y, DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT, 0, 0, baseClass.instance, this);
251 if (!mainHwnd) {
252 throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
253 }
254 vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), getMainHandle());
255
256 // Create the backing buffer
257 buffer = new win32::DIBSectionBuffer(getFrameHandle());
258 setVisible(true);
259
260 // If run with command-line parameters,
261 // open the session file with default settings, otherwise
262 // restore player settings from the registry
263 if (fileName) {
264 openSessionFile(fileName);
265 if (options.initTime > 0) setPos(options.initTime);
266 setSpeed(options.playbackSpeed);
267 } else {
268 options.readFromRegistry();
269 disableTBandMenuItems();
270 setTitle("None");
271 }
272 init();
273}
274
275RfbPlayer::~RfbPlayer() {
276 vlog.debug("~RfbPlayer");
277 if (rfbReader) {
278 delete rfbReader->join();
279 rfbReader = 0;
280 }
281 if (mainHwnd) {
282 setVisible(false);
283 DestroyWindow(mainHwnd);
284 mainHwnd = 0;
285 }
286 if (buffer) delete buffer;
287 if (cutText) delete [] cutText;
288 if (fileName) delete [] fileName;
289 if (hFont) DeleteObject(hFont);
290 vlog.debug("~RfbPlayer done");
291}
292
293LRESULT
294RfbPlayer::processMainMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
295
296 switch (msg) {
297
298 // -=- Process standard window messages
299
300 case WM_CREATE:
301 {
302 tb.create(this, hwnd);
303
304 // Create the frame window
305 frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
306 0, WS_CHILD | WS_VISIBLE, 0, tb.getHeight(), 10, tb.getHeight() + 10,
307 hwnd, 0, frameClass.instance, this);
308
309 hMenu = GetMenu(hwnd);
310
311 return 0;
312 }
313
314 // Process the main menu and toolbar's messages
315
316 case WM_COMMAND:
317
318 switch (LOWORD(wParam)) {
319 case ID_OPENFILE:
320 {
321 char curDir[_MAX_DIR];
322 static char filename[_MAX_PATH];
323 OPENFILENAME ofn;
324 memset((void *) &ofn, 0, sizeof(OPENFILENAME));
325 GetCurrentDirectory(sizeof(curDir), curDir);
326
327 ofn.lStructSize = sizeof(OPENFILENAME);
328 ofn.hwndOwner = getMainHandle();
329 ofn.lpstrFile = filename;
330 ofn.nMaxFile = sizeof(filename);
331 ofn.lpstrInitialDir = curDir;
332 ofn.lpstrFilter = "Rfb Session files (*.rfb, *.fbs)\0*.rfb;*.fbs\0" \
333 "All files (*.*)\0*.*\0";
334 ofn.lpstrDefExt = "rfb";
335 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
336 if (GetOpenFileName(&ofn)) {
337 openSessionFile(filename);
338 }
339 }
340 break;
341 case ID_CLOSEFILE:
342 closeSessionFile();
343 break;
344 case ID_SESSION_INFO:
345 {
346 SessionInfoDialog sessionInfo(&cp, currentEncoding);
347 sessionInfo.showDialog(getMainHandle());
348 }
349 break;
350 case ID_PLAY:
351 setPaused(false);
352 break;
353 case ID_PAUSE:
354 setPaused(true);
355 break;
356 case ID_STOP:
357 stopPlayback();
358 break;
359 case ID_PLAYPAUSE:
360 if (rfbReader) {
361 if (isPaused()) {
362 setPaused(false);
363 } else {
364 setPaused(true);
365 }
366 }
367 break;
368 case ID_GOTO:
369 {
370 GotoPosDialog gotoPosDlg;
371 if (gotoPosDlg.showDialog(getMainHandle())) {
372 long gotoTime = min(gotoPosDlg.getPos(), sessionTimeMs);
373 setPos(gotoTime);
374 tb.updatePos(gotoTime);
375 setPaused(isPaused());;
376 }
377 }
378 break;
379 case ID_LOOP:
380 options.loopPlayback = !options.loopPlayback;
381 if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
382 else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
383 break;
384 case ID_RETURN:
385 tb.processWM_COMMAND(wParam, lParam);
386 break;
387 case ID_OPTIONS:
388 {
389 OptionsDialog optionsDialog(&options, &supportedPF);
390 optionsDialog.showDialog(getMainHandle());
391 }
392 break;
393 case ID_EXIT:
394 PostQuitMessage(0);
395 break;
396 case ID_HOMEPAGE:
397 ShellExecute(getMainHandle(), _T("open"), _T("http://www.tightvnc.com/"),
398 NULL, NULL, SW_SHOWDEFAULT);
399 break;
400 case ID_HELP_COMMANDLINESWITCHES:
401 {
402 InfoDialog usageDialog(usage_msg);
403 usageDialog.showDialog(getMainHandle());
404 }
405 break;
406 case ID_ABOUT:
407 AboutDialog::instance.showDialog();
408 break;
409 }
410 break;
411
412 // Update frame's window size and add scrollbars if required
413
414 case WM_SIZE:
415 {
416
417 Point old_offset = bufferToClient(Point(0, 0));
418
419 // Update the cached sizing information
420 RECT r;
421 GetClientRect(getMainHandle(), &r);
422 MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right - r.left,
423 r.bottom - r.top - tb.getHeight(), TRUE);
424
425 GetWindowRect(getFrameHandle(), &r);
426 window_size = Rect(r.left, r.top, r.right, r.bottom);
427 GetClientRect(getFrameHandle(), &r);
428 client_size = Rect(r.left, r.top, r.right, r.bottom);
429
430 // Determine whether scrollbars are required
431 calculateScrollBars();
432
433 // Resize the ToolBar
434 tb.autoSize();
435
436 // Redraw if required
437 if (!old_offset.equals(bufferToClient(Point(0, 0))))
438 InvalidateRect(getFrameHandle(), 0, TRUE);
439 }
440 break;
441
442 case WM_HSCROLL:
443 tb.processWM_HSCROLL(wParam, lParam);
444 break;
445
446 case WM_NOTIFY:
447 return tb.processWM_NOTIFY(wParam, lParam);
448
449 case WM_CLOSE:
450 vlog.debug("WM_CLOSE %x", getMainHandle());
451 PostQuitMessage(0);
452 break;
453 }
454
455 return rfb::win32::SafeDefWindowProc(getMainHandle(), msg, wParam, lParam);
456}
457
458LRESULT RfbPlayer::processFrameMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
459 switch (msg) {
460
461 case WM_PAINT:
462 {
463 if (isSeeking() || rewindFlag) {
464 seekMode = true;
465 return 0;
466 } else {
467 if (seekMode) {
468 seekMode = false;
469 InvalidateRect(getFrameHandle(), 0, true);
470 UpdateWindow(getFrameHandle());
471 return 0;
472 }
473 }
474
475 PAINTSTRUCT ps;
476 HDC paintDC = BeginPaint(getFrameHandle(), &ps);
477 if (!paintDC)
478 throw SystemException("unable to BeginPaint", GetLastError());
479 Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
480
481 if (!pr.is_empty()) {
482
483 if (buffer->bitmap) {
484
485 // Get device context
486 BitmapDC bitmapDC(paintDC, buffer->bitmap);
487
488 // Blit the border if required
489 Rect bufpos = bufferToClient(buffer->getRect());
490 if (!pr.enclosed_by(bufpos)) {
491 vlog.debug("draw border");
492 HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
493 RECT r;
494 SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
495 SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
496 SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
497 SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
498 }
499
500 // Do the blit
501 Point buf_pos = clientToBuffer(pr.tl);
502 if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
503 bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
504 throw SystemException("unable to BitBlt to window", GetLastError());
505
506 } else {
507 // Blit a load of black
508 if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
509 0, 0, 0, BLACKNESS))
510 throw SystemException("unable to BitBlt to blank window", GetLastError());
511 }
512 }
513 EndPaint(getFrameHandle(), &ps);
514 }
515 return 0;
516
517 // Process play/pause by the left mouse button
518 case WM_LBUTTONDOWN:
519 SendMessage(getMainHandle(), WM_COMMAND, ID_PLAYPAUSE, 0);
520 return 0;
521
522 case WM_VSCROLL:
523 case WM_HSCROLL:
524 {
525 Point delta;
526 int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
527
528 switch (LOWORD(wParam)) {
529 case SB_PAGEUP: newpos -= 50; break;
530 case SB_PAGEDOWN: newpos += 50; break;
531 case SB_LINEUP: newpos -= 5; break;
532 case SB_LINEDOWN: newpos += 5; break;
533 case SB_THUMBTRACK:
534 case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
535 default: vlog.info("received unknown scroll message");
536 };
537
538 if (msg == WM_HSCROLL)
539 setViewportOffset(Point(newpos, scrolloffset.y));
540 else
541 setViewportOffset(Point(scrolloffset.x, newpos));
542
543 SCROLLINFO si;
544 si.cbSize = sizeof(si);
545 si.fMask = SIF_POS;
546 si.nPos = newpos;
547 SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
548 }
549 break;
550 }
551
552 return DefWindowProc(hwnd, msg, wParam, lParam);
553}
554
555void RfbPlayer::disableTBandMenuItems() {
556 // Disable the menu items
557 EnableMenuItem(hMenu, ID_CLOSEFILE, MF_GRAYED | MF_BYCOMMAND);
558 EnableMenuItem(hMenu, ID_SESSION_INFO, MF_GRAYED | MF_BYCOMMAND);
559 ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_GRAYED | MF_BYCOMMAND);
560 ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_GRAYED | MF_BYPOSITION);
561 EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_GRAYED | MF_BYCOMMAND);
562 EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
563 EnableMenuItem(hMenu, ID_GOTO, MF_GRAYED | MF_BYCOMMAND);
564 EnableMenuItem(hMenu, ID_LOOP, MF_GRAYED | MF_BYCOMMAND);
565 ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_GRAYED | MF_BYCOMMAND);
566 ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_GRAYED | MF_BYCOMMAND);
567
568 // Disable the toolbar buttons and child controls
569 tb.disable();
570}
571
572void RfbPlayer::enableTBandMenuItems() {
573 // Enable the menu items
574 EnableMenuItem(hMenu, ID_CLOSEFILE, MF_ENABLED | MF_BYCOMMAND);
575 EnableMenuItem(hMenu, ID_SESSION_INFO, MF_ENABLED | MF_BYCOMMAND);
576 ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_ENABLED | MF_BYCOMMAND);
577 ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_ENABLED | MF_BYPOSITION);
578 EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_ENABLED | MF_BYCOMMAND);
579 EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
580 EnableMenuItem(hMenu, ID_GOTO, MF_ENABLED | MF_BYCOMMAND);
581 EnableMenuItem(hMenu, ID_LOOP, MF_ENABLED | MF_BYCOMMAND);
582 ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_ENABLED | MF_BYCOMMAND);
583 ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_ENABLED | MF_BYCOMMAND);
584
585 // Enable the toolbar buttons and child controls
586 tb.enable();
587}
588
589void RfbPlayer::setVisible(bool visible) {
590 ShowWindow(getMainHandle(), visible ? SW_SHOW : SW_HIDE);
591 if (visible) {
592 // When the window becomes visible, make it active
593 SetForegroundWindow(getMainHandle());
594 SetActiveWindow(getMainHandle());
595 }
596}
597
598void RfbPlayer::setTitle(const char *title) {
599 char _title[256];
600 strcpy(_title, AppName);
601 strcat(_title, " - ");
602 strcat(_title, title);
603 SetWindowText(getMainHandle(), _title);
604}
605
606void RfbPlayer::setFrameSize(int width, int height) {
607 // Calculate and set required size for main window
608 RECT r = {0, 0, width, height};
609 AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), TRUE,
610 GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
611 r.bottom += tb.getHeight(); // Include RfbPlayr's controls area
612 AdjustWindowRect(&r, GetWindowLong(getMainHandle(), GWL_STYLE), FALSE);
613 int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2);
614 int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2);
615 SetWindowPos(getMainHandle(), 0, x, y, r.right-r.left, r.bottom-r.top,
616 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
617
618 // Enable/disable scrollbars as appropriate
619 calculateScrollBars();
620}
621
622void RfbPlayer::calculateScrollBars() {
623 // Calculate the required size of window
624 DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
625 DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
626 DWORD old_style;
627 RECT r;
628 SetRect(&r, 0, 0, buffer->width(), buffer->height());
629 AdjustWindowRectEx(&r, style, FALSE, GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
630 Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
631
632 // Work out whether scroll bars are required
633 do {
634 old_style = style;
635
636 if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
637 style |= WS_HSCROLL;
638 reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
639 }
640 if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
641 style |= WS_VSCROLL;
642 reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
643 }
644 } while (style != old_style);
645
646 // Tell Windows to update the window style & cached settings
647 if (style != current_style) {
648 SetWindowLong(getFrameHandle(), GWL_STYLE, style);
649 SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
650 }
651
652 // Update the scroll settings
653 SCROLLINFO si;
654 if (style & WS_VSCROLL) {
655 si.cbSize = sizeof(si);
656 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
657 si.nMin = 0;
658 si.nMax = buffer->height();
659 si.nPage = buffer->height() - (reqd_size.height() - window_size.height());
660 maxscrolloffset.y = max(0, si.nMax-si.nPage);
661 scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
662 si.nPos = scrolloffset.y;
663 SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE);
664 }
665 if (style & WS_HSCROLL) {
666 si.cbSize = sizeof(si);
667 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
668 si.nMin = 0;
669 si.nMax = buffer->width();
670 si.nPage = buffer->width() - (reqd_size.width() - window_size.width());
671 maxscrolloffset.x = max(0, si.nMax-si.nPage);
672 scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
673 si.nPos = scrolloffset.x;
674 SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE);
675 }
676
677 // Update the cached client size
678 GetClientRect(getFrameHandle(), &r);
679 client_size = Rect(r.left, r.top, r.right, r.bottom);
680}
681
682bool RfbPlayer::setViewportOffset(const Point& tl) {
683/* ***
684 Point np = Point(max(0, min(maxscrolloffset.x, tl.x)),
685 max(0, min(maxscrolloffset.y, tl.y)));
686 */
687 Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
688 max(0, min(tl.y, buffer->height()-client_size.height())));
689 Point delta = np.translate(scrolloffset.negate());
690 if (!np.equals(scrolloffset)) {
691 scrolloffset = np;
692 ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
693 UpdateWindow(getFrameHandle());
694 return true;
695 }
696 return false;
697}
698
699void RfbPlayer::close(const char* reason) {
700 setVisible(false);
701 if (reason) {
702 vlog.info("closing - %s", reason);
703 MessageBox(NULL, TStr(reason), "RfbPlayer", MB_ICONINFORMATION | MB_OK);
704 }
705 SendMessage(getFrameHandle(), WM_CLOSE, 0, 0);
706}
707
708void RfbPlayer::blankBuffer() {
709 fillRect(buffer->getRect(), 0);
710}
711
712void RfbPlayer::rewind() {
713 bool paused = isPaused();
714 blankBuffer();
715 newSession(fileName);
716 skipHandshaking();
717 is->setSpeed(options.playbackSpeed);
718 if (paused) is->pausePlayback();
719 else is->resumePlayback();
720}
721
722void RfbPlayer::processMsg() {
723 // Perform return if waitWhilePaused processed because
724 // rfbReader thread could receive the signal to close
725 if (waitWhilePaused()) return;
726
727 static long update_time = GetTickCount();
728 try {
729 if ((!isSeeking()) && ((GetTickCount() - update_time) > 250)
730 && (!tb.isPosSliderDragging())) {
731 // Update pos in the toolbar 4 times in 1 second
732 tb.updatePos(getTimeOffset());
733 update_time = GetTickCount();
734 }
735 RfbProto::processMsg();
736 } catch (rdr::Exception e) {
737 if (strcmp(e.str(), "[End Of File]") == 0) {
738 rewind();
739 setPaused(!options.loopPlayback);
740 tb.updatePos(getTimeOffset());
741 return;
742 }
743 // It's a special exception to perform backward seeking.
744 // We only rewind the stream and seek the offset
745 if (strcmp(e.str(), "[REWIND]") == 0) {
746 rewindFlag = true;
747 long seekOffset = max(getSeekOffset(), imageDataStartTime);
748 rewind();
749 if (!stopped) setPos(seekOffset);
750 else stopped = false;
751 tb.updatePos(seekOffset);
752 rewindFlag = false;
753 return;
754 }
755 // It's a special exception which is used to terminate the playback
756 if (strcmp(e.str(), "[TERMINATE]") == 0) {
757 sessionTerminateThread *terminate = new sessionTerminateThread(this);
758 terminate->start();
759 } else {
760 // Show the exception message and close the session playback
761 is->pausePlayback();
762 char message[256] = "\0";
763 strcat(message, e.str());
764 strcat(message, "\nMaybe you force wrong the pixel format for this session");
765 MessageBox(getMainHandle(), message, "RFB Player", MB_OK | MB_ICONERROR);
766 sessionTerminateThread *terminate = new sessionTerminateThread(this);
767 terminate->start();
768 return;
769 }
770 }
771}
772
773long ChoosePixelFormatDialog::pfIndex = DEFAULT_PF_INDEX;
774bool ChoosePixelFormatDialog::bigEndian = false;
775
776void RfbPlayer::serverInit() {
777 RfbProto::serverInit();
778
779 // Save the image data start time
780 imageDataStartTime = is->getTimeOffset();
781
782 // Resize the backing buffer
783 buffer->setSize(cp.width, cp.height);
784
785 // Check on the true colour mode
786 if (!(cp.pf()).trueColour)
787 throw rdr::Exception("This version plays only true color session!");
788
789 // Set the session pixel format
790 if (options.askPixelFormat) {
791 ChoosePixelFormatDialog choosePixelFormatDialog(&supportedPF);
792 if (choosePixelFormatDialog.showDialog(getMainHandle())) {
793 long pixelFormatIndex = choosePixelFormatDialog.getPFIndex();
794 if (pixelFormatIndex < 0) {
795 options.autoDetectPF = true;
796 options.setPF((PixelFormat *)&cp.pf());
797 } else {
798 options.autoDetectPF = false;
799 options.setPF(&supportedPF[pixelFormatIndex]->PF);
800 options.pixelFormat.bigEndian = choosePixelFormatDialog.isBigEndian();
801 }
802 } else {
803 is->pausePlayback();
804 throw rdr::Exception("[TERMINATE]");
805 }
806 } else {
807 if (!options.commandLineParam) {
808 if (options.autoDetectPF) {
809 options.setPF((PixelFormat *)&cp.pf());
810 } else {
811 options.setPF(&supportedPF[options.pixelFormatIndex]->PF);
812 options.pixelFormat.bigEndian = options.bigEndianFlag;
813 }
814 } else if (options.autoDetectPF) {
815 options.setPF((PixelFormat *)&cp.pf());
816 }
817 }
818 cp.setPF(options.pixelFormat);
819 buffer->setPF(options.pixelFormat);
820
821 // If the window is not maximised then resize it
822 if (!(GetWindowLong(getMainHandle(), GWL_STYLE) & WS_MAXIMIZE))
823 setFrameSize(cp.width, cp.height);
824
825 // Set the window title and show it
826 setTitle(cp.name());
827
828 // Calculate the full session time and update posTrackBar control in toolbar
829 sessionTimeMs = calculateSessionTime(fileName);
830 tb.init(sessionTimeMs);
831 tb.updatePos(getTimeOffset());
832
833 setPaused(!options.autoPlay);
834 // Restore the parameters from registry,
835 // which was replaced by command-line parameters.
836 if (options.commandLineParam) {
837 options.readFromRegistry();
838 options.commandLineParam = false;
839 }
840}
841
842void RfbPlayer::setColourMapEntries(int first, int count, U16* rgbs) {
843 vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
844 throw rdr::Exception("Can't handle SetColourMapEntries message");
845/* int i;
846 for (i=0;i<count;i++) {
847 buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
848 }
849 // *** change to 0, 256?
850 refreshWindowPalette(first, count);
851 palette_changed = true;
852 InvalidateRect(getFrameHandle(), 0, FALSE);*/
853}
854
855void RfbPlayer::bell() {
856 if (options.acceptBell)
857 MessageBeep(-1);
858}
859
860void RfbPlayer::serverCutText(const char* str, int len) {
861 if (cutText != NULL)
862 delete [] cutText;
863 cutText = new char[len + 1];
864 memcpy(cutText, str, len);
865 cutText[len] = '\0';
866}
867
868void RfbPlayer::frameBufferUpdateEnd() {
869};
870
871void RfbPlayer::beginRect(const Rect& r, unsigned int encoding) {
872 currentEncoding = encoding;
873}
874
875void RfbPlayer::endRect(const Rect& r, unsigned int encoding) {
876}
877
878
879void RfbPlayer::fillRect(const Rect& r, Pixel pix) {
880 buffer->fillRect(r, pix);
881 invalidateBufferRect(r);
882}
883
884void RfbPlayer::imageRect(const Rect& r, void* pixels) {
885 buffer->imageRect(r, pixels);
886 invalidateBufferRect(r);
887}
888
889void RfbPlayer::copyRect(const Rect& r, int srcX, int srcY) {
890 buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
891 invalidateBufferRect(r);
892}
893
894bool RfbPlayer::invalidateBufferRect(const Rect& crect) {
895 Rect rect = bufferToClient(crect);
896 if (rect.intersect(client_size).is_empty()) return false;
897 RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
898 InvalidateRect(getFrameHandle(), &invalid, FALSE);
899 return true;
900}
901
902bool RfbPlayer::waitWhilePaused() {
903 bool result = false;
904 while(isPaused() && !isSeeking()) {
905 Sleep(20);
906 result = true;
907 }
908 return result;
909}
910
911long RfbPlayer::calculateSessionTime(char *filename) {
912 FbsInputStream sessionFile(filename);
913 sessionFile.setTimeOffset(100000000);
914 try {
915 while (TRUE) {
916 sessionFile.skip(1024);
917 }
918 } catch (rdr::Exception e) {
919 if (strcmp(e.str(), "[End Of File]") == 0) {
920 return sessionFile.getTimeOffset();
921 } else {
922 MessageBox(getMainHandle(), e.str(), "RFB Player", MB_OK | MB_ICONERROR);
923 return 0;
924 }
925 }
926 return 0;
927}
928
929void RfbPlayer::init() {
930 if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
931 else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
932}
933
934void RfbPlayer::closeSessionFile() {
935 DWORD dwStyle;
936 RECT r;
937
938 // Uncheck all toolbar buttons
939 if (tb.getHandle()) {
940 tb.checkButton(ID_PLAY, false);
941 tb.checkButton(ID_PAUSE, false);
942 tb.checkButton(ID_STOP, false);
943 }
944
945 // Stop playback and update the player state
946 disableTBandMenuItems();
947 if (rfbReader) {
948 delete rfbReader->join();
949 rfbReader = 0;
950 delete [] fileName;
951 fileName = 0;
952 }
953 blankBuffer();
954 setTitle("None");
955 options.playbackSpeed = 1.0;
956 tb.init(0);
957
958 // Change the player window size and frame size to default
959 if ((dwStyle = GetWindowLong(getMainHandle(), GWL_STYLE)) & WS_MAXIMIZE) {
960 dwStyle &= ~WS_MAXIMIZE;
961 SetWindowLong(getMainHandle(), GWL_STYLE, dwStyle);
962 }
963 int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
964 int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
965 SetWindowPos(getMainHandle(), 0, x, y,
966 DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT,
967 SWP_NOZORDER | SWP_FRAMECHANGED);
968 buffer->setSize(32, 32);
969 calculateScrollBars();
970
971 // Update the cached sizing information and repaint the frame window
972 GetWindowRect(getFrameHandle(), &r);
973 window_size = Rect(r.left, r.top, r.right, r.bottom);
974 GetClientRect(getFrameHandle(), &r);
975 client_size = Rect(r.left, r.top, r.right, r.bottom);
976 InvalidateRect(getFrameHandle(), 0, TRUE);
977 UpdateWindow(getFrameHandle());
978}
979
980void RfbPlayer::openSessionFile(char *_fileName) {
981 fileName = strDup(_fileName);
982
983 // Close the previous reading thread
984 if (rfbReader) {
985 delete rfbReader->join();
986 rfbReader = 0;
987 }
988 blankBuffer();
989 newSession(fileName);
990 setSpeed(options.playbackSpeed);
991 rfbReader = new rfbSessionReader(this);
992 rfbReader->start();
993 tb.setTimePos(0);
994 enableTBandMenuItems();
995}
996
997void RfbPlayer::setPaused(bool paused) {
998 if (paused) {
999 is->pausePlayback();
1000 tb.checkButton(ID_PAUSE, true);
1001 tb.checkButton(ID_PLAY, false);
1002 tb.checkButton(ID_STOP, false);
1003 } else {
1004 if (is) is->resumePlayback();
1005 tb.checkButton(ID_PLAY, true);
1006 tb.checkButton(ID_STOP, false);
1007 tb.checkButton(ID_PAUSE, false);
1008 }
1009 tb.enableButton(ID_PAUSE, true);
1010 EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
1011}
1012
1013void RfbPlayer::stopPlayback() {
1014 stopped = true;
1015 setPos(0);
1016 if (is) {
1017 is->pausePlayback();
1018 is->interruptFrameDelay();
1019 }
1020 tb.checkButton(ID_STOP, true);
1021 tb.checkButton(ID_PLAY, false);
1022 tb.checkButton(ID_PAUSE, false);
1023 tb.enableButton(ID_PAUSE, false);
1024 tb.setTimePos(0);
1025 EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
1026}
1027
1028void RfbPlayer::setSpeed(double speed) {
1029 if (speed > 0) {
1030 char speedStr[20] = "\0";
1031 double newSpeed = min(speed, MAX_SPEED);
1032 is->setSpeed(newSpeed);
1033 options.playbackSpeed = newSpeed;
1034 SendMessage(tb.getSpeedUpDownHwnd(), UDM_SETPOS,
1035 0, MAKELONG((short)(newSpeed / 0.5), 0));
1036 sprintf(speedStr, "%.2f", newSpeed);
1037 SetWindowText(tb.getSpeedEditHwnd(), speedStr);
1038 }
1039}
1040
1041double RfbPlayer::getSpeed() {
1042 return is->getSpeed();
1043}
1044
1045void RfbPlayer::setPos(long pos) {
1046 is->setTimeOffset(max(pos, imageDataStartTime));
1047}
1048
1049long RfbPlayer::getSeekOffset() {
1050 return is->getSeekOffset();
1051}
1052
1053bool RfbPlayer::isSeeking() {
1054 if (is) return is->isSeeking();
1055 else return false;
1056}
1057
1058bool RfbPlayer::isSeekMode() {
1059 return seekMode;
1060}
1061
1062bool RfbPlayer::isPaused() {
1063 return is->isPaused();
1064}
1065
1066long RfbPlayer::getTimeOffset() {
1067 return max(is->getTimeOffset(), is->getSeekOffset());
1068}
1069
1070void RfbPlayer::skipHandshaking() {
1071 int skipBytes = 12 + 4 + 24 + strlen(cp.name());
1072 is->skip(skipBytes);
1073 state_ = RFBSTATE_NORMAL;
1074}
1075
1076void programInfo() {
1077 win32::FileVersionInfo inf;
1078 _tprintf(_T("%s - %s, Version %s\n"),
1079 inf.getVerString(_T("ProductName")),
1080 inf.getVerString(_T("FileDescription")),
1081 inf.getVerString(_T("FileVersion")));
1082 printf("%s\n", buildTime);
1083 _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
1084}
1085
1086void programUsage() {
1087 InfoDialog usageDialog(usage_msg);
1088 usageDialog.showDialog();
1089}
1090
1091char *fileName = 0;
1092
1093// playerOptions is the player options with default parameters values,
1094// it is used only for run the player with command-line parameters
1095PlayerOptions playerOptions;
1096bool print_usage = false;
1097bool print_upf_list = false;
1098
1099bool processParams(int argc, char* argv[]) {
1100 playerOptions.commandLineParam = true;
1101 for (int i = 1; i < argc; i++) {
1102 if ((strcasecmp(argv[i], "-help") == 0) ||
1103 (strcasecmp(argv[i], "--help") == 0) ||
1104 (strcasecmp(argv[i], "/help") == 0) ||
1105 (strcasecmp(argv[i], "-h") == 0) ||
1106 (strcasecmp(argv[i], "/h") == 0) ||
1107 (strcasecmp(argv[i], "/?") == 0) ||
1108 (strcasecmp(argv[i], "-?") == 0)) {
1109 print_usage = true;
1110 return true;
1111 }
1112
1113 if ((strcasecmp(argv[i], "-pf") == 0) ||
1114 (strcasecmp(argv[i], "/pf") == 0) && (i < argc-1)) {
1115 char *pf = argv[++i];
1116 char rgb_order[4] = "\0";
1117 int order = RGB_ORDER;
1118 int r = -1, g = -1, b = -1;
1119 bool big_endian = false;
1120 if (strlen(pf) < 6) return false;
1121 while (strlen(pf)) {
1122 if ((pf[0] == 'r') || (pf[0] == 'R')) {
1123 if (r >=0 ) return false;
1124 r = atoi(++pf);
1125 strcat(rgb_order, "r");
1126 continue;
1127 }
1128 if ((pf[0] == 'g') || (pf[0] == 'G')) {
1129 if (g >=0 ) return false;
1130 g = atoi(++pf);
1131 strcat(rgb_order, "g");
1132 continue;
1133 }
1134 if (((pf[0] == 'b') || (pf[0] == 'B')) &&
1135 (pf[1] != 'e') && (pf[1] != 'E')) {
1136 if (b >=0 ) return false;
1137 b = atoi(++pf);
1138 strcat(rgb_order, "b");
1139 continue;
1140 }
1141 if ((pf[0] == 'l') || (pf[0] == 'L') ||
1142 (pf[0] == 'b') || (pf[0] == 'B')) {
1143 if (strcasecmp(pf, "le") == 0) break;
1144 if (strcasecmp(pf, "be") == 0) { big_endian = true; break;}
1145 return false;
1146 }
1147 pf++;
1148 }
1149 if ((r < 0) || (g < 0) || (b < 0) || (r + g + b > 32)) return false;
1150 if (strcasecmp(rgb_order, "rgb") == 0) { order = RGB_ORDER; }
1151 else if (strcasecmp(rgb_order, "rbg") == 0) { order = RBG_ORDER; }
1152 else if (strcasecmp(rgb_order, "grb") == 0) { order = GRB_ORDER; }
1153 else if (strcasecmp(rgb_order, "gbr") == 0) { order = GBR_ORDER; }
1154 else if (strcasecmp(rgb_order, "bgr") == 0) { order = BGR_ORDER; }
1155 else if (strcasecmp(rgb_order, "brg") == 0) { order = BRG_ORDER; }
1156 else return false;
1157 playerOptions.autoDetectPF = false;
1158 playerOptions.setPF(order, r, g, b, big_endian);
1159 continue;
1160 }
1161
1162 if ((strcasecmp(argv[i], "-upf") == 0) ||
1163 (strcasecmp(argv[i], "/upf") == 0) && (i < argc-1)) {
1164 if ((i == argc - 1) || (argv[++i][0] == '-')) {
1165 print_upf_list = true;
1166 return true;
1167 }
1168 PixelFormatList userPfList;
1169 userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
1170 int index = userPfList.getIndexByPFName(argv[i]);
1171 if (index > 0) {
1172 playerOptions.autoDetectPF = false;
1173 playerOptions.setPF(&userPfList[index]->PF);
1174 } else {
1175 return false;
1176 }
1177 continue;
1178 }
1179
1180 if ((strcasecmp(argv[i], "-speed") == 0) ||
1181 (strcasecmp(argv[i], "/speed") == 0) && (i < argc-1)) {
1182 double playbackSpeed = atof(argv[++i]);
1183 if (playbackSpeed <= 0) {
1184 return false;
1185 }
1186 playerOptions.playbackSpeed = playbackSpeed;
1187 continue;
1188 }
1189
1190 if ((strcasecmp(argv[i], "-pos") == 0) ||
1191 (strcasecmp(argv[i], "/pos") == 0) && (i < argc-1)) {
1192 long initTime = atol(argv[++i]);
1193 if (initTime <= 0)
1194 return false;
1195 playerOptions.initTime = initTime;
1196 continue;
1197 }
1198
1199 if ((strcasecmp(argv[i], "-autoplay") == 0) ||
1200 (strcasecmp(argv[i], "/autoplay") == 0) && (i < argc-1)) {
1201 playerOptions.autoPlay = true;
1202 continue;
1203 }
1204
1205 if ((strcasecmp(argv[i], "-loop") == 0) ||
1206 (strcasecmp(argv[i], "/loop") == 0) && (i < argc-1)) {
1207 playerOptions.loopPlayback = true;
1208 continue;
1209 }
1210
1211 if (i != argc - 1)
1212 return false;
1213 }
1214
1215 fileName = strDup(argv[argc-1]);
1216 if (fileName[0] == '-') return false;
1217 else return true;
1218}
1219
1220//
1221// -=- WinMain
1222//
1223
1224int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
1225
1226 // - Process the command-line
1227
1228 int argc = __argc;
1229 char** argv = __argv;
1230 if ((argc > 1) && (!processParams(argc, argv))) {
1231 MessageBox(0, wrong_cmd_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
1232 return 0;
1233 }
1234
1235 if (print_usage) {
1236 programUsage();
1237 return 0;
1238 }
1239 // Show the user defined pixel formats if required
1240 if (print_upf_list) {
1241 int list_size = 256;
1242 char *upf_list = new char[list_size];
1243 PixelFormatList userPfList;
1244 userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
1245 strcpy(upf_list, "The list of the user defined pixel formats:\r\n");
1246 for (int i = userPfList.getDefaultPFCount(); i < userPfList.count(); i++) {
1247 if ((list_size - strlen(upf_list) - 1) <
1248 (strlen(userPfList[i]->format_name) + 2)) {
1249 char *tmpStr = new char[list_size =
1250 list_size + strlen(userPfList[i]->format_name) + 2];
1251 strcpy(tmpStr, upf_list);
1252 delete [] upf_list;
1253 upf_list = new char[list_size];
1254 strcpy(upf_list, tmpStr);
1255 delete [] tmpStr;
1256 }
1257 strcat(upf_list, userPfList[i]->format_name);
1258 strcat(upf_list, "\r\n");
1259 }
1260 InfoDialog upfInfoDialog(upf_list);
1261 upfInfoDialog.showDialog();
1262 delete [] upf_list;
1263 return 0;
1264 }
1265
1266 // Create the player
1267 RfbPlayer *player = NULL;
1268 try {
1269 player = new RfbPlayer(fileName, &playerOptions);
1270 } catch (rdr::Exception e) {
1271 MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
1272 delete player;
1273 return 0;
1274 }
1275
1276 // Run the player
1277 HACCEL hAccel = LoadAccelerators(inst, MAKEINTRESOURCE(IDR_ACCELERATOR));
1278 MSG msg;
1279 while (GetMessage(&msg, NULL, 0, 0) > 0) {
1280 if(!TranslateAccelerator(player->getMainHandle(), hAccel, &msg)) {
1281 TranslateMessage(&msg);
1282 DispatchMessage(&msg);
1283 }
1284 }
1285
1286 // Destroy the player
1287 try{
1288 if (player) delete player;
1289 } catch (rdr::Exception e) {
1290 MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
1291 }
1292
1293 return 0;
1294};