Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@591 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/win/rfbplayer/rfbplayer.cxx b/win/rfbplayer/rfbplayer.cxx
new file mode 100644
index 0000000..b304aec
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.cxx
@@ -0,0 +1,1294 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- RFB Player for Win32
+#include <windows.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#include <rfb/LogWriter.h>
+
+#include <rfb_win32/AboutDialog.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/Win32Util.h>
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/ChoosePixelFormatDialog.h>
+#include <rfbplayer/GotoPosDialog.h>
+#include <rfbplayer/InfoDialog.h>
+#include <rfbplayer/SessionInfoDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+// -=- Variables & consts
+
+static LogWriter vlog("RfbPlayer");
+
+TStr rfb::win32::AppName("RfbPlayer");
+extern const char* buildTime;
+HFONT hFont = 0;
+
+char wrong_cmd_msg[] =
+ "Wrong command-line parameters!\n"
+ "Use for help: rfbplayer -help";
+
+char usage_msg[] =
+ "usage: rfbplayer <options> <filename>\r\n"
+ "Command-line options:\r\n"
+ " -help \t- Provide usage information.\r\n"
+ " -pf <mode> \t- Forces the pixel format for the session.\r\n"
+ " \t <mode>=r<r_bits>g<g_bits>b<b_bits>[le|be],\r\n"
+ " \t r_bits - size the red component, in bits,\r\n"
+ " \t g_bits - size the green component, in bits,\r\n"
+ " \t b_bits - size the blue component, in bits,\r\n"
+ " \t le - little endian byte order (default),\r\n"
+ " \t be - big endian byte order.\r\n"
+ " \t The r, g, b component is in any order.\r\n"
+ " \t Default: auto detect the pixel format.\r\n"
+ " -upf <name> \t- Forces the user defined pixel format for\r\n"
+ " \t the session. If <name> is empty then application\r\n"
+ " \t shows the list of user defined pixel formats.\r\n"
+ " \t Don't use this option with -pf.\r\n"
+ " -speed <value>\t- Sets playback speed, where 1 is normal speed,\r\n"
+ " \t is double speed, 0.5 is half speed. Default: 1.0.\r\n"
+ " -pos <ms> \t- Sets initial time position in the session file,\r\n"
+ " \t in milliseconds. Default: 0.\r\n"
+ " -autoplay \t- Runs the player in the playback mode.\r\n"
+ " -loop \t- Replays the rfb session.";
+
+// -=- RfbPlayer's defines and consts
+
+#define strcasecmp _stricmp
+#define DEFAULT_PLAYER_WIDTH 640
+#define DEFAULT_PLAYER_HEIGHT 480
+
+//
+// -=- AboutDialog global values
+//
+
+const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
+const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
+const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
+const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
+const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
+
+//
+// -=- RfbPlayerClass
+
+//
+// Window class used as the basis for RfbPlayer instance
+//
+
+class RfbPlayerClass {
+public:
+ RfbPlayerClass();
+ ~RfbPlayerClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK RfbPlayerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+
+ if (msg == WM_CREATE)
+ SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY) {
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ SetWindowLong(hwnd, GWL_USERDATA, 0);
+ }
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", hwnd, msg);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processMainMessage(hwnd, msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+};
+
+RfbPlayerClass::RfbPlayerClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = RfbPlayerProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+ if (!wndClass.hIcon)
+ printf("unable to load icon:%ld", GetLastError());
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = HBRUSH(COLOR_WINDOW);
+ wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
+ wndClass.lpszClassName = _T("RfbPlayerClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register RfbPlayer window class",
+ GetLastError());
+ }
+}
+
+RfbPlayerClass::~RfbPlayerClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+RfbPlayerClass baseClass;
+
+//
+// -=- RfbFrameClass
+
+//
+// Window class used to displaying the rfb data
+//
+
+class RfbFrameClass {
+public:
+ RfbFrameClass();
+ ~RfbFrameClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+
+ if (msg == WM_CREATE)
+ SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(hwnd, GWL_USERDATA, 0);
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", hwnd, msg);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processFrameMessage(hwnd, msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+}
+
+RfbFrameClass::RfbFrameClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = FrameProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = 0;
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = 0;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("RfbPlayerClass1");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register RfbPlayer window class",
+ GetLastError());
+ }
+}
+
+RfbFrameClass::~RfbFrameClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+RfbFrameClass frameClass;
+
+//
+// -=- RfbPlayer instance implementation
+//
+
+RfbPlayer::RfbPlayer(char *_fileName, PlayerOptions *_options)
+: RfbProto(_fileName), fileName(_fileName), buffer(0), client_size(0, 0, 32, 32),
+ window_size(0, 0, 32, 32), cutText(0), seekMode(false), lastPos(0),
+ rfbReader(0), sessionTimeMs(0), sliderStepMs(0), imageDataStartTime(0),
+ rewindFlag(false), stopped(false), currentEncoding(-1) {
+
+ // Save the player options
+ memcpy(&options, _options, sizeof(options));
+
+ // Reset the full session time
+ strcpy(fullSessionTime, "00m:00s");
+
+ // Load the user defined pixel formats from the registry
+ supportedPF.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+
+ // Create the main window
+ const TCHAR* name = _T("RfbPlayer");
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+ mainHwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW,
+ x, y, DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT, 0, 0, baseClass.instance, this);
+ if (!mainHwnd) {
+ throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+ }
+ vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), getMainHandle());
+
+ // Create the backing buffer
+ buffer = new win32::DIBSectionBuffer(getFrameHandle());
+ setVisible(true);
+
+ // If run with command-line parameters,
+ // open the session file with default settings, otherwise
+ // restore player settings from the registry
+ if (fileName) {
+ openSessionFile(fileName);
+ if (options.initTime > 0) setPos(options.initTime);
+ setSpeed(options.playbackSpeed);
+ } else {
+ options.readFromRegistry();
+ disableTBandMenuItems();
+ setTitle("None");
+ }
+ init();
+}
+
+RfbPlayer::~RfbPlayer() {
+ vlog.debug("~RfbPlayer");
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ }
+ if (mainHwnd) {
+ setVisible(false);
+ DestroyWindow(mainHwnd);
+ mainHwnd = 0;
+ }
+ if (buffer) delete buffer;
+ if (cutText) delete [] cutText;
+ if (fileName) delete [] fileName;
+ if (hFont) DeleteObject(hFont);
+ vlog.debug("~RfbPlayer done");
+}
+
+LRESULT
+RfbPlayer::processMainMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+
+ switch (msg) {
+
+ // -=- Process standard window messages
+
+ case WM_CREATE:
+ {
+ tb.create(this, hwnd);
+
+ // Create the frame window
+ frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+ 0, WS_CHILD | WS_VISIBLE, 0, tb.getHeight(), 10, tb.getHeight() + 10,
+ hwnd, 0, frameClass.instance, this);
+
+ hMenu = GetMenu(hwnd);
+
+ return 0;
+ }
+
+ // Process the main menu and toolbar's messages
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+ case ID_OPENFILE:
+ {
+ char curDir[_MAX_DIR];
+ static char filename[_MAX_PATH];
+ OPENFILENAME ofn;
+ memset((void *) &ofn, 0, sizeof(OPENFILENAME));
+ GetCurrentDirectory(sizeof(curDir), curDir);
+
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = getMainHandle();
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof(filename);
+ ofn.lpstrInitialDir = curDir;
+ ofn.lpstrFilter = "Rfb Session files (*.rfb, *.fbs)\0*.rfb;*.fbs\0" \
+ "All files (*.*)\0*.*\0";
+ ofn.lpstrDefExt = "rfb";
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ if (GetOpenFileName(&ofn)) {
+ openSessionFile(filename);
+ }
+ }
+ break;
+ case ID_CLOSEFILE:
+ closeSessionFile();
+ break;
+ case ID_SESSION_INFO:
+ {
+ SessionInfoDialog sessionInfo(&cp, currentEncoding);
+ sessionInfo.showDialog(getMainHandle());
+ }
+ break;
+ case ID_PLAY:
+ setPaused(false);
+ break;
+ case ID_PAUSE:
+ setPaused(true);
+ break;
+ case ID_STOP:
+ stopPlayback();
+ break;
+ case ID_PLAYPAUSE:
+ if (rfbReader) {
+ if (isPaused()) {
+ setPaused(false);
+ } else {
+ setPaused(true);
+ }
+ }
+ break;
+ case ID_GOTO:
+ {
+ GotoPosDialog gotoPosDlg;
+ if (gotoPosDlg.showDialog(getMainHandle())) {
+ long gotoTime = min(gotoPosDlg.getPos(), sessionTimeMs);
+ setPos(gotoTime);
+ tb.updatePos(gotoTime);
+ setPaused(isPaused());;
+ }
+ }
+ break;
+ case ID_LOOP:
+ options.loopPlayback = !options.loopPlayback;
+ if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+ else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+ break;
+ case ID_RETURN:
+ tb.processWM_COMMAND(wParam, lParam);
+ break;
+ case ID_OPTIONS:
+ {
+ OptionsDialog optionsDialog(&options, &supportedPF);
+ optionsDialog.showDialog(getMainHandle());
+ }
+ break;
+ case ID_EXIT:
+ PostQuitMessage(0);
+ break;
+ case ID_HOMEPAGE:
+ ShellExecute(getMainHandle(), _T("open"), _T("http://www.tightvnc.com/"),
+ NULL, NULL, SW_SHOWDEFAULT);
+ break;
+ case ID_HELP_COMMANDLINESWITCHES:
+ {
+ InfoDialog usageDialog(usage_msg);
+ usageDialog.showDialog(getMainHandle());
+ }
+ break;
+ case ID_ABOUT:
+ AboutDialog::instance.showDialog();
+ break;
+ }
+ break;
+
+ // Update frame's window size and add scrollbars if required
+
+ case WM_SIZE:
+ {
+
+ Point old_offset = bufferToClient(Point(0, 0));
+
+ // Update the cached sizing information
+ RECT r;
+ GetClientRect(getMainHandle(), &r);
+ MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right - r.left,
+ r.bottom - r.top - tb.getHeight(), TRUE);
+
+ GetWindowRect(getFrameHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Determine whether scrollbars are required
+ calculateScrollBars();
+
+ // Resize the ToolBar
+ tb.autoSize();
+
+ // Redraw if required
+ if (!old_offset.equals(bufferToClient(Point(0, 0))))
+ InvalidateRect(getFrameHandle(), 0, TRUE);
+ }
+ break;
+
+ case WM_HSCROLL:
+ tb.processWM_HSCROLL(wParam, lParam);
+ break;
+
+ case WM_NOTIFY:
+ return tb.processWM_NOTIFY(wParam, lParam);
+
+ case WM_CLOSE:
+ vlog.debug("WM_CLOSE %x", getMainHandle());
+ PostQuitMessage(0);
+ break;
+ }
+
+ return rfb::win32::SafeDefWindowProc(getMainHandle(), msg, wParam, lParam);
+}
+
+LRESULT RfbPlayer::processFrameMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ case WM_PAINT:
+ {
+ if (isSeeking() || rewindFlag) {
+ seekMode = true;
+ return 0;
+ } else {
+ if (seekMode) {
+ seekMode = false;
+ InvalidateRect(getFrameHandle(), 0, true);
+ UpdateWindow(getFrameHandle());
+ return 0;
+ }
+ }
+
+ PAINTSTRUCT ps;
+ HDC paintDC = BeginPaint(getFrameHandle(), &ps);
+ if (!paintDC)
+ throw SystemException("unable to BeginPaint", GetLastError());
+ Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+ if (!pr.is_empty()) {
+
+ if (buffer->bitmap) {
+
+ // Get device context
+ BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+ // Blit the border if required
+ Rect bufpos = bufferToClient(buffer->getRect());
+ if (!pr.enclosed_by(bufpos)) {
+ vlog.debug("draw border");
+ HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ RECT r;
+ SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+ }
+
+ // Do the blit
+ Point buf_pos = clientToBuffer(pr.tl);
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+ throw SystemException("unable to BitBlt to window", GetLastError());
+
+ } else {
+ // Blit a load of black
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ 0, 0, 0, BLACKNESS))
+ throw SystemException("unable to BitBlt to blank window", GetLastError());
+ }
+ }
+ EndPaint(getFrameHandle(), &ps);
+ }
+ return 0;
+
+ // Process play/pause by the left mouse button
+ case WM_LBUTTONDOWN:
+ SendMessage(getMainHandle(), WM_COMMAND, ID_PLAYPAUSE, 0);
+ return 0;
+
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ Point delta;
+ int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+ switch (LOWORD(wParam)) {
+ case SB_PAGEUP: newpos -= 50; break;
+ case SB_PAGEDOWN: newpos += 50; break;
+ case SB_LINEUP: newpos -= 5; break;
+ case SB_LINEDOWN: newpos += 5; break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+ default: vlog.info("received unknown scroll message");
+ };
+
+ if (msg == WM_HSCROLL)
+ setViewportOffset(Point(newpos, scrolloffset.y));
+ else
+ setViewportOffset(Point(scrolloffset.x, newpos));
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ si.nPos = newpos;
+ SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
+ }
+ break;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void RfbPlayer::disableTBandMenuItems() {
+ // Disable the menu items
+ EnableMenuItem(hMenu, ID_CLOSEFILE, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_SESSION_INFO, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_GOTO, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_LOOP, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_GRAYED | MF_BYCOMMAND);
+
+ // Disable the toolbar buttons and child controls
+ tb.disable();
+}
+
+void RfbPlayer::enableTBandMenuItems() {
+ // Enable the menu items
+ EnableMenuItem(hMenu, ID_CLOSEFILE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_SESSION_INFO, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_GOTO, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_LOOP, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_ENABLED | MF_BYCOMMAND);
+
+ // Enable the toolbar buttons and child controls
+ tb.enable();
+}
+
+void RfbPlayer::setVisible(bool visible) {
+ ShowWindow(getMainHandle(), visible ? SW_SHOW : SW_HIDE);
+ if (visible) {
+ // When the window becomes visible, make it active
+ SetForegroundWindow(getMainHandle());
+ SetActiveWindow(getMainHandle());
+ }
+}
+
+void RfbPlayer::setTitle(const char *title) {
+ char _title[256];
+ strcpy(_title, AppName);
+ strcat(_title, " - ");
+ strcat(_title, title);
+ SetWindowText(getMainHandle(), _title);
+}
+
+void RfbPlayer::setFrameSize(int width, int height) {
+ // Calculate and set required size for main window
+ RECT r = {0, 0, width, height};
+ AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), TRUE,
+ GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+ r.bottom += tb.getHeight(); // Include RfbPlayr's controls area
+ AdjustWindowRect(&r, GetWindowLong(getMainHandle(), GWL_STYLE), FALSE);
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2);
+ SetWindowPos(getMainHandle(), 0, x, y, r.right-r.left, r.bottom-r.top,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+
+ // Enable/disable scrollbars as appropriate
+ calculateScrollBars();
+}
+
+void RfbPlayer::calculateScrollBars() {
+ // Calculate the required size of window
+ DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD old_style;
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Work out whether scroll bars are required
+ do {
+ old_style = style;
+
+ if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+ style |= WS_HSCROLL;
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+ }
+ if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+ style |= WS_VSCROLL;
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ }
+ } while (style != old_style);
+
+ // Tell Windows to update the window style & cached settings
+ if (style != current_style) {
+ SetWindowLong(getFrameHandle(), GWL_STYLE, style);
+ SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+
+ // Update the scroll settings
+ SCROLLINFO si;
+ if (style & WS_VSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->height();
+ si.nPage = buffer->height() - (reqd_size.height() - window_size.height());
+ maxscrolloffset.y = max(0, si.nMax-si.nPage);
+ scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+ si.nPos = scrolloffset.y;
+ SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE);
+ }
+ if (style & WS_HSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->width();
+ si.nPage = buffer->width() - (reqd_size.width() - window_size.width());
+ maxscrolloffset.x = max(0, si.nMax-si.nPage);
+ scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+ si.nPos = scrolloffset.x;
+ SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE);
+ }
+
+ // Update the cached client size
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+bool RfbPlayer::setViewportOffset(const Point& tl) {
+/* ***
+ Point np = Point(max(0, min(maxscrolloffset.x, tl.x)),
+ max(0, min(maxscrolloffset.y, tl.y)));
+ */
+ Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+ max(0, min(tl.y, buffer->height()-client_size.height())));
+ Point delta = np.translate(scrolloffset.negate());
+ if (!np.equals(scrolloffset)) {
+ scrolloffset = np;
+ ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+ UpdateWindow(getFrameHandle());
+ return true;
+ }
+ return false;
+}
+
+void RfbPlayer::close(const char* reason) {
+ setVisible(false);
+ if (reason) {
+ vlog.info("closing - %s", reason);
+ MessageBox(NULL, TStr(reason), "RfbPlayer", MB_ICONINFORMATION | MB_OK);
+ }
+ SendMessage(getFrameHandle(), WM_CLOSE, 0, 0);
+}
+
+void RfbPlayer::blankBuffer() {
+ fillRect(buffer->getRect(), 0);
+}
+
+void RfbPlayer::rewind() {
+ bool paused = isPaused();
+ blankBuffer();
+ newSession(fileName);
+ skipHandshaking();
+ is->setSpeed(options.playbackSpeed);
+ if (paused) is->pausePlayback();
+ else is->resumePlayback();
+}
+
+void RfbPlayer::processMsg() {
+ // Perform return if waitWhilePaused processed because
+ // rfbReader thread could receive the signal to close
+ if (waitWhilePaused()) return;
+
+ static long update_time = GetTickCount();
+ try {
+ if ((!isSeeking()) && ((GetTickCount() - update_time) > 250)
+ && (!tb.isPosSliderDragging())) {
+ // Update pos in the toolbar 4 times in 1 second
+ tb.updatePos(getTimeOffset());
+ update_time = GetTickCount();
+ }
+ RfbProto::processMsg();
+ } catch (rdr::Exception e) {
+ if (strcmp(e.str(), "[End Of File]") == 0) {
+ rewind();
+ setPaused(!options.loopPlayback);
+ tb.updatePos(getTimeOffset());
+ return;
+ }
+ // It's a special exception to perform backward seeking.
+ // We only rewind the stream and seek the offset
+ if (strcmp(e.str(), "[REWIND]") == 0) {
+ rewindFlag = true;
+ long seekOffset = max(getSeekOffset(), imageDataStartTime);
+ rewind();
+ if (!stopped) setPos(seekOffset);
+ else stopped = false;
+ tb.updatePos(seekOffset);
+ rewindFlag = false;
+ return;
+ }
+ // It's a special exception which is used to terminate the playback
+ if (strcmp(e.str(), "[TERMINATE]") == 0) {
+ sessionTerminateThread *terminate = new sessionTerminateThread(this);
+ terminate->start();
+ } else {
+ // Show the exception message and close the session playback
+ is->pausePlayback();
+ char message[256] = "\0";
+ strcat(message, e.str());
+ strcat(message, "\nMaybe you force wrong the pixel format for this session");
+ MessageBox(getMainHandle(), message, "RFB Player", MB_OK | MB_ICONERROR);
+ sessionTerminateThread *terminate = new sessionTerminateThread(this);
+ terminate->start();
+ return;
+ }
+ }
+}
+
+long ChoosePixelFormatDialog::pfIndex = DEFAULT_PF_INDEX;
+bool ChoosePixelFormatDialog::bigEndian = false;
+
+void RfbPlayer::serverInit() {
+ RfbProto::serverInit();
+
+ // Save the image data start time
+ imageDataStartTime = is->getTimeOffset();
+
+ // Resize the backing buffer
+ buffer->setSize(cp.width, cp.height);
+
+ // Check on the true colour mode
+ if (!(cp.pf()).trueColour)
+ throw rdr::Exception("This version plays only true color session!");
+
+ // Set the session pixel format
+ if (options.askPixelFormat) {
+ ChoosePixelFormatDialog choosePixelFormatDialog(&supportedPF);
+ if (choosePixelFormatDialog.showDialog(getMainHandle())) {
+ long pixelFormatIndex = choosePixelFormatDialog.getPFIndex();
+ if (pixelFormatIndex < 0) {
+ options.autoDetectPF = true;
+ options.setPF((PixelFormat *)&cp.pf());
+ } else {
+ options.autoDetectPF = false;
+ options.setPF(&supportedPF[pixelFormatIndex]->PF);
+ options.pixelFormat.bigEndian = choosePixelFormatDialog.isBigEndian();
+ }
+ } else {
+ is->pausePlayback();
+ throw rdr::Exception("[TERMINATE]");
+ }
+ } else {
+ if (!options.commandLineParam) {
+ if (options.autoDetectPF) {
+ options.setPF((PixelFormat *)&cp.pf());
+ } else {
+ options.setPF(&supportedPF[options.pixelFormatIndex]->PF);
+ options.pixelFormat.bigEndian = options.bigEndianFlag;
+ }
+ } else if (options.autoDetectPF) {
+ options.setPF((PixelFormat *)&cp.pf());
+ }
+ }
+ cp.setPF(options.pixelFormat);
+ buffer->setPF(options.pixelFormat);
+
+ // If the window is not maximised then resize it
+ if (!(GetWindowLong(getMainHandle(), GWL_STYLE) & WS_MAXIMIZE))
+ setFrameSize(cp.width, cp.height);
+
+ // Set the window title and show it
+ setTitle(cp.name());
+
+ // Calculate the full session time and update posTrackBar control in toolbar
+ sessionTimeMs = calculateSessionTime(fileName);
+ tb.init(sessionTimeMs);
+ tb.updatePos(getTimeOffset());
+
+ setPaused(!options.autoPlay);
+ // Restore the parameters from registry,
+ // which was replaced by command-line parameters.
+ if (options.commandLineParam) {
+ options.readFromRegistry();
+ options.commandLineParam = false;
+ }
+}
+
+void RfbPlayer::setColourMapEntries(int first, int count, U16* rgbs) {
+ vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+ throw rdr::Exception("Can't handle SetColourMapEntries message");
+/* int i;
+ for (i=0;i<count;i++) {
+ buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+ }
+ // *** change to 0, 256?
+ refreshWindowPalette(first, count);
+ palette_changed = true;
+ InvalidateRect(getFrameHandle(), 0, FALSE);*/
+}
+
+void RfbPlayer::bell() {
+ if (options.acceptBell)
+ MessageBeep(-1);
+}
+
+void RfbPlayer::serverCutText(const char* str, int len) {
+ if (cutText != NULL)
+ delete [] cutText;
+ cutText = new char[len + 1];
+ memcpy(cutText, str, len);
+ cutText[len] = '\0';
+}
+
+void RfbPlayer::frameBufferUpdateEnd() {
+};
+
+void RfbPlayer::beginRect(const Rect& r, unsigned int encoding) {
+ currentEncoding = encoding;
+}
+
+void RfbPlayer::endRect(const Rect& r, unsigned int encoding) {
+}
+
+
+void RfbPlayer::fillRect(const Rect& r, Pixel pix) {
+ buffer->fillRect(r, pix);
+ invalidateBufferRect(r);
+}
+
+void RfbPlayer::imageRect(const Rect& r, void* pixels) {
+ buffer->imageRect(r, pixels);
+ invalidateBufferRect(r);
+}
+
+void RfbPlayer::copyRect(const Rect& r, int srcX, int srcY) {
+ buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+ invalidateBufferRect(r);
+}
+
+bool RfbPlayer::invalidateBufferRect(const Rect& crect) {
+ Rect rect = bufferToClient(crect);
+ if (rect.intersect(client_size).is_empty()) return false;
+ RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+ InvalidateRect(getFrameHandle(), &invalid, FALSE);
+ return true;
+}
+
+bool RfbPlayer::waitWhilePaused() {
+ bool result = false;
+ while(isPaused() && !isSeeking()) {
+ Sleep(20);
+ result = true;
+ }
+ return result;
+}
+
+long RfbPlayer::calculateSessionTime(char *filename) {
+ FbsInputStream sessionFile(filename);
+ sessionFile.setTimeOffset(100000000);
+ try {
+ while (TRUE) {
+ sessionFile.skip(1024);
+ }
+ } catch (rdr::Exception e) {
+ if (strcmp(e.str(), "[End Of File]") == 0) {
+ return sessionFile.getTimeOffset();
+ } else {
+ MessageBox(getMainHandle(), e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void RfbPlayer::init() {
+ if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+ else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+}
+
+void RfbPlayer::closeSessionFile() {
+ DWORD dwStyle;
+ RECT r;
+
+ // Uncheck all toolbar buttons
+ if (tb.getHandle()) {
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_PAUSE, false);
+ tb.checkButton(ID_STOP, false);
+ }
+
+ // Stop playback and update the player state
+ disableTBandMenuItems();
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ delete [] fileName;
+ fileName = 0;
+ }
+ blankBuffer();
+ setTitle("None");
+ options.playbackSpeed = 1.0;
+ tb.init(0);
+
+ // Change the player window size and frame size to default
+ if ((dwStyle = GetWindowLong(getMainHandle(), GWL_STYLE)) & WS_MAXIMIZE) {
+ dwStyle &= ~WS_MAXIMIZE;
+ SetWindowLong(getMainHandle(), GWL_STYLE, dwStyle);
+ }
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+ SetWindowPos(getMainHandle(), 0, x, y,
+ DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT,
+ SWP_NOZORDER | SWP_FRAMECHANGED);
+ buffer->setSize(32, 32);
+ calculateScrollBars();
+
+ // Update the cached sizing information and repaint the frame window
+ GetWindowRect(getFrameHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+ InvalidateRect(getFrameHandle(), 0, TRUE);
+ UpdateWindow(getFrameHandle());
+}
+
+void RfbPlayer::openSessionFile(char *_fileName) {
+ fileName = strDup(_fileName);
+
+ // Close the previous reading thread
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ }
+ blankBuffer();
+ newSession(fileName);
+ setSpeed(options.playbackSpeed);
+ rfbReader = new rfbSessionReader(this);
+ rfbReader->start();
+ tb.setTimePos(0);
+ enableTBandMenuItems();
+}
+
+void RfbPlayer::setPaused(bool paused) {
+ if (paused) {
+ is->pausePlayback();
+ tb.checkButton(ID_PAUSE, true);
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_STOP, false);
+ } else {
+ if (is) is->resumePlayback();
+ tb.checkButton(ID_PLAY, true);
+ tb.checkButton(ID_STOP, false);
+ tb.checkButton(ID_PAUSE, false);
+ }
+ tb.enableButton(ID_PAUSE, true);
+ EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::stopPlayback() {
+ stopped = true;
+ setPos(0);
+ if (is) {
+ is->pausePlayback();
+ is->interruptFrameDelay();
+ }
+ tb.checkButton(ID_STOP, true);
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_PAUSE, false);
+ tb.enableButton(ID_PAUSE, false);
+ tb.setTimePos(0);
+ EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::setSpeed(double speed) {
+ if (speed > 0) {
+ char speedStr[20] = "\0";
+ double newSpeed = min(speed, MAX_SPEED);
+ is->setSpeed(newSpeed);
+ options.playbackSpeed = newSpeed;
+ SendMessage(tb.getSpeedUpDownHwnd(), UDM_SETPOS,
+ 0, MAKELONG((short)(newSpeed / 0.5), 0));
+ sprintf(speedStr, "%.2f", newSpeed);
+ SetWindowText(tb.getSpeedEditHwnd(), speedStr);
+ }
+}
+
+double RfbPlayer::getSpeed() {
+ return is->getSpeed();
+}
+
+void RfbPlayer::setPos(long pos) {
+ is->setTimeOffset(max(pos, imageDataStartTime));
+}
+
+long RfbPlayer::getSeekOffset() {
+ return is->getSeekOffset();
+}
+
+bool RfbPlayer::isSeeking() {
+ if (is) return is->isSeeking();
+ else return false;
+}
+
+bool RfbPlayer::isSeekMode() {
+ return seekMode;
+}
+
+bool RfbPlayer::isPaused() {
+ return is->isPaused();
+}
+
+long RfbPlayer::getTimeOffset() {
+ return max(is->getTimeOffset(), is->getSeekOffset());
+}
+
+void RfbPlayer::skipHandshaking() {
+ int skipBytes = 12 + 4 + 24 + strlen(cp.name());
+ is->skip(skipBytes);
+ state_ = RFBSTATE_NORMAL;
+}
+
+void programInfo() {
+ win32::FileVersionInfo inf;
+ _tprintf(_T("%s - %s, Version %s\n"),
+ inf.getVerString(_T("ProductName")),
+ inf.getVerString(_T("FileDescription")),
+ inf.getVerString(_T("FileVersion")));
+ printf("%s\n", buildTime);
+ _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
+}
+
+void programUsage() {
+ InfoDialog usageDialog(usage_msg);
+ usageDialog.showDialog();
+}
+
+char *fileName = 0;
+
+// playerOptions is the player options with default parameters values,
+// it is used only for run the player with command-line parameters
+PlayerOptions playerOptions;
+bool print_usage = false;
+bool print_upf_list = false;
+
+bool processParams(int argc, char* argv[]) {
+ playerOptions.commandLineParam = true;
+ for (int i = 1; i < argc; i++) {
+ if ((strcasecmp(argv[i], "-help") == 0) ||
+ (strcasecmp(argv[i], "--help") == 0) ||
+ (strcasecmp(argv[i], "/help") == 0) ||
+ (strcasecmp(argv[i], "-h") == 0) ||
+ (strcasecmp(argv[i], "/h") == 0) ||
+ (strcasecmp(argv[i], "/?") == 0) ||
+ (strcasecmp(argv[i], "-?") == 0)) {
+ print_usage = true;
+ return true;
+ }
+
+ if ((strcasecmp(argv[i], "-pf") == 0) ||
+ (strcasecmp(argv[i], "/pf") == 0) && (i < argc-1)) {
+ char *pf = argv[++i];
+ char rgb_order[4] = "\0";
+ int order = RGB_ORDER;
+ int r = -1, g = -1, b = -1;
+ bool big_endian = false;
+ if (strlen(pf) < 6) return false;
+ while (strlen(pf)) {
+ if ((pf[0] == 'r') || (pf[0] == 'R')) {
+ if (r >=0 ) return false;
+ r = atoi(++pf);
+ strcat(rgb_order, "r");
+ continue;
+ }
+ if ((pf[0] == 'g') || (pf[0] == 'G')) {
+ if (g >=0 ) return false;
+ g = atoi(++pf);
+ strcat(rgb_order, "g");
+ continue;
+ }
+ if (((pf[0] == 'b') || (pf[0] == 'B')) &&
+ (pf[1] != 'e') && (pf[1] != 'E')) {
+ if (b >=0 ) return false;
+ b = atoi(++pf);
+ strcat(rgb_order, "b");
+ continue;
+ }
+ if ((pf[0] == 'l') || (pf[0] == 'L') ||
+ (pf[0] == 'b') || (pf[0] == 'B')) {
+ if (strcasecmp(pf, "le") == 0) break;
+ if (strcasecmp(pf, "be") == 0) { big_endian = true; break;}
+ return false;
+ }
+ pf++;
+ }
+ if ((r < 0) || (g < 0) || (b < 0) || (r + g + b > 32)) return false;
+ if (strcasecmp(rgb_order, "rgb") == 0) { order = RGB_ORDER; }
+ else if (strcasecmp(rgb_order, "rbg") == 0) { order = RBG_ORDER; }
+ else if (strcasecmp(rgb_order, "grb") == 0) { order = GRB_ORDER; }
+ else if (strcasecmp(rgb_order, "gbr") == 0) { order = GBR_ORDER; }
+ else if (strcasecmp(rgb_order, "bgr") == 0) { order = BGR_ORDER; }
+ else if (strcasecmp(rgb_order, "brg") == 0) { order = BRG_ORDER; }
+ else return false;
+ playerOptions.autoDetectPF = false;
+ playerOptions.setPF(order, r, g, b, big_endian);
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-upf") == 0) ||
+ (strcasecmp(argv[i], "/upf") == 0) && (i < argc-1)) {
+ if ((i == argc - 1) || (argv[++i][0] == '-')) {
+ print_upf_list = true;
+ return true;
+ }
+ PixelFormatList userPfList;
+ userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ int index = userPfList.getIndexByPFName(argv[i]);
+ if (index > 0) {
+ playerOptions.autoDetectPF = false;
+ playerOptions.setPF(&userPfList[index]->PF);
+ } else {
+ return false;
+ }
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-speed") == 0) ||
+ (strcasecmp(argv[i], "/speed") == 0) && (i < argc-1)) {
+ double playbackSpeed = atof(argv[++i]);
+ if (playbackSpeed <= 0) {
+ return false;
+ }
+ playerOptions.playbackSpeed = playbackSpeed;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-pos") == 0) ||
+ (strcasecmp(argv[i], "/pos") == 0) && (i < argc-1)) {
+ long initTime = atol(argv[++i]);
+ if (initTime <= 0)
+ return false;
+ playerOptions.initTime = initTime;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-autoplay") == 0) ||
+ (strcasecmp(argv[i], "/autoplay") == 0) && (i < argc-1)) {
+ playerOptions.autoPlay = true;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-loop") == 0) ||
+ (strcasecmp(argv[i], "/loop") == 0) && (i < argc-1)) {
+ playerOptions.loopPlayback = true;
+ continue;
+ }
+
+ if (i != argc - 1)
+ return false;
+ }
+
+ fileName = strDup(argv[argc-1]);
+ if (fileName[0] == '-') return false;
+ else return true;
+}
+
+//
+// -=- WinMain
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+
+ // - Process the command-line
+
+ int argc = __argc;
+ char** argv = __argv;
+ if ((argc > 1) && (!processParams(argc, argv))) {
+ MessageBox(0, wrong_cmd_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return 0;
+ }
+
+ if (print_usage) {
+ programUsage();
+ return 0;
+ }
+ // Show the user defined pixel formats if required
+ if (print_upf_list) {
+ int list_size = 256;
+ char *upf_list = new char[list_size];
+ PixelFormatList userPfList;
+ userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ strcpy(upf_list, "The list of the user defined pixel formats:\r\n");
+ for (int i = userPfList.getDefaultPFCount(); i < userPfList.count(); i++) {
+ if ((list_size - strlen(upf_list) - 1) <
+ (strlen(userPfList[i]->format_name) + 2)) {
+ char *tmpStr = new char[list_size =
+ list_size + strlen(userPfList[i]->format_name) + 2];
+ strcpy(tmpStr, upf_list);
+ delete [] upf_list;
+ upf_list = new char[list_size];
+ strcpy(upf_list, tmpStr);
+ delete [] tmpStr;
+ }
+ strcat(upf_list, userPfList[i]->format_name);
+ strcat(upf_list, "\r\n");
+ }
+ InfoDialog upfInfoDialog(upf_list);
+ upfInfoDialog.showDialog();
+ delete [] upf_list;
+ return 0;
+ }
+
+ // Create the player
+ RfbPlayer *player = NULL;
+ try {
+ player = new RfbPlayer(fileName, &playerOptions);
+ } catch (rdr::Exception e) {
+ MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ delete player;
+ return 0;
+ }
+
+ // Run the player
+ HACCEL hAccel = LoadAccelerators(inst, MAKEINTRESOURCE(IDR_ACCELERATOR));
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ if(!TranslateAccelerator(player->getMainHandle(), hAccel, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ // Destroy the player
+ try{
+ if (player) delete player;
+ } catch (rdr::Exception e) {
+ MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+
+ return 0;
+};