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/ChoosePixelFormatDialog.h b/win/rfbplayer/ChoosePixelFormatDialog.h
new file mode 100644
index 0000000..ada820b
--- /dev/null
+++ b/win/rfbplayer/ChoosePixelFormatDialog.h
@@ -0,0 +1,59 @@
+/* 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.
+ */
+
+// -=- ChoosePixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class ChoosePixelFormatDialog : public rfb::win32::Dialog {
+public:
+  ChoosePixelFormatDialog(PixelFormatList *_supportedPF) 
+  : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), combo(0) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_PIXELFORMAT), parent);
+  }
+  const long getPFIndex() const {return pfIndex;}
+  bool isBigEndian() {return isItemChecked(IDC_BIG_ENDIAN);}
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+    SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+    for (int i = 0; i < supportedPF->count(); i++) {
+      SendMessage(combo, CB_ADDSTRING, 
+        0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+    }
+    SendMessage(combo, CB_SETCURSEL, pfIndex + 1, 0);
+    setItemChecked(IDC_BIG_ENDIAN, bigEndian);
+  }
+  virtual bool onOk() {
+    pfIndex = SendMessage(combo, CB_GETCURSEL, 0, 0) - 1;
+    bigEndian = isItemChecked(IDC_BIG_ENDIAN);
+    return true;
+  }
+  virtual bool onCancel() {
+    return false;
+  }
+  static long pfIndex;
+  static bool bigEndian;
+  PixelFormatList *supportedPF;
+  HWND combo;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/EditPixelFormatDialog.h b/win/rfbplayer/EditPixelFormatDialog.h
new file mode 100644
index 0000000..0765285
--- /dev/null
+++ b/win/rfbplayer/EditPixelFormatDialog.h
@@ -0,0 +1,104 @@
+/* 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.
+ */
+
+// -=- EditPixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+#define MAX_STR_LEN 256
+
+class EditPixelFormatDialog : public rfb::win32::Dialog {
+public:
+  EditPixelFormatDialog(PixelFormatList *_supportedPF, char *_format_name,
+                        PixelFormat *_pf) 
+  : Dialog(GetModuleHandle(0)), format_name(_format_name), 
+  supportedPF(_supportedPF), pf(_pf) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_UPF_EDIT), parent);
+  }
+
+protected:
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    HWND bppCombo = GetDlgItem(handle, IDC_BPP_COMBO);
+    SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("8"));
+    SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("16"));
+    SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("32"));
+    SendMessage(bppCombo, CB_SETCURSEL, min(2, (pf->bpp - 8) / 8), 0);
+
+    HWND bigendianCombo = GetDlgItem(handle, IDC_BIGENDIAN_COMBO);
+    SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("No"));
+    SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Yes"));
+    SendMessage(bigendianCombo, CB_SETCURSEL, pf->bigEndian, 0);
+
+    setItemString(IDC_NAME_EDIT, format_name);
+    setItemInt(IDC_DEPTH_EDIT, pf->depth);
+    setItemInt(IDC_REDMAX_EDIT, pf->redMax);
+    setItemInt(IDC_GREENMAX_EDIT, pf->greenMax);
+    setItemInt(IDC_BLUEMAX_EDIT, pf->blueMax);
+    setItemInt(IDC_REDSHIFT_EDIT, pf->redShift);
+    setItemInt(IDC_GREENSHIFT_EDIT, pf->greenShift);
+    setItemInt(IDC_BLUESHIFT_EDIT, pf->blueShift);
+  }
+  virtual bool onOk() {
+    // Check for the errors
+    char err_msg[256] = "\0";
+    if (((getItemString(IDC_NAME_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_DEPTH_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_REDMAX_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_GREENMAX_EDIT))[0] == '\0') ||
+        ((getItemString(IDC_BLUEMAX_EDIT))[0] == '\0') ||
+        ((getItemString(IDC_REDSHIFT_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_GREENSHIFT_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_BLUESHIFT_EDIT))[0] == '\0')) {
+      strcpy(err_msg, "Please fill the all fields in the dialog.");
+    }
+    int newIndex = supportedPF->getIndexByPFName(getItemString(IDC_NAME_EDIT));
+    if ((supportedPF->getIndexByPFName(format_name) != newIndex) && 
+        (newIndex != -1)) {
+      strcpy(err_msg, "The pixel format with that name is already exist.");
+    }
+    if (getItemInt(IDC_DEPTH_EDIT) <= 0) {
+      strcpy(err_msg, "The pixel depth must be larger than 0.");
+    }
+    if (err_msg[0] != 0) {
+      MessageBox(handle, err_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+      return false;
+    }
+    // Fill the pixel format structure
+    strCopy(format_name, getItemString(IDC_NAME_EDIT), MAX_STR_LEN);
+    pf->bpp = getItemInt(IDC_BPP_COMBO);
+    pf->depth = getItemInt(IDC_DEPTH_EDIT);
+    pf->bigEndian = (SendMessage(GetDlgItem(handle, IDC_BIGENDIAN_COMBO), 
+      CB_GETCURSEL, 0, 0)) ? true : false;
+    pf->trueColour = true;
+    pf->redMax = getItemInt(IDC_REDMAX_EDIT);
+    pf->greenMax = getItemInt(IDC_GREENMAX_EDIT);
+    pf->blueMax = getItemInt(IDC_BLUEMAX_EDIT);
+    pf->redShift = getItemInt(IDC_REDSHIFT_EDIT);
+    pf->greenShift = getItemInt(IDC_GREENSHIFT_EDIT);
+    pf->blueShift = getItemInt(IDC_BLUESHIFT_EDIT);
+    return true;
+  }
+
+  char *format_name;
+  PixelFormatList *supportedPF;
+  PixelFormat *pf;
+};
diff --git a/win/rfbplayer/FbsInputStream.cxx b/win/rfbplayer/FbsInputStream.cxx
new file mode 100644
index 0000000..6381a16
--- /dev/null
+++ b/win/rfbplayer/FbsInputStream.cxx
@@ -0,0 +1,251 @@
+/* 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.
+ */
+
+// -=- FbsInputStream class
+
+#include <windows.h>
+
+#include <rfb/Exception.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+FbsInputStream::FbsInputStream(char* FileName) {
+  bufferSize = 0;
+  ptr = end = start = NULL;
+
+  timeOffset = 0;
+  seekOffset = -1;
+  startTime  = GetTickCount();
+
+  playbackSpeed = 1.0;
+  seekBackwards = false;
+  paused        = false;
+
+  interruptDelay = false;
+
+  fbsFile = fopen(FileName, "rb");
+  if (fbsFile == NULL) {
+    char *msg = new char[12 + sizeof(FileName)];
+    strcpy(msg, "Can't open ");
+    strcat(msg, FileName);
+    throw rfb::Exception(msg);
+  }
+
+  U8 b[12];
+  readNByte(b, 12);
+
+  if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
+      b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
+	    b[8]  < '0' || b[8]  > '9' || b[9]  < '0' || b[9] > '9'  ||
+	    b[10] < '0' || b[10] > '9' || b[11] != '\n') {
+    throw rfb::Exception("Incorrect protocol version");
+  }
+}
+
+FbsInputStream::~FbsInputStream() {
+  if (start != NULL) 
+    delete [] start;
+  ptr = end = start = NULL;
+  fclose(fbsFile);
+}
+
+int FbsInputStream::pos() {
+  return ptr - start;
+}
+
+//
+// Close FbsInputStream and free data buffer
+//
+
+void FbsInputStream::close() {
+  fclose(fbsFile);
+
+  startTime = -1;
+  timeOffset = 0;
+  seekOffset = -1;
+  seekBackwards = false;
+  paused = false;
+  playbackSpeed = 1.0;
+
+  if (start != NULL)
+    delete [] start;
+  ptr = end = start = NULL;
+  bufferSize = 0;
+}
+
+//
+// Fill data buffer from the session file (InStream::overrun() override)
+//
+
+int FbsInputStream::overrun(int itemSize, int nItems, bool wait=true) {
+  // Just wait unless we are performing playback OR seeking.
+  waitWhilePaused(); 
+  
+  // Perform backwardSeek (throws the special exception)
+  if (seekBackwards) {
+    throw rfb::Exception("[REWIND]");
+  }
+
+  // Save a tail of data
+  U8 *tmp;
+  int n = end - ptr;
+  if (n) {
+    tmp = new U8[n];
+    memmove(tmp, ptr, n);
+  }
+
+  bufferSize = (int)readUnsigned32();
+  if (bufferSize >= 0) {
+    if (start != NULL)
+      delete [] start;
+    int realSize = (bufferSize + 3) & 0xFFFFFFFC; // padding to multiple of 32-bits
+    ptr = start = new U8[realSize + n];
+    end = ptr + bufferSize + n;
+    if (n) {
+      memmove(start, tmp, n);
+      delete [] tmp;
+    }
+    readNByte(start + n, realSize);
+    timeOffset = (long)(readUnsigned32() / playbackSpeed);
+
+    if (itemSize * nItems > bufferSize)
+      nItems = bufferSize / itemSize;
+  }
+
+  if (bufferSize < 0 || timeOffset < 0) {
+    if (start != NULL)
+      delete [] start;
+    ptr = end = start = NULL;
+    bufferSize = 0;
+    return 0;
+  }
+
+  if (seekOffset >= 0) {
+    if (timeOffset >= seekOffset) {
+      startTime = GetTickCount() - seekOffset;
+      seekOffset = -1;
+    } else {
+	    return nItems;
+    }
+  }
+
+  while (!interruptDelay) {
+    long timeDiff = startTime + timeOffset - GetTickCount();
+    if (timeDiff <= 0) {
+	    break;
+    }
+    Sleep(min(20, timeDiff));
+    waitWhilePaused();
+  }
+  interruptDelay = false;
+
+  return nItems;
+}
+
+int FbsInputStream::readUnsigned32() {
+  U8 buf[4];
+  if (!readNByte(buf, 4))
+    return -1;
+
+  return ((long)(buf[0] & 0xFF) << 24 |
+    	    (buf[1] & 0xFF) << 16 |
+	        (buf[2] & 0xFF) << 8  |
+	        (buf[3] & 0xFF)); 
+}
+
+//
+// Read n-bytes from the session file
+//
+
+bool FbsInputStream::readNByte(U8 b[], int n) {
+  int off = 0;
+  
+  while (off != n) {
+    int count = fread(b, 1, n - off, fbsFile);
+    if (count < n) {
+      if (ferror(fbsFile)) 
+        throw rfb::Exception("Read error from session file");
+      if (feof(fbsFile))
+        throw rfb::Exception("[End Of File]");
+    }
+    off += count;
+  }
+  return true;
+}
+
+void FbsInputStream::waitWhilePaused() {
+  while (paused && !isSeeking()) {
+    // A small delay helps to decrease the cpu usage
+    Sleep(20);
+  }
+}
+
+void FbsInputStream::interruptFrameDelay() {
+  interruptDelay = true;
+}
+
+//
+// Methods providing additional functionality.
+//
+
+long FbsInputStream::getTimeOffset() {
+  //long off = max(seekOffset, timeOffset);
+  return (long)(timeOffset * playbackSpeed);
+}
+
+void FbsInputStream::setTimeOffset(long pos) {
+  seekOffset = (long)(pos / playbackSpeed);
+  if (seekOffset < timeOffset) {
+    seekBackwards = true;
+  }
+}
+
+void FbsInputStream::setSpeed(double newSpeed) {
+  long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
+  startTime += timeOffset - newOffset;
+  timeOffset = newOffset;
+  if (isSeeking()) {
+    seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
+  }
+  playbackSpeed = newSpeed;
+}
+
+double FbsInputStream::getSpeed() {
+  return playbackSpeed;
+}
+
+bool FbsInputStream::isSeeking() {
+  return (seekOffset >= 0);
+}
+
+long FbsInputStream::getSeekOffset() {
+  return (long)(seekOffset * playbackSpeed);
+}
+
+bool FbsInputStream::isPaused() {
+  return paused;
+}
+
+void FbsInputStream::pausePlayback() {
+  paused = true;
+}
+
+void FbsInputStream::resumePlayback() {
+  paused = false;
+  startTime = GetTickCount() - timeOffset;
+}
diff --git a/win/rfbplayer/FbsInputStream.h b/win/rfbplayer/FbsInputStream.h
new file mode 100644
index 0000000..9649273
--- /dev/null
+++ b/win/rfbplayer/FbsInputStream.h
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+// -=- FbsInputStream.h
+
+#include <rdr/InStream.h>
+
+using namespace rdr;
+
+class FbsInputStream : public InStream {
+  public:
+    FbsInputStream(char *FileName);
+    ~FbsInputStream();
+
+    // Methods are used to contol the Rfb Stream
+    long getTimeOffset();
+    void setTimeOffset(long pos);
+    double getSpeed();
+    void setSpeed(double newSpeed);
+    bool isSeeking();
+    long getSeekOffset();
+    bool isPaused();
+    void pausePlayback();
+    void resumePlayback();
+    void interruptFrameDelay();
+    void close();
+    int  pos();
+
+  private:
+    U8 *start;
+    int bufferSize;
+    long startTime;
+    long timeOffset;
+    long seekOffset;
+    double playbackSpeed;
+    bool seekBackwards;
+    bool paused;
+    bool interruptDelay;
+
+    FILE  *fbsFile;
+
+    // overrun() - overrides InStream::overrun().
+    // It is implemented to fill the data buffer from the session file.
+    // It ensures there are at least itemSize bytes of buffer data.  Returns
+    // the number of items in the buffer (up to a maximum of nItems).  itemSize
+    // is supposed to be "small" (a few bytes).
+
+    int overrun(int itemSize, int nItems, bool wait);
+
+    int readUnsigned32();
+    bool readNByte(U8 *b, int n);
+    void waitWhilePaused();
+};
diff --git a/win/rfbplayer/GotoPosDialog.h b/win/rfbplayer/GotoPosDialog.h
new file mode 100644
index 0000000..ddbbe53
--- /dev/null
+++ b/win/rfbplayer/GotoPosDialog.h
@@ -0,0 +1,44 @@
+/* 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.
+ */
+
+// -=- GotoPosDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class GotoPosDialog : public rfb::win32::Dialog {
+public:
+  GotoPosDialog() : Dialog(GetModuleHandle(0)) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_GOTO), parent);
+  }
+  const long getPos() const {return pos;}
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    setItemString(IDC_GOTO_EDIT, rfb::TStr("0"));
+  }
+  virtual bool onOk() {
+    pos = atol(rfb::CStr(getItemString(IDC_GOTO_EDIT)));
+    return true;
+  }
+
+  long pos;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/InfoDialog.h b/win/rfbplayer/InfoDialog.h
new file mode 100644
index 0000000..bbe9b26
--- /dev/null
+++ b/win/rfbplayer/InfoDialog.h
@@ -0,0 +1,41 @@
+/* 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.
+ */
+
+// -=- InfoDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class InfoDialog : public rfb::win32::Dialog {
+public:
+  InfoDialog(char *_info_message, char *_title = "Information") 
+  : Dialog(GetModuleHandle(0)), info_message(_info_message), title(_title) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent = 0) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_INFO), parent);
+  }
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    SetWindowText(handle, title);
+    setItemString(IDC_INFO_EDIT, info_message);
+  }
+  char *info_message;
+  char *title;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/OptionsDialog.h b/win/rfbplayer/OptionsDialog.h
new file mode 100644
index 0000000..8c3a87d
--- /dev/null
+++ b/win/rfbplayer/OptionsDialog.h
@@ -0,0 +1,112 @@
+/* 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.
+ */
+
+// -=- OptionsDialog.h
+
+#include <rfbplayer/PlayerOptions.h>
+#include <rfbplayer/UserPixelFormatsDialog.h>
+
+class OptionsDialog : public rfb::win32::Dialog {
+public:
+  OptionsDialog(PlayerOptions *_options, PixelFormatList *_supportedPF) 
+  : Dialog(GetModuleHandle(0)), options(_options), combo(0),
+  supportedPF(_supportedPF) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_OPTIONS), parent);
+  }
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+    SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+    for (int i = 0; i < supportedPF->count(); i++) {
+      SendMessage(combo, CB_ADDSTRING, 
+        0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+    }
+    SendMessage(combo, CB_SETCURSEL, options->pixelFormatIndex + 1, 0);
+    setItemChecked(IDC_ACCEPT_BELL, options->acceptBell);
+    setItemChecked(IDC_ACCEPT_CUT_TEXT, options->acceptCutText);
+    setItemChecked(IDC_AUTOPLAY, options->autoPlay);
+    setItemChecked(IDC_BIG_ENDIAN, options->bigEndianFlag);
+    if (options->askPixelFormat) {
+      setItemChecked(IDC_ASK_PF, true);
+      enableItem(IDC_PIXELFORMAT, false);
+      enableItem(IDC_BIG_ENDIAN, false);
+    }
+  }
+  virtual bool onOk() {
+    options->askPixelFormat = isItemChecked(IDC_ASK_PF);
+    options->acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+    options->acceptCutText = isItemChecked(IDC_ACCEPT_CUT_TEXT);
+    options->autoPlay = isItemChecked(IDC_AUTOPLAY);
+    options->bigEndianFlag = isItemChecked(IDC_BIG_ENDIAN);
+    if (!options->askPixelFormat) {
+      options->pixelFormatIndex = int(SendMessage(combo, CB_GETCURSEL, 0, 0)) - 1;
+      if (options->pixelFormatIndex < 0) {
+        options->autoDetectPF = true;
+      } else {
+        options->setPF(&((*supportedPF)[options->pixelFormatIndex])->PF);
+        options->pixelFormat.bigEndian = options->bigEndianFlag;
+        options->autoDetectPF = false;
+      }
+    }
+    options->writeToRegistry();
+    return true;
+  }
+  virtual bool onCommand(int item, int cmd) { 
+    if (item == IDC_ASK_PF) {
+      enableItem(IDC_PIXELFORMAT, !isItemChecked(IDC_ASK_PF));
+      enableItem(IDC_BIG_ENDIAN, !isItemChecked(IDC_ASK_PF));
+    }
+    if (item == IDC_DEFAULT) {
+      SendMessage(combo, CB_SETCURSEL, DEFAULT_PF_INDEX + 1, 0);
+      enableItem(IDC_PIXELFORMAT, !DEFAULT_ASK_PF);
+      enableItem(IDC_BIG_ENDIAN, !DEFAULT_ASK_PF);
+      setItemChecked(IDC_ASK_PF, DEFAULT_ASK_PF);
+      setItemChecked(IDC_ACCEPT_BELL, DEFAULT_ACCEPT_BELL);
+      setItemChecked(IDC_ACCEPT_CUT_TEXT, DEFAULT_ACCEPT_CUT_TEXT);
+      setItemChecked(IDC_AUTOPLAY, DEFAULT_AUTOPLAY);
+      setItemChecked(IDC_BIG_ENDIAN, DEFAULT_BIG_ENDIAN);
+    }
+    if (item == IDC_EDIT_UPF) {
+      UserPixelFormatsDialog UpfListDialog(supportedPF);
+      if (UpfListDialog.showDialog(handle)) {
+        int index = SendMessage(combo, CB_GETCURSEL, 0, 0);
+        SendMessage(combo, CB_RESETCONTENT, 0, 0);
+        SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+        for (int i = 0; i < supportedPF->count(); i++) {
+          SendMessage(combo, CB_ADDSTRING, 
+            0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+        }
+        if ( index > (SendMessage(combo, CB_GETCOUNT, 0, 0) - 1)) {
+          index = SendMessage(combo, CB_GETCOUNT, 0, 0) - 1;
+        }
+        SendMessage(combo, CB_SETCURSEL, index, 0);
+        options->pixelFormatIndex = index - 1;
+      }
+    }
+    return false;
+  }
+
+  HWND combo;
+  PlayerOptions *options;
+  PixelFormatList *supportedPF;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.cxx b/win/rfbplayer/PixelFormatList.cxx
new file mode 100644
index 0000000..25996f6
--- /dev/null
+++ b/win/rfbplayer/PixelFormatList.cxx
@@ -0,0 +1,159 @@
+/* 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.
+ */
+
+// -=- PixelFormatList class
+
+#include <rfbplayer/PixelFormatList.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+PixelFormatList::PixelFormatList() {
+  PixelFormatListElement PFElem;
+  
+  // -=- Add the default pixel formats to list
+  // PF_BGR233
+  PFElem.setName("8-bits depth (BGR233)");
+  PFElem.setPF(&PixelFormat(8,8,0,1,7,7,3,0,3,6));
+  PFList.push_back(PFElem);
+  // PF_RGB555
+  PFElem.setName("15-bits depth (RGB555)");
+  PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,10,5,0));
+  PFList.push_back(PFElem);
+  // PF_BGR555
+  PFElem.setName("15-bits depth (BGR555)");
+  PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,0,5,10));
+  PFList.push_back(PFElem);
+  // PF_RGB565
+  PFElem.setName("16-bits depth (RGB565)");
+  PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,11,5,0));
+  PFList.push_back(PFElem);
+  // PF_BGR565
+  PFElem.setName("16-bits depth (BGR565)");
+  PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,0,5,11));
+  PFList.push_back(PFElem);
+  // PF_RGB888
+  PFElem.setName("24-bits depth (RGB888)");
+  PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,16,8,0));
+  PFList.push_back(PFElem);
+  // PF_BGR888
+  PFElem.setName("24-bits depth (BGR888)");
+  PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,0,8,16));
+  PFList.push_back(PFElem);
+
+  PF_DEFAULT_COUNT = PFList.size();
+}
+
+PixelFormatListElement *PixelFormatList::operator[](int index) {
+  return &(*getIterator(index));
+}
+
+void PixelFormatList::add(char *format_name, PixelFormat PF) {
+  PixelFormatListElement PFElem;
+  PFElem.setName(format_name);
+  PFElem.setPF(&PF);
+  PFList.push_back(PFElem);
+}
+
+void PixelFormatList::insert(int index, char *format_name, PixelFormat PF) {
+  if (isDefaultPF(index)) 
+    rdr::Exception("PixelFormatList:can't insert to the default pixel format place");
+
+  PixelFormatListElement PFElem;
+  PFElem.setName(format_name);
+  PFElem.setPF(&PF);
+  PFList.insert(getIterator(index), PFElem);
+}
+
+void PixelFormatList::remove(int index) {
+  if (isDefaultPF(index)) 
+    rdr::Exception("PixelFormatList:can't remove the default pixel format");
+  PFList.erase(getIterator(index));
+}
+
+list <PixelFormatListElement>::iterator PixelFormatList::getIterator(int index) {
+  if ((index >= PFList.size()) || (index < 0))
+    rdr::Exception("PixelFormatList:out of range");
+
+  int i = 0;
+  list <PixelFormatListElement>::iterator iter;
+  for (iter = PFList.begin(); iter != PFList.end(); iter++) {
+    if (i++ == index) break;
+  }
+  return iter;
+}
+
+bool PixelFormatList::isDefaultPF(int index) {
+  if (index < PF_DEFAULT_COUNT) return true;
+  return false;
+}
+
+void PixelFormatList::readUserDefinedPF(HKEY root, const char *keypath) {
+  RegKey regKey;
+  regKey.createKey(root, keypath);
+  int count = regKey.getInt(_T("PixelFormatCount"), 0);
+  if (count > 0) {
+    // Erase all user defined pixel formats
+    int upf_count = getUserPFCount();
+    if (upf_count > 0) {
+      for(int i = 0; i < upf_count; i++) {
+        remove(PF_DEFAULT_COUNT);
+      }
+    }
+    // Add the user defined pixel formats from the registry
+    for(int i = 0; i < count; i++) {
+      char upf_name[20] = "\0";
+      sprintf(upf_name, "%s%i", "Upf", i);
+      int size = sizeof(PixelFormatListElement);
+      PixelFormatListElement *pPFElem = 0;// = &PFElem;
+      regKey.getBinary(upf_name, (void**)&pPFElem, &size);
+      PFList.push_back(*pPFElem);
+      if (pPFElem) delete pPFElem;
+    }
+  }
+}
+
+void PixelFormatList::writeUserDefinedPF(HKEY root, const char *keypath) {
+  RegKey regKey;
+
+  // Delete all user defined pixel formats from the regisry
+  regKey.createKey(root, keypath);//_T("Software\\TightVnc\\RfbPlayer\\UserDefinedPF"));
+  int count = regKey.getInt(_T("PixelFormatCount"), 0);
+  for (int i = 0; i < count; i++) {
+    char upf_name[20] = "\0";
+    sprintf(upf_name, "%s%i", "Upf", i);
+    regKey.deleteValue(upf_name);
+  }
+  regKey.setInt(_T("PixelFormatCount"), 0);
+
+  // Write new user defined pixel formats to the registry
+  regKey.setInt(_T("PixelFormatCount"), getUserPFCount());
+  for (i = 0; i < getUserPFCount(); i++) {
+    char upf_name[20] = "\0";
+    sprintf(upf_name, "%s%i", "Upf", i);
+    regKey.setBinary(upf_name, (void *)operator[](i+getDefaultPFCount()), 
+      sizeof(PixelFormatListElement));
+  }
+}
+
+int PixelFormatList::getIndexByPFName(const char *format_name) {
+  for (int i = 0; i < PixelFormatList::count(); i++) {
+    if (_stricmp(operator[](i)->format_name, format_name) == 0) return i;
+  }
+  return -1;
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.h b/win/rfbplayer/PixelFormatList.h
new file mode 100644
index 0000000..cd7c50a
--- /dev/null
+++ b/win/rfbplayer/PixelFormatList.h
@@ -0,0 +1,85 @@
+/* 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.
+ */
+
+// -=- PixelFormatList.h
+
+// Definition of the PixelFormatList class, responsible for 
+// controlling the list of supported pixel formats.
+
+#include <list>
+
+#include <rfb/Exception.h>
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+// Definition indexes of the default pixel formats
+#define PF_BGR233 0
+#define PF_RGB555 1
+#define PF_BGR555 2
+#define PF_RGB565 3
+#define PF_BGR565 4
+#define PF_RGB888 5
+#define PF_BGR888 6
+
+using namespace rfb;
+using namespace std;
+
+// PixelFormatListElement class, it is 
+// an item of the PixelFormatList list.
+
+class PixelFormatListElement {
+public:
+  PixelFormatListElement() {
+    format_name[0] = 0;
+  }
+  char format_name[256];
+  PixelFormat PF;
+  void setName(const char *name) {
+    format_name[0] = '\0';
+    strcpy(format_name, name);
+    format_name[strlen(name)] = '\0';
+  }
+  void setPF(PixelFormat *_PF) {
+    memcpy(&PF, _PF, sizeof(PixelFormat));
+  }
+};
+
+class PixelFormatList {
+public:
+  PixelFormatList();
+
+  PixelFormatListElement* operator[](int index);
+  void add(char *format_name, PixelFormat PF);
+  void insert(int index, char *format_name, PixelFormat PF);
+  void remove(int index);
+
+  void readUserDefinedPF(HKEY root, const char *keypath);
+  void writeUserDefinedPF(HKEY root, const char *keypath);
+  
+  int count() { return PFList.size(); }
+  int getDefaultPFCount() { return  PF_DEFAULT_COUNT; }
+  int getUserPFCount() { return max(0, count() - PF_DEFAULT_COUNT); }
+  int getIndexByPFName(const char *format_name);
+  bool isDefaultPF(int index);
+
+protected:
+  list <PixelFormatListElement>::iterator getIterator(int index);
+  list <PixelFormatListElement> PFList;
+  int PF_DEFAULT_COUNT;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.cxx b/win/rfbplayer/PlayerOptions.cxx
new file mode 100644
index 0000000..5384c6e
--- /dev/null
+++ b/win/rfbplayer/PlayerOptions.cxx
@@ -0,0 +1,152 @@
+/* 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.
+ */
+
+// -=- PlayerOptions class
+
+#include <rfbplayer/PlayerOptions.h>
+
+using namespace rfb::win32;
+
+PlayerOptions::PlayerOptions() { 
+  writeDefaults();
+};
+
+void PlayerOptions::readFromRegistry() {
+  try {
+    PixelFormat *pPF = 0;
+    int pfSize = sizeof(PixelFormat);
+    RegKey regKey;
+    regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+    autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+    autoDetectPF = regKey.getBool(_T("AutoDetectPixelFormat"), DEFAULT_AUTOPF);
+    bigEndianFlag = regKey.getBool(_T("BigEndianFlag"), DEFAULT_BIG_ENDIAN);
+    pixelFormatIndex = regKey.getInt(_T("PixelFormatIndex"), DEFAULT_PF_INDEX);
+    regKey.getBinary(_T("PixelFormat"), (void**)&pPF, &pfSize, 
+      &PixelFormat(32,24,0,1,255,255,255,16,8,0), sizeof(PixelFormat));
+    setPF(pPF);
+    acceptBell = regKey.getBool(_T("AcceptBell"), DEFAULT_ACCEPT_BELL);
+    acceptCutText = regKey.getBool(_T("AcceptCutText"), DEFAULT_ACCEPT_CUT_TEXT);
+    autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+    askPixelFormat = regKey.getBool(_T("AskPixelFormat"), DEFAULT_ASK_PF);
+    if (pPF) delete pPF;
+  } catch (rdr::Exception e) {
+    MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+  }
+}
+
+void PlayerOptions::writeToRegistry() {
+  try {
+    RegKey regKey;
+    regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+    regKey.setBool(_T("AutoPlay"), autoPlay);
+    regKey.setBool(_T("AutoDetectPixelFormat"), autoDetectPF);
+    regKey.setBool(_T("BigEndianFlag"), bigEndianFlag);
+    regKey.setInt(_T("PixelFormatIndex"), pixelFormatIndex);
+    regKey.setBinary(_T("PixelFormat"), &pixelFormat, sizeof(PixelFormat));
+    regKey.setBool(_T("AcceptBell"), acceptBell);
+    regKey.setBool(_T("AcceptCutText"), acceptCutText);
+    regKey.setBool(_T("AutoPlay"), autoPlay);
+    regKey.setBool(_T("AskPixelFormat"), askPixelFormat);
+  } catch (rdr::Exception e) {
+    MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+  }
+}
+
+void PlayerOptions::writeDefaults() {
+  initTime = DEFAULT_INIT_TIME;
+  playbackSpeed = DEFAULT_SPEED;
+  autoDetectPF = DEFAULT_AUTOPF;
+  bigEndianFlag = DEFAULT_BIG_ENDIAN;
+  pixelFormatIndex = DEFAULT_PF_INDEX;
+  pixelFormat = PixelFormat(32,24,0,1,255,255,255,16,8,0);
+  frameScale = DEFAULT_FRAME_SCALE;
+  autoPlay = DEFAULT_AUTOPLAY;
+  fullScreen = DEFAULT_FULL_SCREEN;
+  acceptBell = DEFAULT_ACCEPT_BELL; 
+  acceptCutText = DEFAULT_ACCEPT_CUT_TEXT;
+  loopPlayback = DEFAULT_LOOP_PLAYBACK;
+  askPixelFormat = DEFAULT_ASK_PF; 
+  commandLineParam = false;
+}
+
+void PlayerOptions::setPF(PixelFormat *newPF) {
+  memcpy(&pixelFormat, newPF, sizeof(PixelFormat));
+}
+
+bool PlayerOptions::setPF(int rgb_order, int rm, int gm, int bm, bool big_endian) {
+  PixelFormat newPF;
+  
+  // Calculate the colour bits per pixel
+  int bpp = rm + gm + bm;
+  if (bpp < 0) {
+    return false;
+  } else if (bpp <= 8 ) {
+    newPF.bpp = 8;
+  } else if (bpp <= 16) {
+    newPF.bpp = 16;
+  } else if (bpp <= 32) {
+    newPF.bpp = 32;
+  } else {
+    return false;
+  }
+  newPF.depth = bpp;
+
+  // Calculate the r, g and b bits shifts
+  switch (rgb_order) {
+  case RGB_ORDER:
+    newPF.redShift = gm + bm;
+    newPF.greenShift = bm;
+    newPF.blueShift = 0;
+    break;
+  case RBG_ORDER:
+    newPF.redShift = bm + gm;
+    newPF.blueShift = gm;
+    newPF.greenShift = 0;
+    break;
+  case GRB_ORDER:
+    newPF.greenShift = rm + bm;
+    newPF.redShift = bm;
+    newPF.blueShift = 0;
+    break;
+  case GBR_ORDER:
+    newPF.greenShift = bm + rm;
+    newPF.blueShift = rm;
+    newPF.redShift = 0;
+    break;
+  case BGR_ORDER:
+    newPF.blueShift = gm + rm;
+    newPF.greenShift = rm;
+    newPF.redShift = 0;
+    break;
+  case BRG_ORDER:
+    newPF.blueShift = rm + gm;
+    newPF.redShift = gm;
+    newPF.greenShift = 0;
+    break;
+  default:
+    return false;
+  }
+
+  newPF.trueColour = true;
+  newPF.bigEndian = big_endian;
+  newPF.redMax = (1 << rm) - 1;
+  newPF.greenMax = (1 << gm) - 1;
+  newPF.blueMax = (1 << bm) - 1;
+  setPF(&newPF);
+  return true;
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.h b/win/rfbplayer/PlayerOptions.h
new file mode 100644
index 0000000..83618a7
--- /dev/null
+++ b/win/rfbplayer/PlayerOptions.h
@@ -0,0 +1,77 @@
+/* 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.
+ */
+
+// -=- PlayerOptions.h
+
+// Definition of the PlayerOptions class, responsible for 
+// storing & retrieving the RfbPlayer's options.
+
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+#define PF_MODES 3
+
+// The R, G and B values order in the pixel
+#define RGB_ORDER 0
+#define RBG_ORDER 1
+#define GRB_ORDER 2
+#define GBR_ORDER 3
+#define BGR_ORDER 4
+#define BRG_ORDER 5
+
+// Default options values
+//#define DEFAULT_PF 0
+#define DEFAULT_PF_INDEX -1
+#define DEFAULT_AUTOPF TRUE
+#define DEFAULT_INIT_TIME -1
+#define DEFAULT_SPEED 1.0
+#define DEFAULT_FRAME_SCALE 100
+#define DEFAULT_ACCEPT_BELL FALSE
+#define DEFAULT_ACCEPT_CUT_TEXT FALSE
+#define DEFAULT_BIG_ENDIAN FALSE
+#define DEFAULT_LOOP_PLAYBACK FALSE
+#define DEFAULT_ASK_PF FALSE
+#define DEFAULT_AUTOPLAY FALSE
+#define DEFAULT_FULL_SCREEN FALSE
+
+using namespace rfb;
+
+class PlayerOptions {
+public:
+  PlayerOptions();
+  void readFromRegistry();
+  void writeToRegistry();
+  void writeDefaults();
+  void setPF(PixelFormat *pf);
+  bool setPF(int rgb_order, int rm, int gm, int bm, bool big_endian=false);
+  long initTime;
+  double playbackSpeed;
+  bool autoPlay;
+  bool fullScreen;
+  bool autoDetectPF;
+  bool bigEndianFlag;
+  long pixelFormatIndex;
+  PixelFormat pixelFormat;
+  bool acceptBell;
+  bool acceptCutText;
+  bool loopPlayback;
+  bool askPixelFormat;
+  long frameScale;
+  bool commandLineParam;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.cxx b/win/rfbplayer/PlayerToolBar.cxx
new file mode 100644
index 0000000..3056f28
--- /dev/null
+++ b/win/rfbplayer/PlayerToolBar.cxx
@@ -0,0 +1,248 @@
+/* Copyright (C) 2005 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.
+ */
+
+// -=- PlayerToolBar.cxx
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/resource.h>
+
+PlayerToolBar::PlayerToolBar() 
+: ToolBar(), hFont(0), timeStatic(0), speedEdit(0), posTrackBar(0),
+  speedUpDown(0), sliderDragging(false), sliderStepMs(0)
+{
+}
+
+void PlayerToolBar::create(RfbPlayer *player_, HWND parentHwnd_) {
+  HDC hdc;
+  SIZE sz;
+  RECT tRect;
+  NONCLIENTMETRICS nonClientMetrics;
+
+  player = player_;
+
+  // Get the default font for the main menu
+  nonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);
+  if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nonClientMetrics, 0))
+    MessageBox(0, "Can't access to the system font.", 
+               "RfbPlayer", MB_OK | MB_ICONERROR);
+  nonClientMetrics.lfMenuFont.lfHeight = 16;
+  hFont = CreateFontIndirect(&nonClientMetrics.lfMenuFont);
+
+  // Create the toolbar panel
+  ToolBar::create(ID_TOOLBAR, parentHwnd_,
+                  WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NORESIZE);
+  addBitmap(4, IDB_TOOLBAR);
+
+  // Create the control buttons
+  addButton(0, ID_PLAY);
+  addButton(1, ID_PAUSE);
+  addButton(2, ID_STOP);
+  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+  // Create the static control for the time output
+  timeStatic = CreateWindowEx(0, "Static", "00m:00s (00m:00s)", 
+    WS_CHILD | WS_VISIBLE, 0, 0, 20, 20, getHandle(), (HMENU)ID_TIME_STATIC, 
+    GetModuleHandle(0), 0);
+  SendMessage(timeStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+  hdc = GetDC(timeStatic);
+  SelectObject(hdc, hFont);
+  GetTextExtentPoint32(hdc, "00m:00s (00m:00s)", 16, &sz);
+  addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(4, &tRect);
+  MoveWindow(timeStatic, tRect.left, tRect.top+2, tRect.right-tRect.left, 
+    tRect.bottom-tRect.top, FALSE);
+    
+  // Create the trackbar control for the time position
+  addButton(200, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(6, &tRect);
+  posTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, "Trackbar Control", 
+    WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE,
+    tRect.left, tRect.top, tRect.right-tRect.left, tRect.bottom-tRect.top,
+    parentHwnd, (HMENU)ID_POS_TRACKBAR, GetModuleHandle(0), 0);
+  // It's need to send notify messages to toolbar parent window
+  SetParent(posTrackBar, getHandle());
+  addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+  // Create the label with "Speed:" caption
+  HWND speedStatic = CreateWindowEx(0, "Static", "Speed:", WS_CHILD | WS_VISIBLE, 
+    0, 0, 5, 5, getHandle(), (HMENU)ID_SPEED_STATIC, GetModuleHandle(0), 0);
+  SendMessage(speedStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+  hdc = GetDC(speedStatic);
+  SelectObject(hdc, hFont);
+  GetTextExtentPoint32(hdc, "Speed:", 6, &sz);
+  addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(8, &tRect);
+  MoveWindow(speedStatic, tRect.left, tRect.top+2, tRect.right-tRect.left, 
+    tRect.bottom-tRect.top, FALSE);
+
+  // Create the edit control and the spin for the speed managing
+  addButton(60, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(9, &tRect);
+  speedEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "1.00", 
+    WS_CHILD | WS_VISIBLE | ES_RIGHT, tRect.left, tRect.top, 
+    tRect.right-tRect.left, tRect.bottom-tRect.top, parentHwnd,
+    (HMENU)ID_SPEED_EDIT, GetModuleHandle(0), 0);
+  SendMessage(speedEdit, WM_SETFONT,(WPARAM) hFont, TRUE);
+  // It's need to send notify messages to toolbar parent window
+  SetParent(speedEdit, getHandle());
+
+  speedUpDown = CreateUpDownControl(WS_CHILD | WS_VISIBLE  
+    | WS_BORDER | UDS_ALIGNRIGHT, 0, 0, 0, 0, getHandle(),
+    ID_SPEED_UPDOWN, GetModuleHandle(0), speedEdit, 20, 1, 2);
+
+  // Resize the toolbar window
+  autoSize();
+}
+
+void PlayerToolBar::init(long sessionTimeMs_) {
+  sessionTimeMs = sessionTimeMs_;
+
+  setSessionTimeStr(sessionTimeMs);
+  SendMessage(posTrackBar, TBM_SETRANGE, 
+    TRUE, MAKELONG(0, min(sessionTimeMs / 1000, MAX_POS_TRACKBAR_RANGE)));
+  if (sessionTimeMs == 0) {
+    sliderStepMs = 1;
+  } else {
+    sliderStepMs = sessionTimeMs / SendMessage(posTrackBar, TBM_GETRANGEMAX, 0, 0);
+  }
+  updatePos(0);
+}
+
+void PlayerToolBar::enable() {
+  enableButton(ID_PLAY, true);
+  enableButton(ID_PAUSE, true);
+  enableButton(ID_STOP, true);
+  enableButton(ID_FULLSCREEN, true);
+  EnableWindow(posTrackBar, true);
+  EnableWindow(speedEdit, true);
+  EnableWindow(speedUpDown, true);
+}
+
+void PlayerToolBar::disable() {
+  enableButton(ID_PLAY, false);
+  enableButton(ID_PAUSE, false);
+  enableButton(ID_STOP, false);
+  enableButton(ID_FULLSCREEN, false);
+  EnableWindow(posTrackBar, false);
+  EnableWindow(speedEdit, false);
+  EnableWindow(speedUpDown, false);
+}
+
+LRESULT PlayerToolBar::processWM_COMMAND(WPARAM wParam, LPARAM lParam) {
+  switch (LOWORD(wParam)) {
+
+  case ID_RETURN:
+    // Update the speed if return pressed in speedEdit
+    if (getSpeedEditHwnd() == GetFocus()) {
+      char speedStr[20], *stopStr;
+      GetWindowText(getSpeedEditHwnd(), speedStr, sizeof(speedStr));
+      double speed = strtod(speedStr, &stopStr);
+      if (speed > 0) {
+        speed = min(MAX_SPEED, speed);
+      } else {
+        speed = player->getSpeed();
+      }
+      player->setSpeed(speed);
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_HSCROLL(WPARAM wParam, LPARAM lParam) {
+  long Pos = SendMessage(posTrackBar, TBM_GETPOS, 0, 0);
+  Pos *= sliderStepMs;
+
+  switch (LOWORD(wParam)) { 
+  case TB_PAGEUP:
+  case TB_PAGEDOWN:
+  case TB_LINEUP:
+  case TB_LINEDOWN:
+  case TB_THUMBTRACK:
+    sliderDragging = true;
+    updatePos(Pos);
+    return FALSE;
+  case TB_THUMBPOSITION:
+  case TB_ENDTRACK: 
+    player->setPos(Pos);
+    player->setPaused(player->isPaused());;
+    updatePos(Pos);
+    sliderDragging = false;
+    return FALSE;
+  default:
+    break;
+  }
+  
+  return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+  switch (((NMHDR*)lParam)->code) {
+  case UDN_DELTAPOS:
+    if ((int)wParam == ID_SPEED_UPDOWN) {
+      char speedStr[20] = "\0";
+      DWORD speedRange = SendMessage(speedUpDown, UDM_GETRANGE, 0, 0);
+      LPNM_UPDOWN upDown = (LPNM_UPDOWN)lParam;
+      double speed;
+
+      // The out of range checking
+      if (upDown->iDelta > 0) {
+        speed = min(upDown->iPos + upDown->iDelta, LOWORD(speedRange)) * 0.5;
+      } else {
+        // It's need to round the UpDown position
+        if ((upDown->iPos * 0.5) != player->getSpeed()) {
+          upDown->iDelta = 0;
+        }
+        speed = max(upDown->iPos + upDown->iDelta, HIWORD(speedRange)) * 0.5;
+      }
+      player->setSpeed(speed);
+    }
+  }
+
+  // We always return TRUE to prevent the change in the updown contol 
+  // position. The control's position changes in the RfbPlayer::setSpeed().
+  return TRUE;
+}
+
+void PlayerToolBar::updatePos(long newPos) {
+  // Update time pos in static control
+  char timePos[30] = "\0";
+  long time = newPos / 1000;
+  sprintf(timePos, "%.2um:%.2us (%s)", time/60, time%60, fullSessionTimeStr);
+  SetWindowText(timeStatic, timePos);
+
+  // Update the position of slider
+  if (!sliderDragging) {
+    double error = SendMessage(posTrackBar, TBM_GETPOS, 0, 0) * 
+      sliderStepMs / double(newPos);
+    if (!((error > 1 - CALCULATION_ERROR) && (error <= 1 + CALCULATION_ERROR))) {
+      SendMessage(posTrackBar, TBM_SETPOS, TRUE, newPos / sliderStepMs);
+    }
+  }
+}
+
+void PlayerToolBar::setSessionTimeStr(long sessionTimeMs) {
+  sprintf(fullSessionTimeStr, "%.2um:%.2us", 
+    sessionTimeMs / 1000 / 60, sessionTimeMs / 1000 % 60);
+}
+
+void PlayerToolBar::setTimePos(long pos) {
+  SendMessage(posTrackBar, TBM_SETPOS, TRUE, pos);
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.h b/win/rfbplayer/PlayerToolBar.h
new file mode 100644
index 0000000..17ab82e
--- /dev/null
+++ b/win/rfbplayer/PlayerToolBar.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2005 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.
+ */
+
+// -=- PlayerToolBar.h
+
+// ToolBar for the RfbPlayer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+#define ID_TOOLBAR 500
+#define ID_PLAY 510
+#define ID_PAUSE 520
+#define ID_TIME_STATIC 530
+#define ID_SPEED_STATIC 540
+#define ID_SPEED_EDIT 550
+#define ID_POS_TRACKBAR 560
+#define ID_SPEED_UPDOWN 570
+
+#define MAX_SPEED 10.00
+#define CALCULATION_ERROR MAX_SPEED / 1000
+#define MAX_POS_TRACKBAR_RANGE 50
+
+class RfbPlayer;
+
+class PlayerToolBar : public ToolBar {
+public:
+  PlayerToolBar();
+  ~PlayerToolBar() {}
+
+  void create(RfbPlayer *player, HWND parentHwnd);
+
+  void init(long sessionTimeMs);
+
+  void enable();
+  void disable();
+
+  LRESULT processWM_COMMAND(WPARAM wParam, LPARAM lParam);
+  LRESULT processWM_HSCROLL(WPARAM wParam, LPARAM lParam);
+  LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+  HWND getSpeedEditHwnd() { return speedEdit; }
+  HWND getSpeedUpDownHwnd() { return speedUpDown; }
+
+  bool isPosSliderDragging() { return sliderDragging; };
+  void updatePos(long newPos);
+  void setSessionTimeStr(long sessionTimeMs);
+  void setTimePos(long newPos);
+
+protected:
+  RfbPlayer *player;
+  HFONT hFont;
+  HWND timeStatic;
+  HWND speedEdit;
+  HWND posTrackBar;
+  HWND speedUpDown;
+  char fullSessionTimeStr[20];
+  long sessionTimeMs;
+  bool sliderDragging;
+  long sliderStepMs;
+};
diff --git a/win/rfbplayer/RfbProto.cxx b/win/rfbplayer/RfbProto.cxx
new file mode 100644
index 0000000..5a7ff7f
--- /dev/null
+++ b/win/rfbplayer/RfbProto.cxx
@@ -0,0 +1,142 @@
+/* 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 Protocol
+
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+static LogWriter vlog("RfbProto");
+
+//
+// Constructor
+//
+
+RfbProto::RfbProto(char *fileName) {
+  is = NULL;
+  reader = NULL;
+  newSession(fileName);
+}
+
+//
+// Destructor
+//
+
+RfbProto::~RfbProto() {
+  if (is) delete is;
+  is = 0;
+  if (reader) delete reader;
+  reader = 0;
+}
+
+void RfbProto::newSession(char *fileName) {
+  // Close the previous session
+  if (is) {
+    delete is;
+    is = NULL;
+    delete reader;
+    reader = NULL;
+  }
+
+  // Begin the new session
+  if (fileName != NULL) {
+    is = new FbsInputStream(fileName);
+    reader = new CMsgReaderV3(this, is);
+    initialiseProtocol();
+  }
+}
+
+void RfbProto::initialiseProtocol() {
+  state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void RfbProto::processMsg()
+{
+  switch (state_) {
+
+  case RFBSTATE_PROTOCOL_VERSION: processVersionMsg();       break;
+  case RFBSTATE_SECURITY:         processSecurityMsg();      break;
+  case RFBSTATE_INITIALISATION:   processInitMsg();          break;
+  case RFBSTATE_NORMAL:           reader->readMsg();         break;
+  default:
+    throw rfb::Exception("RfbProto::processMsg: invalid state");
+  }
+}
+
+void RfbProto::processVersionMsg()
+{
+  vlog.debug("reading protocol version");
+  memset(&cp, 0, sizeof(cp));
+  bool done;
+  if (!cp.readVersion(is, &done)) {
+    state_ = RFBSTATE_INVALID;
+    throw rfb::Exception("reading version failed: wrong file format?");
+  }
+  if (!done) return;
+
+  // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+  if (!cp.isVersion(3,3) && !cp.isVersion(3,7) && !cp.isVersion(3,8)) {
+    char msg[256];
+    sprintf(msg,"File have unsupported RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+    state_ = RFBSTATE_INVALID;
+    throw rfb::Exception(msg);
+  }
+
+  state_ = RFBSTATE_SECURITY;
+
+  vlog.info("Using RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+}
+
+void RfbProto::processSecurityMsg()
+{
+  vlog.debug("processing security types message");
+
+  int secType = secTypeInvalid;
+
+  // legacy 3.3 server may only offer "vnc authentication" or "none"
+  secType = is->readU32();
+  if (secType == secTypeInvalid) {
+    int reasonLen = is->readU32();
+    char *reason = new char[reasonLen];
+    is->readBytes(reason, reasonLen);
+    throw rfb::Exception(reason); 
+  }
+
+  if (secType != secTypeNone) {
+    throw rfb::Exception("Wrong authentication type in the session file");
+  }
+
+  state_ = RFBSTATE_INITIALISATION;
+}
+
+void RfbProto::processInitMsg() {
+  vlog.debug("reading server initialisation");
+  reader->readServerInit(); 
+}
+
+void RfbProto::serverInit()
+{
+  state_ = RFBSTATE_NORMAL;
+  vlog.debug("initialisation done");
+}
diff --git a/win/rfbplayer/RfbProto.h b/win/rfbplayer/RfbProto.h
new file mode 100644
index 0000000..316ea26
--- /dev/null
+++ b/win/rfbplayer/RfbProto.h
@@ -0,0 +1,69 @@
+/* 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.
+ */
+
+// -=- RfbProto.h
+
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+using namespace rfb;
+
+class RfbProto : public CMsgHandler {
+  public:
+
+    RfbProto(char *fileName);
+    ~RfbProto();
+
+    void newSession(char *filename);
+    void initialiseProtocol();
+    void interruptFrameDelay() { is->interruptFrameDelay(); };
+    const rdr::InStream* getInStream() { return is; }
+
+    virtual void processMsg();
+
+    // serverInit() is called when the ServerInit message is received.  The
+    // derived class must call on to CMsgHandler::serverInit().
+    void serverInit();
+
+    enum stateEnum {
+      RFBSTATE_PROTOCOL_VERSION,
+      RFBSTATE_SECURITY,
+      RFBSTATE_INITIALISATION,
+      RFBSTATE_NORMAL,
+      RFBSTATE_INVALID
+    };
+
+    stateEnum state() { return state_; }
+
+  protected:
+    void setState(stateEnum s) { state_ = s; }
+    virtual void framebufferUpdateEnd() {};
+
+    FbsInputStream* is;
+    CMsgReaderV3* reader;
+    stateEnum state_;
+
+  private:
+    void processVersionMsg();
+    void processSecurityMsg();
+    void processInitMsg();
+};
diff --git a/win/rfbplayer/SessionInfoDialog.h b/win/rfbplayer/SessionInfoDialog.h
new file mode 100644
index 0000000..2c036db
--- /dev/null
+++ b/win/rfbplayer/SessionInfoDialog.h
@@ -0,0 +1,100 @@
+/* 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.
+ */
+
+// -=- SessionInfoDialog.h
+
+#include <math.h>
+
+#include <rfb/ConnParams.h>
+
+#include <rfb_win32/Dialog.h>
+
+#define log2(n) log(n) / 0.693147180559945
+
+int max3(int v1, int v2, int v3) {
+  return max(v1, max(v2, v3));
+}
+
+class SessionInfoDialog : public rfb::win32::Dialog {
+public:
+  SessionInfoDialog(ConnParams *_cp, int _currentEncoding) 
+    : Dialog(GetModuleHandle(0)), cp(_cp), currentEncoding(_currentEncoding) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent = 0) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_SESSION_INFO), parent);
+  }
+protected:
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    char strValue[255] = "\0";
+    setItemString(IDC_DESKTOP_NAME, cp->name());
+    
+    sprintf(strValue, "%ix%i", cp->width, cp->height);
+    setItemString(IDC_DESKTOP_SIZE, strValue);
+    
+    int r = cp->pf().redShift, g = cp->pf().greenShift, b = cp->pf().blueShift;
+    int i = 3;
+    char buffer[10];
+    sprintf(strValue, "depth %i(%ibpp), ", cp->pf().depth, cp->pf().bpp);
+    while (i) {
+      if (r == max3(r, g, b)) {
+        strcat(strValue, "r");
+        _itoa(ceil(log2(cp->pf().redMax)), buffer, 10);
+        strcat(strValue, buffer);
+        r = -1; 
+        i--;
+        continue;
+      } else if (g == max3(r, g, b)) {
+        strcat(strValue, "g");
+        _itoa(ceil(log2(cp->pf().greenMax)), buffer, 10);
+        strcat(strValue, buffer);
+        g = -1; 
+        i--;
+        continue;
+      } else if (b == max3(r, g, b)) {
+        strcat(strValue, "b");
+        _itoa(ceil(log2(cp->pf().blueMax)), buffer, 10);
+        strcat(strValue, buffer);
+        b = -1; 
+        i--;
+        continue;
+      } else break;
+    }
+    if (cp->pf().bigEndian) strcat(strValue, ", big-endian");
+    else strcat(strValue, ", little-endian");
+    setItemString(IDC_PIXEL_FORMAT, strValue);
+
+    switch (currentEncoding) {
+    case encodingRaw:      strcpy(strValue, "Raw");      break;
+    case encodingCopyRect: strcpy(strValue, "CopyRect"); break;
+    case encodingRRE:      strcpy(strValue, "RRE");      break;
+    case encodingCoRRE:    strcpy(strValue, "CoRRE");    break;
+    case encodingHextile:  strcpy(strValue, "Hextile");  break;
+    case encodingTight:    strcpy(strValue, "Tight");    break;
+    case encodingZRLE:     strcpy(strValue, "ZRLE");     break;
+    default:               strcpy(strValue, "Unknown");
+    }
+    setItemString(IDC_CURRENT_ENCODING, strValue);
+
+    sprintf(strValue, "%i.%i", cp->majorVersion, cp->minorVersion);
+    setItemString(IDC_VERSION, strValue);
+  }
+  ConnParams *cp;
+  int currentEncoding;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/UserPixelFormatsDialog.h b/win/rfbplayer/UserPixelFormatsDialog.h
new file mode 100644
index 0000000..fe2ad22
--- /dev/null
+++ b/win/rfbplayer/UserPixelFormatsDialog.h
@@ -0,0 +1,105 @@
+/* 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.
+ */
+
+// -=- UserPixelFormatsDialog.h
+
+#include <rfbplayer/EditPixelFormatDialog.h>
+
+#define UPF_REGISTRY_PATH "Software\\TightVnc\\RfbPlayer\\UserDefinedPF"
+
+class UserPixelFormatsDialog : public rfb::win32::Dialog {
+public:
+  UserPixelFormatsDialog(PixelFormatList *_supportedPF) 
+  : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), pfList(0) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_USERPF_LIST), parent);
+  }
+
+protected:
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    pfList = GetDlgItem(handle, IDC_PF_LIST);
+    for (int i = supportedPF->getDefaultPFCount(); i < supportedPF->count(); i++) {
+      SendMessage(pfList, LB_ADDSTRING, 
+        0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+    }
+    SendMessage(pfList, LB_SETCURSEL, 0, 0);
+  }
+  virtual bool onCommand(int item, int cmd) { 
+    switch (item) {
+    case IDC_ADD_BUTTON:
+      { 
+        char format_name[MAX_STR_LEN] = "";
+        PixelFormat pf(32, 24, 0, 1, 0, 0, 0, 0, 0, 0);
+        EditPixelFormatDialog edit(supportedPF, format_name, &pf);
+        if (edit.showDialog(handle)) {
+          supportedPF->add(format_name, pf);
+          SendMessage(pfList, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)format_name);
+        }
+      }
+      break;
+    case IDC_REMOVE_BUTTON:
+      {
+        int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+        if (index == LB_ERR) {
+          MessageBox(handle, "You must select the pixel format for remove.", 
+                     "RfbPlayer", MB_OK | MB_ICONWARNING);
+          return false;
+        } else {
+          supportedPF->remove(supportedPF->getDefaultPFCount() + index);
+          SendMessage(pfList, LB_DELETESTRING, index, 0);
+        }
+      }
+      break;
+    case IDC_PF_LIST:
+      if (cmd != LBN_DBLCLK) break;
+    case IDC_EDIT_BUTTON:
+      {
+        int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+        if (index == LB_ERR) {
+          MessageBox(handle, "You must select the pixel format for remove.", 
+                     "RfbPlayer", MB_OK | MB_ICONWARNING);
+          return false;
+        }
+        PixelFormat *pf = 
+          &(supportedPF->operator[](index + supportedPF->getDefaultPFCount())->PF);
+        char *format_name = 
+          (supportedPF)->operator[](index + supportedPF->getDefaultPFCount())->format_name;
+        EditPixelFormatDialog edit(supportedPF, format_name, pf);
+        if (edit.showDialog(handle)) {
+          SendMessage(pfList, LB_DELETESTRING, index, 0);
+          SendMessage(pfList, LB_INSERTSTRING, index, (LPARAM)(LPCTSTR)format_name);
+          SendMessage(pfList, LB_SETCURSEL, index, 0);
+        }
+      }
+      break;
+    default:
+      break;
+    }
+    return false;
+  }
+  virtual bool onOk() {
+    supportedPF->writeUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+    return true;
+  }
+
+  HWND pfList;
+  PixelFormatList *supportedPF;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/buildTime.cxx b/win/rfbplayer/buildTime.cxx
new file mode 100644
index 0000000..bab2e13
--- /dev/null
+++ b/win/rfbplayer/buildTime.cxx
@@ -0,0 +1 @@
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
\ No newline at end of file
diff --git a/win/rfbplayer/resource.h b/win/rfbplayer/resource.h
new file mode 100644
index 0000000..90a057f
--- /dev/null
+++ b/win/rfbplayer/resource.h
@@ -0,0 +1,81 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by rfbplayer.rc
+//
+#define IDI_ICON                        105
+#define IDR_MENU                        128
+#define IDR_ACCELERATOR                 131
+#define IDB_TOOLBAR                     132
+#define IDD_GOTO                        133
+#define IDD_PIXELFORMAT                 134
+#define IDD_OPTIONS                     137
+#define IDD_ABOUT                       138
+#define IDD_USERPF_LIST                 139
+#define IDD_UPF_EDIT                    140
+#define IDD_INFO                        141
+#define IDD_SESSION_INFO                142
+#define IDC_GOTO_EDIT                   1003
+#define IDC_PIXELFORMAT                 1004
+#define IDC_ASK_PF                      1006
+#define IDC_DEFAULT                     1008
+#define IDC_VERSION                     1008
+#define IDC_ACCEPT_BELL                 1009
+#define IDC_BUILDTIME                   1009
+#define IDC_ACCEPT_CUT_TEXT             1010
+#define IDC_AUTO_STORE_PARAM            1011
+#define IDC_AUTOPLAY                    1012
+#define IDC_BIG_ENDIAN                  1013
+#define IDC_EDIT_UPF                    1015
+#define IDC_PF_LIST                     1016
+#define IDC_BPP_COMBO                   1016
+#define IDC_ADD_BUTTON                  1017
+#define IDC_NAME_EDIT                   1017
+#define IDC_REMOVE_BUTTON               1018
+#define IDC_EDIT_BUTTON                 1019
+#define IDC_COPYRIGHT                   1021
+#define IDC_DEPTH_EDIT                  1021
+#define IDC_DESCRIPTION                 1022
+#define IDC_BIGENDIAN_COMBO             1022
+#define IDC_REDMAX_EDIT                 1023
+#define IDC_GREENMAX_EDIT               1024
+#define IDC_BLUEMAX_EDIT                1025
+#define IDC_REDSHIFT_EDIT               1026
+#define IDC_DESKTOP_NAME                1026
+#define IDC_GREENSHIFT_EDIT             1027
+#define IDC_DESKTOP_SIZE                1027
+#define IDC_BLUESHIFT_EDIT              1028
+#define IDC_CURRENT_ENCODING            1029
+#define IDC_PIXEL_FORMAT                1030
+#define IDC_INFO_EDIT                   1076
+#define ID_OPENFILE                     40011
+#define ID_CLOSEFILE                    40012
+#define ID_EXIT                         40013
+#define ID_FULLSCREEN                   40014
+#define ID_ZOOM_50                      40015
+#define ID_ZOOM_100                     40016
+#define ID_ZOOM_200                     40017
+#define ID_PLAYPAUSE                    40018
+#define ID_STOP                         40019
+#define ID_GOTO                         40020
+#define ID_LOOP                         40022
+#define ID_COPYTOCLIPBOARD              40023
+#define ID_FRAMEEXTRACT                 40024
+#define ID_HELP_HOMEPAGE                40025
+#define ID_HOMEPAGE                     40025
+#define ID_HELP_COMMANDLINESWITCHES     40026
+#define ID_HELP_ABOUT                   40027
+#define ID_ABOUT                        40027
+#define ID_OPTIONS                      40029
+#define ID_RETURN                       40044
+#define ID_SESSION_INFO                 40045
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        143
+#define _APS_NEXT_COMMAND_VALUE         40046
+#define _APS_NEXT_CONTROL_VALUE         1031
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/win/rfbplayer/rfbSessionReader.h b/win/rfbplayer/rfbSessionReader.h
new file mode 100644
index 0000000..31985bc
--- /dev/null
+++ b/win/rfbplayer/rfbSessionReader.h
@@ -0,0 +1,59 @@
+/* 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.
+ */
+
+// -=- rfbSessionReader.h
+
+#include <rfb/Threading.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+class rfbSessionReader : public Thread {
+public:
+  rfbSessionReader(RfbProto *_rfbSession) {
+    rfbSession = _rfbSession;
+    fStop = false;
+    rfbSession->interruptFrameDelay();
+  };
+  
+  ~rfbSessionReader() {
+  }
+
+  virtual Thread* join() {
+    ((FbsInputStream*)(rfbSession->getInStream()))->resumePlayback();
+    fStop = true;
+    return Thread::join();
+  }
+
+  virtual void rfbSessionReader::run() {
+    // Process the rfb messages
+    while (!fStop) {
+      try {
+        rfbSession->processMsg();
+      } catch (rdr::Exception e) {
+        MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+        break;
+      }
+    }
+  }
+
+protected:
+  bool fStop;
+  RfbProto *rfbSession;
+};
\ No newline at end of file
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;
+};
diff --git a/win/rfbplayer/rfbplayer.dsp b/win/rfbplayer/rfbplayer.dsp
new file mode 100644
index 0000000..9068536
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.dsp
@@ -0,0 +1,207 @@
+# Microsoft Developer Studio Project File - Name="rfbplayer" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Application" 0x0101

+

+CFG=rfbplayer - Win32 Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "rfbplayer.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "rfbplayer.mak" CFG="rfbplayer - Win32 Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "rfbplayer - Win32 Release" (based on "Win32 (x86) Application")

+!MESSAGE "rfbplayer - Win32 Debug" (based on "Win32 (x86) Application")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+MTL=midl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "rfbplayer - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir "Release"

+# PROP BASE Intermediate_Dir "Release"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir "..\Release"

+# PROP Intermediate_Dir "..\Release\rfbplayer"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c

+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c

+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32

+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32

+# ADD BASE RSC /l 0x419 /d "NDEBUG"

+# ADD RSC /l 0x409 /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386

+# ADD LINK32 user32.lib gdi32.lib Advapi32.lib comctl32.lib shell32.lib comdlg32.lib version.lib /nologo /subsystem:windows /machine:I386

+# Begin Special Build Tool

+SOURCE="$(InputPath)"

+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\rfbplayer /MTd buildTime.cxx

+# End Special Build Tool

+

+!ELSEIF  "$(CFG)" == "rfbplayer - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "Debug"

+# PROP BASE Intermediate_Dir "Debug"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "..\Debug"

+# PROP Intermediate_Dir "..\Debug\rfbplayer"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c

+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32

+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32

+# ADD BASE RSC /l 0x419 /d "_DEBUG"

+# ADD RSC /l 0x409 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept

+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept

+# Begin Special Build Tool

+SOURCE="$(InputPath)"

+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\rfbplayer /MTd buildTime.cxx

+# End Special Build Tool

+

+!ENDIF 

+

+# Begin Target

+

+# Name "rfbplayer - Win32 Release"

+# Name "rfbplayer - Win32 Debug"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=.\buildTime.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FbsInputStream.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\PixelFormatList.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\PlayerOptions.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\PlayerToolBar.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\rfbplayer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\rfbplayer.rc

+# End Source File

+# Begin Source File

+

+SOURCE=.\RfbProto.cxx

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# Begin Source File

+

+SOURCE=.\ChoosePixelFormatDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\EditPixelFormatDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FbsInputStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\GotoPosDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\InfoDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\OptionsDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\PixelFormatList.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\PlayerOptions.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\PlayerToolBar.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\rfbplayer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\RfbProto.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\rfbSessionReader.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SessionInfoDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\UserPixelFormatsDialog.h

+# End Source File

+# End Group

+# Begin Group "Resource Files"

+

+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"

+# Begin Source File

+

+SOURCE=.\rfbplayer.ico

+# End Source File

+# Begin Source File

+

+SOURCE=.\toolbar.bmp

+# End Source File

+# End Group

+# End Target

+# End Project

diff --git a/win/rfbplayer/rfbplayer.h b/win/rfbplayer/rfbplayer.h
new file mode 100644
index 0000000..c5c5da8
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.h
@@ -0,0 +1,195 @@
+/* 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.
+ */
+
+// -=- RfbPlayer.h
+
+#include <windows.h>
+
+#include <rfb_win32/DIBSectionBuffer.h>
+
+#include <rfbplayer/resource.h>
+#include <rfbplayer/PixelFormatList.h>
+#include <rfbplayer/PlayerToolBar.h>
+#include <rfbplayer/OptionsDialog.h>
+#include <rfbplayer/rfbSessionReader.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+class PlayerToolBar;
+
+class RfbPlayer : public RfbProto {
+  public:
+    RfbPlayer(char *fileName, PlayerOptions *options);
+    ~RfbPlayer();
+
+    // -=- Window Message handling
+
+    LRESULT processMainMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+    LRESULT processFrameMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+    // -=- Window interface
+
+    HWND getMainHandle() const {return mainHwnd;}
+    HWND getFrameHandle() const {return frameHwnd;}
+    void disableTBandMenuItems();
+    void enableTBandMenuItems();
+    void setFrameSize(int width, int height);
+    void setVisible(bool visible);
+    void setTitle(const char *title);
+    void calculateScrollBars();
+    void close(const char* reason=0);
+    void init();
+
+    // -=- Coordinate conversions
+
+    inline Point bufferToClient(const Point& p) {
+      Point pos = p;
+      if (client_size.width() > buffer->width())
+        pos.x += (client_size.width() - buffer->width()) / 2;
+      else if (client_size.width() < buffer->width())
+        pos.x -= scrolloffset.x;
+      if (client_size.height() > buffer->height())
+        pos.y += (client_size.height() - buffer->height()) / 2;
+      else if (client_size.height() < buffer->height())
+        pos.y -= scrolloffset.y;
+      return pos;
+    }
+    inline Rect bufferToClient(const Rect& r) {
+      return Rect(bufferToClient(r.tl), bufferToClient(r.br));
+    }
+
+    inline Point clientToBuffer(const Point& p) {
+      Point pos = p;
+      if (client_size.width() > buffer->width())
+        pos.x -= (client_size.width() - buffer->width()) / 2;
+      else if (client_size.width() < buffer->width())
+        pos.x += scrolloffset.x;
+      if (client_size.height() > buffer->height())
+        pos.y -= (client_size.height() - buffer->height()) / 2;
+      else if (client_size.height() < buffer->height())
+        pos.y += scrolloffset.y;
+      return pos;
+    }
+    inline Rect clientToBuffer(const Rect& r) {
+      return Rect(clientToBuffer(r.tl), clientToBuffer(r.br));
+    }
+
+    bool setViewportOffset(const Point& tl);
+
+    // -=- RfbProto interface overrides
+
+    virtual void processMsg();
+    virtual void serverInit();
+    virtual void frameBufferUpdateEnd();
+    virtual void setColourMapEntries(int first, int count, U16* rgbs);
+    virtual void serverCutText(const char* str, int len);
+    virtual void bell();
+
+    virtual void beginRect(const Rect& r, unsigned int encoding);
+    virtual void endRect(const Rect& r, unsigned int encoding);
+    virtual void fillRect(const Rect& r, Pixel pix);
+    virtual void imageRect(const Rect& r, void* pixels);
+    virtual void copyRect(const Rect& r, int srcX, int srcY);
+
+    // -=- Player functions
+
+    // calculateSessionTime() calculates the full session time in sec
+    long calculateSessionTime(char *fileName);
+
+    // closeSessionFile() closes the session file and blanks the frame buffer
+    void closeSessionFile();
+
+    // openSessionFile() opens the new session file and starts play it
+    void openSessionFile(char *fileName);
+
+    // skipHandshaking() - is implemented to skip the initial handshaking when
+    // perform backward seeking OR replaying.
+    void skipHandshaking();
+
+    void blankBuffer();
+    void rewind();
+    void setPaused(bool paused);
+    void stopPlayback();
+    long getTimeOffset();
+    bool isSeekMode();
+    bool isSeeking();
+    bool isPaused();
+    long getSeekOffset();
+    void setPos(long pos);
+    void setSpeed(double speed);
+    double getSpeed();
+
+  protected:
+    bool seekMode;
+    bool stopped;
+    long lastPos;
+    long sliderStepMs;
+    char fullSessionTime[20];
+    int time_pos_m;
+    int time_pos_s;
+    char *fileName;
+    
+    // rfbReader is a class which used to reading the rfb data from the file
+    rfbSessionReader *rfbReader;
+
+    // Returns true if part of the supplied rect is visible, false otherwise
+    bool invalidateBufferRect(const Rect& crect);
+
+    bool waitWhilePaused();
+
+    // rewindFlag is a flag wich disable the update of the frame buffer window 
+    // while the rewind is performing.
+    bool rewindFlag;
+    
+    // Local window state
+    HWND mainHwnd;
+    HWND frameHwnd;
+    HMENU hMenu;
+    Rect window_size;
+    Rect client_size;
+    Point scrolloffset;
+    Point maxscrolloffset;
+    char *cutText;
+    win32::DIBSectionBuffer* buffer;
+    PlayerToolBar tb;
+
+    // The player's parameters
+    PlayerOptions options;
+    PixelFormatList supportedPF;
+    long imageDataStartTime;
+    long sessionTimeMs;
+    int currentEncoding;
+};
+
+// -=- sessionTerminateThread class
+
+// It is a special thread class, wich is allow the rfbSessionReader class
+// terminate itself.
+
+class sessionTerminateThread : public rfb::Thread {
+public:
+  sessionTerminateThread(RfbPlayer *_player) : player(_player) {
+    setDeleteAfterRun();
+  }
+  virtual void run() {
+    player->closeSessionFile();
+  }
+protected:
+  RfbPlayer *player;
+};
diff --git a/win/rfbplayer/rfbplayer.ico b/win/rfbplayer/rfbplayer.ico
new file mode 100644
index 0000000..c9136bf
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.ico
Binary files differ
diff --git a/win/rfbplayer/rfbplayer.rc b/win/rfbplayer/rfbplayer.rc
new file mode 100644
index 0000000..169d850
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.rc
@@ -0,0 +1,466 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON                ICON    DISCARDABLE     "rfbplayer.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "080904b0"
+        BEGIN
+            VALUE "Comments", "\0"
+            VALUE "CompanyName", "TightVNC Team\0"
+            VALUE "FileDescription", "RFB Session Player for Win32\0"
+            VALUE "FileVersion", "1, 0, 0, 1\0"
+            VALUE "InternalName", "rfbplayer\0"
+            VALUE "LegalCopyright", "Copyright (C) 2004-2005 TightVNC Team.\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "rfbplayer.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "Rfb Session Player 1.0\0"
+            VALUE "ProductVersion", "1, 0, 0, 1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x809, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE 
+BEGIN
+    POPUP "File"
+    BEGIN
+        MENUITEM "Open File...\tCtrl+O",        ID_OPENFILE
+        MENUITEM "Close File...\tCtrl+Q",       ID_CLOSEFILE
+        MENUITEM SEPARATOR
+        MENUITEM "Info...\tCtrl+I",             ID_SESSION_INFO
+        MENUITEM SEPARATOR
+        MENUITEM "Exit\tAlt+X",                 ID_EXIT
+    END
+    POPUP "Play"
+    BEGIN
+        MENUITEM "Play/Pause\tSpace",           ID_PLAYPAUSE
+        MENUITEM "Stop\tC",                     ID_STOP
+        MENUITEM "Go To...\tCtrl+G",            ID_GOTO
+        MENUITEM SEPARATOR
+        MENUITEM "Loop\tCtrl+L",                ID_LOOP
+        MENUITEM SEPARATOR
+        MENUITEM "Options...\tO",               ID_OPTIONS
+    END
+    POPUP "Help"
+    BEGIN
+        MENUITEM "Home Page",                   ID_HOMEPAGE
+        MENUITEM "Command Line Switches",       ID_HELP_COMMANDLINESWITCHES
+        MENUITEM SEPARATOR
+        MENUITEM "About RfbPlayer...",          ID_ABOUT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR ACCELERATORS DISCARDABLE 
+BEGIN
+    "C",            ID_STOP,                VIRTKEY, NOINVERT
+    "C",            ID_COPYTOCLIPBOARD,     VIRTKEY, CONTROL, NOINVERT
+    "C",            ID_FRAMEEXTRACT,        VIRTKEY, ALT, NOINVERT
+    "G",            ID_GOTO,                VIRTKEY, CONTROL, NOINVERT
+    "I",            ID_SESSION_INFO,        VIRTKEY, CONTROL, NOINVERT
+    "L",            ID_LOOP,                VIRTKEY, CONTROL, NOINVERT
+    "O",            ID_OPTIONS,             VIRTKEY, NOINVERT
+    "O",            ID_OPENFILE,            VIRTKEY, CONTROL, NOINVERT
+    "P",            ID_OPTIONS,             VIRTKEY, CONTROL, NOINVERT
+    "Q",            ID_CLOSEFILE,           VIRTKEY, CONTROL, NOINVERT
+    VK_F5,          ID_ZOOM_50,             VIRTKEY, NOINVERT
+    VK_F6,          ID_ZOOM_100,            VIRTKEY, NOINVERT
+    VK_F7,          ID_ZOOM_200,            VIRTKEY, NOINVERT
+    VK_RETURN,      ID_RETURN,              VIRTKEY, NOINVERT
+    VK_RETURN,      ID_FULLSCREEN,          VIRTKEY, ALT, NOINVERT
+    VK_SPACE,       ID_PLAYPAUSE,           VIRTKEY, NOINVERT
+    "X",            ID_EXIT,                VIRTKEY, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TOOLBAR             BITMAP  DISCARDABLE     "toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_GOTO DIALOG DISCARDABLE  0, 0, 153, 54
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Go to position"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_GOTO_EDIT,40,9,106,14,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "OK",IDOK,40,33,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,95,33,51,14
+    LTEXT           "Pos (ms):",IDC_STATIC,7,9,33,15,SS_CENTERIMAGE
+END
+
+IDD_PIXELFORMAT DIALOG DISCARDABLE  0, 0, 144, 78
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Pixel Format"
+FONT 8, "MS Sans Serif"
+BEGIN
+    COMBOBOX        IDC_PIXELFORMAT,7,20,130,98,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    DEFPUSHBUTTON   "OK",IDOK,20,57,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,75,57,50,14
+    LTEXT           "Choose the pixel format:",IDC_STATIC,7,7,130,13
+    CONTROL         "Big endian flag",IDC_BIG_ENDIAN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,40,63,12
+END
+
+IDD_OPTIONS DIALOG DISCARDABLE  0, 0, 187, 180
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Options"
+FONT 8, "MS Sans Serif"
+BEGIN
+    COMBOBOX        IDC_PIXELFORMAT,15,30,157,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Big endian flag",IDC_BIG_ENDIAN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,52,60,10
+    CONTROL         "Ask the pixel format before playing",IDC_ASK_PF,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,67,157,10
+    CONTROL         "Accept the bells",IDC_ACCEPT_BELL,"Button",
+                    BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,105,157,15
+    CONTROL         "Accept the cut text",IDC_ACCEPT_CUT_TEXT,"Button",
+                    BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,120,157,15
+    CONTROL         "Start play the session when it is opened",IDC_AUTOPLAY,
+                    "Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,135,
+                    157,9
+    DEFPUSHBUTTON   "OK",IDOK,20,161,50,13
+    PUSHBUTTON      "Cancel",IDCANCEL,75,161,50,13
+    PUSHBUTTON      "Default",IDC_DEFAULT,130,161,50,13
+    PUSHBUTTON      "Edit User PF",IDC_EDIT_UPF,110,52,62,14
+    GROUPBOX        "Pixel format",IDC_STATIC,7,6,173,79
+    LTEXT           "Forces the pixel format for the rfb session:",
+                    IDC_STATIC,15,17,157,13
+    GROUPBOX        "Other",IDC_STATIC,7,90,173,65
+END
+
+IDD_ABOUT DIALOG DISCARDABLE  0, 0, 251, 95
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Rfb Session Player for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,195,70,47,15
+    ICON            IDI_ICON,IDC_STATIC,7,10,20,20
+    LTEXT           ">appname<",IDC_DESCRIPTION,40,10,125,15
+    LTEXT           ">version<",IDC_VERSION,165,10,77,15
+    LTEXT           ">buildtime<",IDC_BUILDTIME,40,25,202,15
+    LTEXT           ">copyright<",IDC_COPYRIGHT,40,40,202,15
+    LTEXT           "See http://www.tightvnc.com for more information on TightVNC.",
+                    IDC_STATIC,40,55,202,15
+END
+
+IDD_USERPF_LIST DIALOG DISCARDABLE  0, 0, 207, 162
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Add / Remove the user pixel formats"
+FONT 8, "MS Sans Serif"
+BEGIN
+    LISTBOX         IDC_PF_LIST,7,7,136,148,LBS_NOINTEGRALHEIGHT | 
+                    WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Add",IDC_ADD_BUTTON,150,7,50,14
+    PUSHBUTTON      "Remove",IDC_REMOVE_BUTTON,150,26,50,14
+    PUSHBUTTON      "Edit",IDC_EDIT_BUTTON,150,45,50,14
+    PUSHBUTTON      "Close",IDOK,150,64,50,14
+END
+
+IDD_UPF_EDIT DIALOG DISCARDABLE  0, 0, 204, 126
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit the user pixel format"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_NAME_EDIT,68,7,129,13,ES_AUTOHSCROLL
+    COMBOBOX        IDC_BPP_COMBO,68,23,39,45,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    EDITTEXT        IDC_DEPTH_EDIT,157,22,40,13,ES_AUTOHSCROLL | ES_NUMBER
+    COMBOBOX        IDC_BIGENDIAN_COMBO,68,38,39,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    EDITTEXT        IDC_REDMAX_EDIT,68,54,39,13,ES_AUTOHSCROLL | ES_NUMBER
+    EDITTEXT        IDC_GREENMAX_EDIT,68,70,39,13,ES_AUTOHSCROLL | ES_NUMBER
+    EDITTEXT        IDC_BLUEMAX_EDIT,68,86,39,13,ES_AUTOHSCROLL | ES_NUMBER
+    EDITTEXT        IDC_REDSHIFT_EDIT,157,54,39,13,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    EDITTEXT        IDC_GREENSHIFT_EDIT,157,70,40,13,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    EDITTEXT        IDC_BLUESHIFT_EDIT,157,86,40,13,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    PUSHBUTTON      "OK",IDOK,93,105,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,147,105,50,14
+    LTEXT           "Pixel format name:",IDC_STATIC,7,7,57,13,SS_CENTERIMAGE
+    LTEXT           "Bit per pixel:",IDC_STATIC,7,23,38,12,SS_CENTERIMAGE
+    LTEXT           "Big endian flag :",IDC_STATIC,7,38,53,13,SS_CENTERIMAGE
+    LTEXT           "Red max :",IDC_STATIC,7,54,33,13,SS_CENTERIMAGE
+    LTEXT           "Green max :",IDC_STATIC,7,70,38,13,SS_CENTERIMAGE
+    LTEXT           "Blue max :",IDC_STATIC,7,86,38,13,SS_CENTERIMAGE
+    LTEXT           "Depth:",IDC_STATIC,112,23,21,12,SS_CENTERIMAGE
+    LTEXT           "Red shifts :",IDC_STATIC,112,54,36,13,SS_CENTERIMAGE
+    LTEXT           "Green shifts :",IDC_STATIC,112,70,43,13,SS_CENTERIMAGE
+    LTEXT           "Blue shifts :",IDC_STATIC,112,86,43,13,SS_CENTERIMAGE
+END
+
+IDD_INFO DIALOG DISCARDABLE  0, 0, 295, 207
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Information"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "&OK",IDOK,122,186,50,14
+    EDITTEXT        IDC_INFO_EDIT,7,7,281,172,ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | 
+                    WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_SESSION_INFO DIALOG DISCARDABLE  0, 0, 239, 106
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RFB Session Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,182,85,50,14
+    LTEXT           "Desktop Name:",IDC_STATIC,7,10,73,15
+    LTEXT           "Desktop Size:",IDC_STATIC,7,25,73,15
+    LTEXT           "Pixel Format:",IDC_STATIC,7,40,73,15
+    LTEXT           "Current Encoding:",IDC_STATIC,7,55,73,15
+    LTEXT           "RFB Protocol Version:",IDC_STATIC,7,70,73,15
+    LTEXT           "",IDC_DESKTOP_NAME,80,10,152,15
+    LTEXT           "",IDC_DESKTOP_SIZE,80,25,152,15
+    LTEXT           "",IDC_CURRENT_ENCODING,80,55,152,15
+    LTEXT           "",IDC_VERSION,80,70,152,15
+    LTEXT           "",IDC_PIXEL_FORMAT,80,40,152,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_GOTO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 146
+        VERTGUIDE, 40
+        VERTGUIDE, 90
+        VERTGUIDE, 95
+        TOPMARGIN, 9
+        BOTTOMMARGIN, 47
+        HORZGUIDE, 9
+        HORZGUIDE, 24
+        HORZGUIDE, 35
+    END
+
+    IDD_PIXELFORMAT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 137
+        VERTGUIDE, 20
+        VERTGUIDE, 70
+        VERTGUIDE, 75
+        VERTGUIDE, 125
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 71
+        HORZGUIDE, 7
+        HORZGUIDE, 20
+        HORZGUIDE, 35
+        HORZGUIDE, 40
+        HORZGUIDE, 49
+        HORZGUIDE, 57
+    END
+
+    IDD_OPTIONS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 180
+        VERTGUIDE, 15
+        VERTGUIDE, 20
+        VERTGUIDE, 70
+        VERTGUIDE, 75
+        VERTGUIDE, 125
+        VERTGUIDE, 130
+        VERTGUIDE, 172
+        TOPMARGIN, 6
+        BOTTOMMARGIN, 174
+        HORZGUIDE, 17
+        HORZGUIDE, 30
+        HORZGUIDE, 42
+        HORZGUIDE, 52
+        HORZGUIDE, 67
+        HORZGUIDE, 85
+        HORZGUIDE, 90
+        HORZGUIDE, 105
+        HORZGUIDE, 120
+        HORZGUIDE, 135
+        HORZGUIDE, 144
+        HORZGUIDE, 150
+        HORZGUIDE, 155
+        HORZGUIDE, 161
+    END
+
+    IDD_USERPF_LIST, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 200
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 155
+        HORZGUIDE, 21
+        HORZGUIDE, 26
+        HORZGUIDE, 40
+        HORZGUIDE, 45
+        HORZGUIDE, 59
+        HORZGUIDE, 64
+    END
+
+    IDD_UPF_EDIT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 197
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 119
+    END
+
+    IDD_INFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 288
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 200
+    END
+
+    IDD_SESSION_INFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 232
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 99
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/win/rfbplayer/toolbar.bmp b/win/rfbplayer/toolbar.bmp
new file mode 100644
index 0000000..9347a73
--- /dev/null
+++ b/win/rfbplayer/toolbar.bmp
Binary files differ