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/vncviewer/CConn.cxx b/win/vncviewer/CConn.cxx
new file mode 100644
index 0000000..73597f5
--- /dev/null
+++ b/win/vncviewer/CConn.cxx
@@ -0,0 +1,712 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/resource.h>
+#include <rfb/encodings.h>
+#include <rfb/secTypes.h>
+#include <rfb/CSecurityNone.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/CMsgWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/AboutDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+
+// - Statics & consts
+
+static LogWriter vlog("CConn");
+
+
+const int IDM_FULLSCREEN = ID_FULLSCREEN;
+const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY;
+const int IDM_SEND_CAD = ID_SEND_CAD;
+const int IDM_SEND_CTLESC = ID_SEND_CTLESC;
+const int IDM_ABOUT = ID_ABOUT;
+const int IDM_OPTIONS = ID_OPTIONS;
+const int IDM_INFO = ID_INFO;
+const int IDM_NEWCONN = ID_NEW_CONNECTION;
+const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH;
+const int IDM_CTRL_KEY = ID_CTRL_KEY;
+const int IDM_ALT_KEY = ID_ALT_KEY;
+const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER;
+const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS;
+
+
+static IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
+                               "pixel data - a debugging feature", 0);
+
+
+//
+// -=- CConn implementation
+//
+
+RegKey            CConn::userConfigKey;
+
+
+CConn::CConn() 
+  : window(0), sock(0), sockEvent(CreateEvent(0, TRUE, FALSE, 0)), requestUpdate(false),
+    sameMachine(false), encodingChange(false), formatChange(false),
+    reverseConnection(false), lastUsedEncoding_(encodingRaw), isClosed_(false) {
+}
+
+CConn::~CConn() {
+  delete window;
+}
+
+bool CConn::initialise(network::Socket* s, bool reverse) {
+  // Set the server's name for MRU purposes
+  CharArray endpoint(s->getPeerEndpoint());
+  setServerName(endpoint.buf);
+  if (!options.host.buf)
+    options.setHost(endpoint.buf);
+
+  // Initialise the underlying CConnection
+  setStreams(&s->inStream(), &s->outStream());
+
+  // Enable processing of window messages while blocked on I/O
+  s->inStream().setBlockCallback(this);
+
+  // Initialise the viewer options
+  applyOptions(options);
+
+  // - Set which auth schemes we support, in order of preference
+  addSecType(secTypeVncAuth);
+  addSecType(secTypeNone);
+
+  // Start the RFB protocol
+  sock = s;
+  reverseConnection = reverse;
+  initialiseProtocol();
+
+  m_fileTransfer.initialize(&s->inStream(), &s->outStream());
+
+  return true;
+}
+
+
+void
+CConn::applyOptions(CConnOptions& opt) {
+  // - If any encoding-related settings have changed then we must
+  //   notify the server of the new settings
+  encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) ||
+                     (options.useDesktopResize != opt.useDesktopResize) ||
+                     (options.customCompressLevel != opt.customCompressLevel) ||
+                     (options.compressLevel != opt.compressLevel) ||
+                     (options.noJpeg != opt.noJpeg) ||
+                     (options.qualityLevel != opt.qualityLevel) ||
+                     (options.preferredEncoding != opt.preferredEncoding));
+
+  // - If the preferred pixel format has changed then notify the server
+  formatChange |= (options.fullColour != opt.fullColour);
+  if (!opt.fullColour)
+    formatChange |= (options.lowColourLevel != opt.lowColourLevel);
+
+  // - Save the new set of options
+  options = opt;
+
+  // - Set optional features in ConnParams
+  cp.supportsLocalCursor = options.useLocalCursor;
+  cp.supportsDesktopResize = options.useDesktopResize;
+  cp.customCompressLevel = options.customCompressLevel;
+  cp.compressLevel = options.compressLevel;
+  cp.noJpeg = options.noJpeg;
+  cp.qualityLevel = options.qualityLevel;
+
+  // - Configure connection sharing on/off
+  setShared(options.shared);
+
+  // - Whether to use protocol 3.3 for legacy compatibility
+  setProtocol3_3(options.protocol3_3);
+
+  // - Apply settings that affect the window, if it is visible
+  if (window) {
+    window->setMonitor(options.monitor.buf);
+    window->setFullscreen(options.fullScreen);
+    window->setEmulate3(options.emulate3);
+    window->setPointerEventInterval(options.pointerEventInterval);
+    window->setMenuKey(options.menuKey);
+    window->setDisableWinKeys(options.disableWinKeys);
+    window->setShowToolbar(options.showToolbar);
+    if (!options.useLocalCursor)
+      window->setCursor(0, 0, Point(), 0, 0);
+  }
+}
+
+
+void
+CConn::displayChanged() {
+  // Display format has changed - recalculate the full-colour pixel format
+  calculateFullColourPF();
+}
+
+void
+CConn::paintCompleted() {
+  // A repaint message has just completed - request next update if necessary
+  requestNewUpdate();
+}
+
+bool
+CConn::sysCommand(WPARAM wParam, LPARAM lParam) {
+  // - If it's one of our (F8 Menu) messages
+  switch (wParam) {
+  case IDM_FULLSCREEN:
+    options.fullScreen = !window->isFullscreen();
+    window->setFullscreen(options.fullScreen);
+    return true;
+  case IDM_SHOW_TOOLBAR:
+    options.showToolbar = !window->isToolbarEnabled();
+    window->setShowToolbar(options.showToolbar);
+    return true;
+  case IDM_CTRL_KEY:
+    window->kbd.keyEvent(this, VK_CONTROL, 0, !window->kbd.keyPressed(VK_CONTROL));
+    return true;
+  case IDM_ALT_KEY:
+    window->kbd.keyEvent(this, VK_MENU, 0, !window->kbd.keyPressed(VK_MENU));
+    return true;
+  case IDM_SEND_MENU_KEY:
+    window->kbd.keyEvent(this, options.menuKey, 0, true);
+    window->kbd.keyEvent(this, options.menuKey, 0, false);
+    return true;
+  case IDM_SEND_CAD:
+    window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+    window->kbd.keyEvent(this, VK_MENU, 0, true);
+    window->kbd.keyEvent(this, VK_DELETE, 0x1000000, true);
+    window->kbd.keyEvent(this, VK_DELETE, 0x1000000, false);
+    window->kbd.keyEvent(this, VK_MENU, 0, false);
+    window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+    return true;
+  case IDM_SEND_CTLESC:
+    window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+    window->kbd.keyEvent(this, VK_ESCAPE, 0, true);
+    window->kbd.keyEvent(this, VK_ESCAPE, 0, false);
+    window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+    return true;
+  case IDM_REQUEST_REFRESH:
+    try {
+      writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false);
+      requestUpdate = false;
+    } catch (rdr::Exception& e) {
+      close(e.str());
+    }
+    return true;
+  case IDM_NEWCONN:
+    {
+      Thread* newThread = new CConnThread;
+    }
+    return true;
+  case IDM_OPTIONS:
+    // Update the monitor device name in the CConnOptions instance
+    options.monitor.replaceBuf(window->getMonitor());
+    showOptionsDialog();
+    return true;
+  case IDM_INFO:
+    infoDialog.showDialog(this);
+    return true;
+  case IDM_ABOUT:
+    AboutDialog::instance.showDialog();
+    return true;
+  case IDM_FILE_TRANSFER:
+    m_fileTransfer.show(window->getHandle());
+    return true;
+  case IDM_CONN_SAVE_AS:
+    return true;
+  case ID_CLOSE:
+    // FIXME: Remove the corresponding toolbar button.
+    return true;
+  };
+  return false;
+}
+
+
+void
+CConn::closeWindow() {
+  vlog.info("window closed");
+  close();
+}
+
+
+void
+CConn::refreshMenu(bool enableSysItems) {
+  HMENU menu = GetSystemMenu(window->getHandle(), FALSE);
+
+  if (!enableSysItems) {
+    // Gray out menu items that might cause a World Of Pain
+    EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
+    EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
+    EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
+    EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
+    EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);
+  }
+
+  // Update the modifier key menu items
+  UINT ctrlCheckFlags = window->kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED;
+  UINT altCheckFlags = window->kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED;
+  CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags);
+  CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags);
+
+  // Ensure that the Send <MenuKey> menu item has the correct text
+  if (options.menuKey) {
+    TCharArray menuKeyStr(options.menuKeyName());
+    TCharArray tmp(_tcslen(menuKeyStr.buf) + 6);
+    _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf);
+    if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf))
+      InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf);
+  } else {
+    RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND);
+  }
+
+  // Set the menu fullscreen option tick
+  CheckMenuItem(menu, IDM_FULLSCREEN, (window->isFullscreen() ? MF_CHECKED : 0) | MF_BYCOMMAND);
+
+  // Set the menu toolbar option tick
+  int toolbarFlags = window->isToolbarEnabled() ? MF_CHECKED : 0;
+  CheckMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+
+  // In the full-screen mode, "Show toolbar" should be grayed.
+  toolbarFlags = window->isFullscreen() ? MF_GRAYED : MF_ENABLED;
+  EnableMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+}
+
+
+void
+CConn::blockCallback() {
+  // - An InStream has blocked on I/O while processing an RFB message
+  //   We re-enable socket event notifications, so we'll know when more
+  //   data is available, then we sit and dispatch window events until
+  //   the notification arrives.
+  if (!isClosed()) {
+    if (WSAEventSelect(sock->getFd(), sockEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
+      throw rdr::SystemException("Unable to wait for sokcet data", WSAGetLastError());
+  }
+  while (true) {
+    // If we have closed then we can't block waiting for data
+    if (isClosed())
+      throw rdr::EndOfStream();
+
+    // Wait for socket data, or a message to process
+    DWORD result = MsgWaitForMultipleObjects(1, &sockEvent.h, FALSE, INFINITE, QS_ALLINPUT);
+    if (result == WAIT_OBJECT_0) {
+      // - Network event notification.  Return control to I/O routine.
+      break;
+    } else if (result == WAIT_FAILED) {
+      // - The wait operation failed - raise an exception
+      throw rdr::SystemException("blockCallback wait error", GetLastError());
+    }
+
+    // - There should be a message in the message queue
+    MSG msg;
+    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+      // IMPORTANT: We mustn't call TranslateMessage() here, because instead we
+      // call ToAscii() in CKeyboard::keyEvent().  ToAscii() stores dead key
+      // state from one call to the next, which would be messed up by calls to
+      // TranslateMessage() (actually it looks like TranslateMessage() calls
+      // ToAscii() internally).
+      DispatchMessage(&msg);
+    }
+  }
+
+  // Before we return control to the InStream, reset the network event
+  WSAEventSelect(sock->getFd(), sockEvent, 0);
+  ResetEvent(sockEvent);
+}
+
+
+void CConn::keyEvent(rdr::U32 key, bool down) {
+  if (!options.sendKeyEvents) return;
+  try {
+    writer()->keyEvent(key, down);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+void CConn::pointerEvent(const Point& pos, int buttonMask) {
+  if (!options.sendPtrEvents) return;
+  try {
+    writer()->pointerEvent(pos, buttonMask);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+void CConn::clientCutText(const char* str, int len) {
+  if (!options.clientCutText) return;
+  if (state() != RFBSTATE_NORMAL) return;
+  try {
+    writer()->clientCutText(str, len);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+
+CSecurity* CConn::getCSecurity(int secType)
+{
+  switch (secType) {
+  case secTypeNone:
+    return new CSecurityNone();
+  case secTypeVncAuth:
+    return new CSecurityVncAuth(this);
+  default:
+    throw Exception("Unsupported secType?");
+  }
+}
+
+
+void
+CConn::setColourMapEntries(int first, int count, U16* rgbs) {
+  vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+  int i;
+  for (i=0;i<count;i++)
+    window->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+  // *** change to 0, 256?
+  window->refreshWindowPalette(first, count);
+}
+
+void
+CConn::bell() {
+  if (options.acceptBell)
+    MessageBeep(-1);
+}
+
+
+void
+CConn::setDesktopSize(int w, int h) {
+  vlog.debug("setDesktopSize %dx%d", w, h);
+
+  // Resize the window's buffer
+  if (window)
+    window->setSize(w, h);
+
+  // Tell the underlying CConnection
+  CConnection::setDesktopSize(w, h);
+}
+
+void
+CConn::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+  if (!options.useLocalCursor) return;
+
+  // Set the window to use the new cursor
+  window->setCursor(w, h, hotspot, data, mask);
+}
+
+
+void
+CConn::close(const char* reason) {
+  // If already closed then ignore this
+  if (isClosed())
+    return;
+
+  // Hide the window, if it exists
+  if (window)
+    ShowWindow(window->getHandle(), SW_HIDE);
+
+  // Save the reason & flag that we're closed & shutdown the socket
+  isClosed_ = true;
+  closeReason_.replaceBuf(strDup(reason));
+  sock->shutdown();
+}
+
+
+void
+CConn::showOptionsDialog() {
+  optionsDialog.showDialog(this);
+}
+
+
+void
+CConn::framebufferUpdateEnd() {
+  if (debugDelay != 0) {
+    vlog.debug("debug delay %d",(int)debugDelay);
+    UpdateWindow(window->getHandle());
+    Sleep(debugDelay);
+    std::list<rfb::Rect>::iterator i;
+    for (i = debugRects.begin(); i != debugRects.end(); i++) {
+      window->invertRect(*i);
+    }
+    debugRects.clear();
+  }
+  if (options.autoSelect)
+    autoSelectFormatAndEncoding();
+
+  // Always request the next update
+  requestUpdate = true;
+
+  // Check that at least part of the window has changed
+  if (!GetUpdateRect(window->getHandle(), 0, FALSE)) {
+    if (!(GetWindowLong(window->getHandle(), GWL_STYLE) & WS_MINIMIZE))
+      requestNewUpdate();
+  }
+
+  // Make sure the local cursor is shown
+  window->showCursor();
+}
+
+
+// Note: The method below is duplicated in vncviewer_unix/CConn.cxx!
+
+// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+// to the connection speed:
+//
+//   Above 16Mbps (timing for at least a second), switch to hextile
+//   Otherwise, switch to ZRLE
+//
+//   Above 256Kbps, use full colour mode
+//
+void
+CConn::autoSelectFormatAndEncoding() {
+  int kbitsPerSecond = sock->inStream().kbitsPerSecond();
+  unsigned int newEncoding = options.preferredEncoding;
+
+  bool newFullColour = options.fullColour;
+  unsigned int timeWaited = sock->inStream().timeWaited();
+
+  // Select best encoding
+  if (kbitsPerSecond > 16000 && timeWaited >= 10000) {
+    newEncoding = encodingHextile;
+  } else {
+    newEncoding = encodingZRLE;
+  }
+
+  if (newEncoding != options.preferredEncoding) {
+    vlog.info("Throughput %d kbit/s - changing to %s encoding",
+            kbitsPerSecond, encodingName(newEncoding));
+    options.preferredEncoding = newEncoding;
+    encodingChange = true;
+  }
+
+  if (kbitsPerSecond == 0) {
+    return;
+  }
+
+  if (cp.beforeVersion(3, 8)) {
+    // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+    // cursors "asynchronously". If this happens in the middle of a
+    // pixel format change, the server will encode the cursor with
+    // the old format, but the client will try to decode it
+    // according to the new format. This will lead to a
+    // crash. Therefore, we do not allow automatic format change for
+    // old servers.
+    return;
+  }
+  
+  // Select best color level
+  newFullColour = (kbitsPerSecond > 256);
+  if (newFullColour != options.fullColour) {
+    vlog.info("Throughput %d kbit/s - full color is now %s", 
+              kbitsPerSecond,
+              newFullColour ? "enabled" : "disabled");
+    options.fullColour = newFullColour;
+    formatChange = true;
+  }
+}
+
+void
+CConn::requestNewUpdate() {
+  if (!requestUpdate) return;
+
+  if (formatChange) {
+    // Select the required pixel format
+    if (options.fullColour) {
+      window->setPF(fullColourPF);
+    } else {
+      switch (options.lowColourLevel) {
+      case 0:
+        window->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0));
+        break;
+      case 1:
+        window->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0));
+        break;
+      case 2:
+        window->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0));
+        break;
+      }
+    }
+
+    // Print the current pixel format
+    char str[256];
+    window->getPF().print(str, 256);
+    vlog.info("Using pixel format %s",str);
+
+    // Save the connection pixel format and tell server to use it
+    cp.setPF(window->getPF());
+    writer()->writeSetPixelFormat(cp.pf());
+
+    // Correct the local window's palette
+    if (!window->getNativePF().trueColour)
+      window->refreshWindowPalette(0, 1 << cp.pf().depth);
+  }
+
+  if (encodingChange) {
+    vlog.info("Using %s encoding",encodingName(options.preferredEncoding));
+    writer()->writeSetEncodings(options.preferredEncoding, true);
+  }
+
+  writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
+                                          !formatChange);
+
+  encodingChange = formatChange = requestUpdate = false;
+}
+
+
+void
+CConn::calculateFullColourPF() {
+  // If the server is palette based then use palette locally
+  // Also, don't bother doing bgr222
+  if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) {
+    fullColourPF = serverDefaultPF;
+    options.fullColour = true;
+  } else {
+    // If server is trueColour, use lowest depth PF
+    PixelFormat native = window->getNativePF();
+    if ((serverDefaultPF.bpp < native.bpp) ||
+        ((serverDefaultPF.bpp == native.bpp) &&
+        (serverDefaultPF.depth < native.depth)))
+      fullColourPF = serverDefaultPF;
+    else
+      fullColourPF = window->getNativePF();
+  }
+  formatChange = true;
+}
+
+
+void
+CConn::setName(const char* name) {
+  if (window)
+    window->setName(name);
+  CConnection::setName(name);
+}
+
+
+void CConn::serverInit() {
+  CConnection::serverInit();
+
+  // If using AutoSelect with old servers, start in FullColor
+  // mode. See comment in autoSelectFormatAndEncoding. 
+  if (cp.beforeVersion(3, 8) && options.autoSelect) {
+    options.fullColour = true;
+  }
+
+  // Show the window
+  window = new DesktopWindow(this);
+  window->setName(cp.name());
+  window->setSize(cp.width, cp.height);
+  applyOptions(options);
+
+  // Save the server's current format
+  serverDefaultPF = cp.pf();
+
+  // Calculate the full-colour format to use
+  calculateFullColourPF();
+
+  // Request the initial update
+  vlog.info("requesting initial update");
+  formatChange = encodingChange = requestUpdate = true;
+  requestNewUpdate();
+
+  // Update the window menu
+  HMENU wndmenu = GetSystemMenu(window->getHandle(), FALSE);
+  int toolbarChecked = options.showToolbar ? MF_CHECKED : 0;
+
+  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+  AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen"));
+  AppendMenu(wndmenu, MF_STRING | toolbarChecked, IDM_SHOW_TOOLBAR,
+             _T("Show tool&bar"));
+  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+  AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l"));
+  AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t"));
+  AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del"));
+  AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc"));
+  AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen"));
+  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+  AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection..."));
+  AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options..."));
+  AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info..."));
+  AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About..."));
+}
+
+void
+CConn::serverCutText(const char* str, int len) {
+  if (!options.serverCutText) return;
+  window->serverCutText(str, len);
+}
+
+
+void CConn::beginRect(const Rect& r, unsigned int encoding) {
+  sock->inStream().startTiming();
+}
+
+void CConn::endRect(const Rect& r, unsigned int encoding) {
+  sock->inStream().stopTiming();
+  lastUsedEncoding_ = encoding;
+  if (debugDelay != 0) {
+    window->invertRect(r);
+    debugRects.push_back(r);
+  }
+}
+
+void CConn::fillRect(const Rect& r, Pixel pix) {
+  window->fillRect(r, pix);
+}
+void CConn::imageRect(const Rect& r, void* pixels) {
+  window->imageRect(r, pixels);
+}
+void CConn::copyRect(const Rect& r, int srcX, int srcY) {
+  window->copyRect(r, srcX, srcY);
+}
+
+void CConn::getUserPasswd(char** user, char** password) {
+  if (!user && options.passwordFile.buf[0]) {
+    FILE* fp = fopen(options.passwordFile.buf, "rb");
+    if (fp) {
+      char data[256];
+      int datalen = fread(data, 1, 256, fp);
+      fclose(fp);
+      if (datalen == 8) {
+	ObfuscatedPasswd obfPwd;
+	obfPwd.buf = data;
+	obfPwd.length  = datalen; 
+	PlainPasswd passwd(obfPwd);
+	*password = strDup(passwd.buf);
+	memset(data, 0, strlen(data));
+      }
+    }
+  }
+  if (user && options.userName.buf)
+    *user = strDup(options.userName.buf);
+  if (password && options.password.buf)
+    *password = strDup(options.password.buf);
+  if ((user && !*user) || (password && !*password)) {
+    // Missing username or password - prompt the user
+    UserPasswdDialog userPasswdDialog;
+    userPasswdDialog.setCSecurity(getCurrentCSecurity());
+    userPasswdDialog.getUserPasswd(user, password);
+  }
+  if (user) options.setUserName(*user);
+  if (password) options.setPassword(*password);
+}
+
+bool CConn::processFTMsg(int type) {
+  return m_fileTransfer.processFTMsg(type);
+}
diff --git a/win/vncviewer/CConn.h b/win/vncviewer/CConn.h
new file mode 100644
index 0000000..29023f3
--- /dev/null
+++ b/win/vncviewer/CConn.h
@@ -0,0 +1,165 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- CConn.h
+
+// Windows-specific implementation of CConnection
+
+#ifndef __RFB_WIN32_CCONN_H__
+#define __RFB_WIN32_CCONN_H__
+
+#include <network/Socket.h>
+#include <rfb/CConnection.h>
+#include <rfb/Cursor.h>
+#include <rfb/UserPasswdGetter.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Handle.h>
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConnOptions.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/FileTransfer.h>
+#include <list>
+
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConn : public CConnection,
+                  UserPasswdGetter,
+                  DesktopWindow::Callback,
+                  rdr::FdInStreamBlockCallback
+    {
+    public:
+      CConn();
+      ~CConn();
+
+      // - Start the VNC session on the supplied socket
+      //   The socket must already be connected to a host
+      bool initialise(network::Socket* s, bool reverse=false);
+
+      // - Set/get the session options
+      void applyOptions(CConnOptions& opt);
+      const CConnOptions& getOptions() const { return options; };
+
+      // - Show the options dialog for the connection
+      void showOptionsDialog();
+
+      // - Close the socket & set the reason for closure
+      void close(const char* reason=0);
+      bool isClosed() const { return isClosed_; }
+      const char* closeReason() const { return closeReason_.buf; }
+
+      // - Last received encoding, for the Info dialog
+      int lastUsedEncoding() const { return lastUsedEncoding_; }
+
+      // - Get at the DesktopWindow, if any
+      DesktopWindow* getWindow() { return window; }
+
+      // - Get at the underlying Socket
+      network::Socket* getSocket() { return sock; }
+
+      // - Get the server's preferred format
+      const PixelFormat& getServerDefaultPF() const { return serverDefaultPF; }
+
+      // Global user-config registry key
+      static RegKey userConfigKey;
+
+      bool processFTMsg(int type);
+
+    protected:
+      // InputHandler interface (via DesktopWindow::Callback)
+      void keyEvent(rdr::U32 key, bool down);
+      void pointerEvent(const Point& pos, int buttonMask);
+      void clientCutText(const char* str, int len);
+
+      // DesktopWindow::Callback interface
+      void displayChanged();
+      void paintCompleted();
+      bool sysCommand(WPARAM wParam, LPARAM lParam);
+      void closeWindow();
+      void refreshMenu(bool enableSysCommands);
+
+      // CConnection interface
+      CSecurity* getCSecurity(int secType);
+      void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
+      void bell();
+      void framebufferUpdateEnd();
+      void setDesktopSize(int w, int h);
+      void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+      void setName(const char* name);
+      void serverInit();
+      void serverCutText(const char* str, int len);
+      void beginRect(const Rect& r, unsigned int encoding);
+      void endRect(const Rect& r, unsigned int encoding);
+      void fillRect(const Rect& r, Pixel pix);
+      void imageRect(const Rect& r, void* pixels);
+      void copyRect(const Rect& r, int srcX, int srcY);
+
+      // rdr::FdInStreamBlockCallback interface
+      void blockCallback();
+
+      // UserPasswdGetter interface
+      // (overridden to allow a pre-supplied username & password)
+      void getUserPasswd(char** user, char** password);
+
+      // CConn-specific internal interface
+      void autoSelectFormatAndEncoding();
+      void requestNewUpdate();
+      void calculateFullColourPF();
+
+      // The desktop window
+      DesktopWindow* window;
+
+      // Info and Options dialogs
+      OptionsDialog optionsDialog;
+      InfoDialog infoDialog;
+
+      // VNC Viewer options
+      CConnOptions options;
+
+      // Pixel format and encoding
+      PixelFormat serverDefaultPF;
+      PixelFormat fullColourPF;
+      bool sameMachine;
+      bool encodingChange;
+      bool formatChange;
+      int lastUsedEncoding_;
+
+      // Networking and RFB protocol
+      network::Socket* sock;
+      Handle sockEvent;
+      bool reverseConnection;
+      bool requestUpdate;
+
+      // Debugging/logging
+      std::list<Rect> debugRects;
+      CharArray closeReason_;
+      bool isClosed_;
+
+      FileTransfer m_fileTransfer;
+    };
+
+  };
+
+};
+
+#endif
+
+
diff --git a/win/vncviewer/CConnOptions.cxx b/win/vncviewer/CConnOptions.cxx
new file mode 100644
index 0000000..4ea0ada
--- /dev/null
+++ b/win/vncviewer/CConnOptions.cxx
@@ -0,0 +1,450 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+#include <vncviewer/CConnOptions.h>
+#include <rfb/Configuration.h>
+#include <rfb/encodings.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/Registry.h>
+#include <rdr/HexInStream.h>
+#include <rdr/HexOutStream.h>
+#include <stdlib.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static StringParameter passwordFile("PasswordFile",
+				    "Password file for VNC authentication", "");
+
+// - Settings stored in the registry & in .vnc files, by Save Defaults and
+//   Save Configuration respectively.
+
+static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
+static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
+
+static BoolParameter fullColour("FullColor",
+				"Use full color", true);
+static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
+
+static IntParameter lowColourLevel("LowColorLevel",
+                         "Color level to use on slow connections. "
+                         "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
+                         2);
+static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
+
+static BoolParameter fullScreen("FullScreen",
+                         "Use the whole display to show the remote desktop."
+                         "(Press F8 to access the viewer menu)",
+                         false);
+static StringParameter preferredEncoding("PreferredEncoding",
+					 "Preferred encoding to use (Tight, ZRLE, Hextile or"
+					 " Raw)", "Tight");
+static BoolParameter autoSelect("AutoSelect", 
+				"Auto select pixel format and encoding. "
+				"Default if PreferredEncoding and FullColor are not specified.", 
+				true);
+static BoolParameter sharedConnection("Shared",
+                         "Allow existing connections to the server to continue."
+                         "(Default is to disconnect all other clients)",
+                         false);
+
+static BoolParameter sendPtrEvents("SendPointerEvents",
+                         "Send pointer (mouse) events to the server.", true);
+static BoolParameter sendKeyEvents("SendKeyEvents",
+                         "Send key presses (and releases) to the server.", true);
+
+static BoolParameter clientCutText("ClientCutText",
+                         "Send clipboard changes to the server.", true);
+static BoolParameter serverCutText("ServerCutText",
+                         "Accept clipboard changes from the server.", true);
+
+static BoolParameter disableWinKeys("DisableWinKeys",
+                         "Pass special Windows keys directly to the server.", true);
+
+static BoolParameter protocol3_3("Protocol3.3",
+                         "Only use protocol version 3.3", false);
+
+static IntParameter ptrEventInterval("PointerEventInterval",
+                         "The interval to delay between sending one pointer event "
+                         "and the next.", 0);
+static BoolParameter emulate3("Emulate3",
+                         "Emulate middle mouse button when left and right buttons "
+                         "are used simulatenously.", false);
+
+static BoolParameter acceptBell("AcceptBell",
+                         "Produce a system beep when requested to by the server.",
+                         true);
+
+static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true);
+
+static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
+static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
+static BoolParameter autoReconnect("AutoReconnect", "Offer to reconnect to the remote server if the connection"
+                                   "is dropped because an error occurs.", true);
+
+static BoolParameter customCompressLevel("CustomCompressLevel",
+					 "Use custom compression level. "
+					 "Default if CompressLevel is specified.", false);
+
+static IntParameter compressLevel("CompressLevel",
+				  "Use specified compression level"
+				  "0 = Low, 9 = High",
+				  6);
+
+static BoolParameter noJpeg("NoJPEG",
+			    "Disable lossy JPEG compression in Tight encoding.",
+			    false);
+
+static IntParameter qualityLevel("QualityLevel",
+				 "JPEG quality level. "
+				 "0 = Low, 9 = High",
+				 6);
+
+CConnOptions::CConnOptions()
+: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
+autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
+preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
+disableWinKeys(::disableWinKeys), protocol3_3(::protocol3_3), acceptBell(::acceptBell),
+lowColourLevel(::lowColourLevel), pointerEventInterval(ptrEventInterval),
+emulate3(::emulate3), monitor(::monitor.getData()), showToolbar(::showToolbar),
+customCompressLevel(::customCompressLevel), compressLevel(::compressLevel), 
+noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData()),
+autoReconnect(::autoReconnect)
+{
+  if (autoSelect) {
+    preferredEncoding = encodingZRLE;
+  } else {
+    CharArray encodingName(::preferredEncoding.getData());
+    preferredEncoding = encodingNum(encodingName.buf);
+  }
+  setMenuKey(CharArray(::menuKey.getData()).buf);
+
+  if (!::autoSelect.hasBeenSet()) {
+      // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
+    autoSelect = (!::preferredEncoding.hasBeenSet() 
+		  && !::fullColour.hasBeenSet()
+		  && !::fullColourAlias.hasBeenSet());
+  }
+  if (!::customCompressLevel.hasBeenSet()) {
+    // Default to CustomCompressLevel=1 if CompressLevel is used.
+    customCompressLevel = ::compressLevel.hasBeenSet();
+  }
+}
+
+
+void CConnOptions::readFromFile(const char* filename) {
+  FILE* f = fopen(filename, "r");
+  if (!f)
+    throw rdr::Exception("Failed to read configuration file");
+
+  try { 
+    char line[4096];
+    CharArray section;
+
+    CharArray hostTmp;
+    int portTmp = 0;
+
+    while (!feof(f)) {
+      // Read the next line
+      if (!fgets(line, sizeof(line), f)) {
+        if (feof(f))
+          break;
+        throw rdr::SystemException("fgets", ferror(f));
+      }
+      int len=strlen(line);
+      if (line[len-1] == '\n') {
+        line[len-1] = 0;
+        len--;
+      }
+
+      // Process the line
+      if (line[0] == ';') {
+        // Comment
+      } else if (line[0] == '[') {
+        // Entering a new section
+        if (!strSplit(&line[1], ']', &section.buf, 0))
+          throw rdr::Exception("bad Section");
+      } else {
+        // Reading an option
+        CharArray name;
+        CharArray value;
+        if (!strSplit(line, '=', &name.buf, &value.buf))
+          throw rdr::Exception("bad Name/Value pair");
+
+        if (stricmp(section.buf, "Connection") == 0) {
+          if (stricmp(name.buf, "Host") == 0) {
+            hostTmp.replaceBuf(value.takeBuf());
+          } else if (stricmp(name.buf, "Port") == 0) {
+            portTmp = atoi(value.buf);
+          } else if (stricmp(name.buf, "UserName") == 0) {
+            userName.replaceBuf(value.takeBuf());
+          } else if (stricmp(name.buf, "Password") == 0) {
+            ObfuscatedPasswd obfPwd;
+            rdr::HexInStream::hexStrToBin(value.buf, (char**)&obfPwd.buf, &obfPwd.length);
+            PlainPasswd passwd(obfPwd);
+            password.replaceBuf(passwd.takeBuf());
+          }
+        } else if (stricmp(section.buf, "Options") == 0) {
+            // V4 options
+          if (stricmp(name.buf, "UseLocalCursor") == 0) {
+            useLocalCursor = atoi(value.buf);
+          } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
+            useDesktopResize = atoi(value.buf);
+          } else if (stricmp(name.buf, "FullScreen") == 0) {
+            fullScreen = atoi(value.buf);
+          } else if (stricmp(name.buf, "FullColour") == 0) {
+            fullColour = atoi(value.buf);
+          } else if (stricmp(name.buf, "LowColourLevel") == 0) {
+            lowColourLevel = atoi(value.buf);
+          } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
+            preferredEncoding = encodingNum(value.buf);
+          } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
+                     (stricmp(name.buf, "AutoSelect") == 0)) {
+            autoSelect = atoi(value.buf);
+          } else if (stricmp(name.buf, "Shared") == 0) {
+            shared = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
+            sendPtrEvents = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
+            sendKeyEvents = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendCutText") == 0) {
+            clientCutText = atoi(value.buf);
+          } else if (stricmp(name.buf, "AcceptCutText") == 0) {
+            serverCutText = atoi(value.buf);
+          } else if (stricmp(name.buf, "DisableWinKeys") == 0) {
+            disableWinKeys = atoi(value.buf);
+          } else if (stricmp(name.buf, "AcceptBell") == 0) {
+            acceptBell = atoi(value.buf);
+          } else if (stricmp(name.buf, "Emulate3") == 0) {
+            emulate3 = atoi(value.buf);
+          } else if (stricmp(name.buf, "ShowToolbar") == 0) {
+            showToolbar = atoi(value.buf);
+          } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
+            pointerEventInterval = atoi(value.buf);
+          } else if (stricmp(name.buf, "Monitor") == 0) {
+            monitor.replaceBuf(value.takeBuf());
+          } else if (stricmp(name.buf, "MenuKey") == 0) {
+            setMenuKey(value.buf);
+          } else if (stricmp(name.buf, "AutoReconnect") == 0) {
+            autoReconnect = atoi(value.buf);
+
+          } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
+	    customCompressLevel = atoi(value.buf);
+          } else if (stricmp(name.buf, "CompressLevel") == 0) {
+	    compressLevel = atoi(value.buf);
+          } else if (stricmp(name.buf, "NoJPEG") == 0) {
+	    noJpeg = atoi(value.buf);
+          } else if (stricmp(name.buf, "QualityLevel") == 0) {
+	    qualityLevel = atoi(value.buf);
+            // Legacy options
+          } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
+            preferredEncoding = atoi(value.buf);
+          } else if (stricmp(name.buf, "8bit") == 0) {
+            fullColour = !atoi(value.buf);
+          } else if (stricmp(name.buf, "FullScreen") == 0) {
+            fullScreen = atoi(value.buf);
+          } else if (stricmp(name.buf, "ViewOnly") == 0) {
+            sendPtrEvents = sendKeyEvents = !atoi(value.buf);
+          } else if (stricmp(name.buf, "DisableClipboard") == 0) {
+            clientCutText = serverCutText = !atoi(value.buf);
+          }
+        }
+      }
+    }
+    fclose(f); f=0;
+
+    // Process the Host and Port
+    if (hostTmp.buf) {
+      int hostLen = strlen(hostTmp.buf) + 2 + 17;
+      host.replaceBuf(new char[hostLen]);
+      strCopy(host.buf, hostTmp.buf, hostLen);
+      if (portTmp) {
+        strncat(host.buf, "::", hostLen-1);
+        char tmp[16];
+        sprintf(tmp, "%d", portTmp);
+        strncat(host.buf, tmp, hostLen-1);
+      }
+    }
+
+    // If AutoSelect is enabled then override the preferred encoding
+    if (autoSelect)
+      preferredEncoding = encodingZRLE;
+
+    setConfigFileName(filename);
+  } catch (rdr::Exception&) {
+    if (f) fclose(f);
+    throw;
+  }
+}
+
+void CConnOptions::writeToFile(const char* filename) {
+  FILE* f = fopen(filename, "w");
+  if (!f)
+    throw rdr::Exception("Failed to write configuration file");
+
+  try {
+    // - Split server into host and port and save
+    fprintf(f, "[Connection]\n");
+
+    fprintf(f, "Host=%s\n", host.buf);
+    if (userName.buf)
+      fprintf(f, "UserName=%s\n", userName.buf);
+    if (password.buf) {
+      // - Warn the user before saving the password
+      if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
+                    _T("Storing the password is more convenient but poses a security risk."),
+                    MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
+        ObfuscatedPasswd obfPwd(password);
+        CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length);
+        fprintf(f, "Password=%s\n", obfuscatedHex.buf);
+      }
+    }
+
+    // - Save the other options
+    fprintf(f, "[Options]\n");
+
+    fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
+    fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
+    fprintf(f, "FullScreen=%d\n", (int)fullScreen);
+    fprintf(f, "FullColour=%d\n", (int)fullColour);
+    fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
+    fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
+    fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
+    fprintf(f, "Shared=%d\n", (int)shared);
+    fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
+    fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
+    fprintf(f, "SendCutText=%d\n", (int)clientCutText);
+    fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
+    fprintf(f, "DisableWinKeys=%d\n", (int)disableWinKeys);
+    fprintf(f, "AcceptBell=%d\n", (int)acceptBell);
+    fprintf(f, "Emulate3=%d\n", (int)emulate3);
+    fprintf(f, "ShowToolbar=%d\n", (int)showToolbar);
+    fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
+    if (monitor.buf)
+      fprintf(f, "Monitor=%s\n", monitor.buf);
+    fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
+    fprintf(f, "AutoReconnect=%d\n", (int)autoReconnect);
+    fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
+    fprintf(f, "CompressLevel=%d\n", compressLevel);
+    fprintf(f, "NoJPEG=%d\n", noJpeg);
+    fprintf(f, "QualityLevel=%d\n", qualityLevel);
+    fclose(f); f=0;
+
+    setConfigFileName(filename);
+  } catch (rdr::Exception&) {
+    if (f) fclose(f);
+    throw;
+  }
+}
+
+
+void CConnOptions::writeDefaults() {
+  RegKey key;
+  key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
+  key.setBool(_T("UseLocalCursor"), useLocalCursor);
+  key.setBool(_T("UseDesktopResize"), useDesktopResize);
+  key.setBool(_T("FullScreen"), fullScreen);
+  key.setBool(_T("FullColour"), fullColour);
+  key.setInt(_T("LowColourLevel"), lowColourLevel);
+  key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
+  key.setBool(_T("AutoSelect"), autoSelect);
+  key.setBool(_T("Shared"), shared);
+  key.setBool(_T("SendPointerEvents"), sendPtrEvents);
+  key.setBool(_T("SendKeyEvents"), sendKeyEvents);
+  key.setBool(_T("ClientCutText"), clientCutText);
+  key.setBool(_T("ServerCutText"), serverCutText);
+  key.setBool(_T("DisableWinKeys"), disableWinKeys);
+  key.setBool(_T("Protocol3.3"), protocol3_3);
+  key.setBool(_T("AcceptBell"), acceptBell);
+  key.setBool(_T("ShowToolbar"), showToolbar);
+  key.setBool(_T("Emulate3"), emulate3);
+  key.setInt(_T("PointerEventInterval"), pointerEventInterval);
+  if (monitor.buf)
+    key.setString(_T("Monitor"), TStr(monitor.buf));
+  key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
+  key.setBool(_T("AutoReconnect"), autoReconnect);
+  key.setInt(_T("CustomCompressLevel"), customCompressLevel);
+  key.setInt(_T("CompressLevel"), compressLevel);
+  key.setInt(_T("NoJPEG"), noJpeg);
+  key.setInt(_T("QualityLevel"), qualityLevel);
+}
+
+
+void CConnOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
+void CConnOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
+void CConnOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
+void CConnOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
+void CConnOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
+
+void CConnOptions::setMenuKey(const char* keyName) {
+  if (!keyName[0]) {
+    menuKey = 0;
+  } else {
+    menuKey = VK_F8;
+    if (keyName[0] == 'F') {
+      UINT fKey = atoi(&keyName[1]);
+      if (fKey >= 1 && fKey <= 12)
+        menuKey = fKey-1 + VK_F1;
+    }
+  }
+}
+char* CConnOptions::menuKeyName() {
+  int fNum = (menuKey-VK_F1)+1;
+  if (fNum<1 || fNum>12)
+    return strDup("");
+  CharArray menuKeyStr(4);
+  sprintf(menuKeyStr.buf, "F%d", fNum);
+  return menuKeyStr.takeBuf();
+}
+
+
+CConnOptions& CConnOptions::operator=(const CConnOptions& o) {
+  useLocalCursor = o.useLocalCursor;
+  useDesktopResize = o.useDesktopResize;
+  fullScreen = o.fullScreen;
+  fullColour = o.fullColour;
+  lowColourLevel = o.lowColourLevel;
+  preferredEncoding = o.preferredEncoding;
+  autoSelect = o.autoSelect;
+  shared = o.shared;
+  sendPtrEvents = o.sendPtrEvents;
+  sendKeyEvents = o.sendKeyEvents;
+  clientCutText = o.clientCutText;
+  serverCutText = o.serverCutText;
+  disableWinKeys = o.disableWinKeys;
+  emulate3 = o.emulate3;
+  pointerEventInterval = o.pointerEventInterval;
+  protocol3_3 = o.protocol3_3;
+  acceptBell = o.acceptBell;
+  showToolbar = o.showToolbar;
+  setUserName(o.userName.buf);
+  setPassword(o.password.buf);
+  setConfigFileName(o.configFileName.buf);
+  setHost(o.host.buf);
+  setMonitor(o.monitor.buf);
+  menuKey = o.menuKey;
+  autoReconnect = o.autoReconnect;
+  customCompressLevel = o.customCompressLevel;
+  compressLevel = o.compressLevel;
+  noJpeg = o.noJpeg;
+  qualityLevel = o.qualityLevel;
+
+  return *this;
+}
diff --git a/win/vncviewer/CConnOptions.h b/win/vncviewer/CConnOptions.h
new file mode 100644
index 0000000..59fd0a3
--- /dev/null
+++ b/win/vncviewer/CConnOptions.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- CConnOptions.h
+
+// Definition of the CConnOptions class, responsible for storing the
+// current & requested VNC Viewer options.
+
+#ifndef __RFB_WIN32_CCONN_OPTIONS_H__
+#define __RFB_WIN32_CCONN_OPTIONS_H__
+
+#include <rfb/Password.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    //
+    // -=- Options structure.  Each viewer option has a corresponding
+    //     entry in CConnOptions.  The viewer options are set by calling
+    //     CConn::applyOptions(...)
+    //     The CConnOptions structure automatically picks up the default
+    //     value of each option from the Configuration system
+    //     The readFromFile and writeFromFile methods can be used to load
+    //     and save VNC configuration files.  readFromFile is backwards
+    //     compatible with 3.3 releases, while writeToFile is not.
+
+    class CConnOptions {
+    public:
+      CConnOptions();
+      CConnOptions(const CConnOptions& o) {operator=(o);}
+      CConnOptions& operator=(const CConnOptions& o);
+      void readFromFile(const char* filename_);
+      void writeToFile(const char* filename_);
+      void writeDefaults();
+      bool useLocalCursor;
+      bool useDesktopResize;
+      bool fullScreen;
+      bool fullColour;
+      int lowColourLevel;
+      int preferredEncoding;
+      bool autoSelect;
+      bool shared;
+      bool sendPtrEvents;
+      bool sendKeyEvents;
+      bool showToolbar;
+      bool clientCutText;
+      bool serverCutText;
+      bool disableWinKeys;
+      bool emulate3;
+      int pointerEventInterval;
+      bool protocol3_3;
+      bool acceptBell;
+      CharArray userName;
+      void setUserName(const char* user);
+      PlainPasswd password;
+      void setPassword(const char* pwd);
+      CharArray configFileName;
+      void setConfigFileName(const char* cfn);
+      CharArray host;
+      void setHost(const char* h);
+      CharArray monitor;
+      void setMonitor(const char* m);
+      unsigned int menuKey;
+      void setMenuKey(const char* keyName);
+      char* menuKeyName();
+      bool autoReconnect;
+
+      bool customCompressLevel;
+      int compressLevel;
+      bool noJpeg;
+      int qualityLevel;
+
+      CharArray passwordFile;
+    };
+
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/CConnThread.cxx b/win/vncviewer/CConnThread.cxx
new file mode 100644
index 0000000..cfd2695
--- /dev/null
+++ b/win/vncviewer/CConnThread.cxx
@@ -0,0 +1,198 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- CConnThread.cxx
+
+// A CConnThread instance is created for each new connection.
+// The CConnThread creates the corresponding CConn instance
+// and manages it.
+
+#include <stdlib.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Hostname.h>
+#include <rfb_win32/MsgBox.h>
+#include <network/TcpSocket.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <set>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CConnThread");
+
+static std::set<CConnThread*> threads;
+static Mutex threadsLock;
+static Handle noMoreThreads(CreateEvent(0, TRUE, FALSE, 0));
+
+
+CConnThread::CConnThread() : Thread("CConnThread"), isConfig(false),
+                             sock(0), reverse(false) {
+  vlog.info("CConnThread (dialog)");
+  setDeleteAfterRun();
+  Lock l(threadsLock);
+  threads.insert(this);
+  start();
+}
+
+CConnThread::CConnThread(const char* hostOrConfig_, bool isConfig_)
+ : Thread("CConnThread"), hostOrConfig(strDup(hostOrConfig_)),
+   isConfig(isConfig_), sock(0), reverse(false) {
+  vlog.info("CConnThread (host/port)");
+  setDeleteAfterRun();
+  Lock l(threadsLock);
+  threads.insert(this);
+  start();
+}
+
+CConnThread::CConnThread(network::Socket* sock_, bool reverse_)
+ : Thread("CConnThread"), isConfig(false), sock(sock_), reverse(reverse_) {
+  vlog.info("CConnThread (reverse connection)");
+  setDeleteAfterRun();
+  Lock l(threadsLock);
+  threads.insert(this);
+  start();
+}
+
+CConnThread::~CConnThread() {
+  Lock l(threadsLock);
+  threads.erase(this);
+  if (threads.empty())
+    SetEvent(noMoreThreads);
+  delete sock;
+}
+
+
+void CConnThread::run() {
+  CConnOptions options;
+  bool reconnect;
+
+  do {
+    {
+      CConn conn;
+      reconnect = false;
+
+      // If there is no socket object then set the host & port info
+      if (!sock && !options.host.buf) {
+        try {
+          if (isConfig) {
+            // A configuration file name was specified - load it
+            CharArray filename = hostOrConfig.takeBuf();
+            options.readFromFile(filename.buf);
+          } else {
+            // An actual hostname (and possibly port) was specified
+            options.host.replaceBuf(hostOrConfig.takeBuf());
+          }
+
+          if (!options.host.buf) {
+            // No host was specified - prompt for one
+            ConnectionDialog connDlg(&conn);
+            if (!connDlg.showDialog())
+              return;
+            options = conn.getOptions();
+            options.setHost(CStr(connDlg.hostname.buf));
+          }
+        } catch (rdr::Exception& e) {
+          MsgBox(0, TStr(e.str()), MB_ICONERROR | MB_OK);
+          return;
+        }
+      }
+
+      // Apply the connection options to the CConn
+      conn.applyOptions(options);
+
+      if (!sock) {
+        // There is no existing connection - better make one
+        const char* hostAndPort = conn.getOptions().host.buf;
+
+        try {
+          ConnectingDialog dlg;
+          sock = dlg.connect(hostAndPort);
+
+          // If the connection was cancelled by the user, just quit
+          if (!sock)
+            return;
+        } catch(rdr::Exception& e) {
+          MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
+          return;
+        }
+
+        // Try to add the caller to the MRU
+        MRU::addToMRU(hostAndPort);
+      }
+
+      // Run the RFB protocol over the connected socket
+      conn.initialise(sock, reverse);
+      while (!conn.isClosed()) {
+        try {
+          conn.getInStream()->check(1,1);
+          conn.processMsg();
+        } catch (rdr::EndOfStream) {
+          if (conn.state() == CConnection::RFBSTATE_NORMAL)
+            conn.close();
+          else
+            conn.close("The connection closed unexpectedly");
+        } catch (rfb::AuthCancelledException) {
+          conn.close();
+        } catch (rfb::AuthFailureException& e) {
+          // Clear the password, in case we auto-reconnect
+          options = conn.getOptions();
+          options.password.replaceBuf(0);
+          conn.applyOptions(options);
+          conn.close(e.str());
+        } catch (rdr::Exception& e) {
+          conn.close(e.str());
+        }
+      }
+
+      // If there is a cause for closing the connection logged then display it
+      if (conn.closeReason()) {
+        reconnect = !reverse && conn.getOptions().autoReconnect;
+        if (!reconnect) {
+          MsgBox(0, TStr(conn.closeReason()), MB_ICONINFORMATION | MB_OK);
+        } else {
+          options = conn.getOptions();
+          const char* format = "%s\nDo you wish to attempt to reconnect to %s?";
+          CharArray message(strlen(conn.closeReason()) + strlen(format) +
+                            strlen(conn.getOptions().host.buf));
+          sprintf(message.buf, format, conn.closeReason(), conn.getOptions().host.buf);
+          if (MsgBox(0, TStr(message.buf), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
+            reconnect = false;
+        }
+      }
+    } // Exit the CConn's scope, implicitly destroying it & making it safe to delete the TcpSocket
+
+    // Clean up the old socket, if any
+    delete sock; sock = 0;
+  } while (reconnect);
+}
+
+
+BOOL CConnThread::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
+  while (!PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE)) {
+    DWORD result = MsgWaitForMultipleObjects(1, &noMoreThreads.h, FALSE, INFINITE, QS_ALLINPUT);
+    if (result == WAIT_OBJECT_0)
+      return FALSE;
+    else if (result == WAIT_FAILED)
+      throw rdr::SystemException("CConnThread::getMessage wait failed", GetLastError());
+  }
+  return msg->message != WM_QUIT;
+}
diff --git a/win/vncviewer/CConnThread.h b/win/vncviewer/CConnThread.h
new file mode 100644
index 0000000..7a8451c
--- /dev/null
+++ b/win/vncviewer/CConnThread.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- CConnThread.h
+
+// CConn-managing Thread implementation.
+
+#ifndef __RFB_WIN32_CCONN_THREAD_H__
+#define __RFB_WIN32_CCONN_THREAD_H__
+
+#include <network/Socket.h>
+#include <rfb/Threading.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConnThread : public Thread {
+    public:
+      CConnThread();
+      CConnThread(const char* hostOrConfig, bool isConfig=false);
+      CConnThread(network::Socket* sock, bool reverse=false);
+      ~CConnThread();
+
+      void run();
+
+      // Special getMessage call that returns FALSE if message is WM_QUIT,
+      // OR if there are no more CConnThreads running.
+      static BOOL getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg);
+    protected:
+      CharArray hostOrConfig;
+      bool isConfig;
+      network::Socket* sock;
+      bool reverse;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_CCONN_THREAD_H__
diff --git a/win/vncviewer/ConnectingDialog.cxx b/win/vncviewer/ConnectingDialog.cxx
new file mode 100644
index 0000000..60fcb66
--- /dev/null
+++ b/win/vncviewer/ConnectingDialog.cxx
@@ -0,0 +1,160 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- ConnectingDialog.cxx
+
+#include <stdlib.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/resource.h>
+#include <network/TcpSocket.h>
+#include <rfb/Threading.h>
+#include <rfb/Hostname.h>
+#include <map>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// ConnectingDialog callback
+static BOOL CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+  bool* activePtr = (bool*)GetWindowLong(hwnd, GWL_USERDATA);
+  switch (uMsg) {
+  case WM_INITDIALOG:
+    SetWindowLong(hwnd, GWL_USERDATA, lParam);
+    return TRUE;
+	case WM_COMMAND:
+	  switch (LOWORD(wParam)) {
+	  case IDCANCEL:
+      if (activePtr)
+        *activePtr = false;
+		  return TRUE;
+		}
+		break;
+	case WM_DESTROY:
+    if (activePtr)
+      *activePtr = false;
+	  return TRUE;
+	}
+	return 0;
+}
+
+
+// Global map, used by ConnectingDialog::Threads to call back to their owning
+// ConnectingDialogs, while coping with the fact that the owner may already have quit.
+static std::map<int, ConnectingDialog*> dialogs;
+static int nextDialogId = 0;
+static Mutex dialogsLock;
+
+
+// ConnectingDialog::Thread
+//   Attempts to connect to the specified host.  If the connection succeeds, the
+//   socket is saved in the owning ConnectingDialog, if still available, and the
+//   event is signalled.  If the connection fails, the Exception text is returned
+//   to the dialog.  If the dialog is already gone, the Exception/socket are discarded.
+//   NB: This thread class cleans itself up on exit - DO NOT join()!
+class ConnectingDialog::Thread : public rfb::Thread {
+public:
+  Thread(int dialogId_, const char* hostAndPort) : dialogId(dialogId_) {
+    setDeleteAfterRun();
+    getHostAndPort(hostAndPort, &host.buf, &port);
+  }
+  virtual void run() {
+    try {
+      returnSock(new network::TcpSocket(host.buf, port));
+    } catch (rdr::Exception& e) {
+      returnException(e);
+    }
+  }
+  void returnSock(network::Socket* s) {
+    Lock l(dialogsLock);
+    if (dialogs.count(dialogId)) {
+      dialogs[dialogId]->newSocket = s;
+      SetEvent(dialogs[dialogId]->readyEvent);
+    } else {
+      delete s;
+    }
+  }
+  void returnException(const rdr::Exception& e) {
+    Lock l(dialogsLock);
+    if (dialogs.count(dialogId)) {
+      dialogs[dialogId]->errMsg.replaceBuf(strDup(e.str()));
+      SetEvent(dialogs[dialogId]->readyEvent);
+    }
+  };
+  CharArray host;
+  int port;
+  int dialogId;
+};
+
+
+ConnectingDialog::ConnectingDialog() : dialog(0), readyEvent(CreateEvent(0, TRUE, FALSE, 0)),
+                                       newSocket(0), dialogId(0) {
+}
+
+network::Socket* ConnectingDialog::connect(const char* hostAndPort) {
+  Thread* connectThread = 0;
+  bool active = true;
+  errMsg.replaceBuf(0);
+  newSocket = 0;
+
+  // Get a unique dialog identifier and create the dialog window
+  {
+    Lock l(dialogsLock);
+    dialogId = ++nextDialogId;
+    dialogs[dialogId] = this;
+    dialog = CreateDialogParam(GetModuleHandle(0),
+      MAKEINTRESOURCE(IDD_CONNECTING_DLG), 0, &ConnectingDlgProc, (long)&active);
+    ShowWindow(dialog, SW_SHOW);
+    ResetEvent(readyEvent);
+  }
+
+  // Create and start the connection thread
+  try {
+    connectThread = new Thread(dialogId, hostAndPort);
+    connectThread->start();
+  } catch (rdr::Exception& e) {
+    errMsg.replaceBuf(strDup(e.str()));
+    active = false;
+  }
+
+  // Process window messages until the connection thread signals readyEvent, or the dialog is cancelled
+  while (active && (MsgWaitForMultipleObjects(1, &readyEvent.h, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)) {
+    MSG msg;
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+      DispatchMessage(&msg);
+  }
+
+  // Remove this dialog from the table
+  //   NB: If the dialog was cancelled then the thread is still running, and will only
+  //       discover that we're gone when it looks up our unique Id in the dialog table.
+  {
+    Lock l(dialogsLock);
+    dialogs.erase(dialogId);
+  }
+
+  // Close the dialog window
+  DestroyWindow(dialog); dialog=0;
+
+  // Throw the exception, if there was one
+  if (errMsg.buf)
+    throw rdr::Exception(errMsg.buf);
+
+  // Otherwise, return the socket
+  //   NB: The socket will be null if the dialog was cancelled
+  return newSocket;
+}
diff --git a/win/vncviewer/ConnectingDialog.h b/win/vncviewer/ConnectingDialog.h
new file mode 100644
index 0000000..c38b3a1
--- /dev/null
+++ b/win/vncviewer/ConnectingDialog.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- ConnectingDialog.h
+
+// ConnectingDialog instances are used to display a status dialog while a
+// connection attempt is in progress.  The connection attempt is performed
+// in a background thread by the ConnectingDialog, to allow the status dialog
+// to remain interactive.  If the dialog is cancelled then it will close and
+// the connection dialog will eventually tidy itself up.
+
+#ifndef __RFB_WIN32_CONNECTING_DLG_H__
+#define __RFB_WIN32_CONNECTING_DLG_H__
+
+#include <windows.h>
+#include <network/Socket.h>
+#include <rfb/util.h>
+#include <rfb_win32/Handle.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class ConnectingDialog {
+    public:
+      ConnectingDialog();
+
+      // connect
+      //   Show a Connecting dialog and attempt to connect to the specified host
+      //   in the background.
+      //   If the connection succeeds then the Socket is returned.
+      //   If an error occurs, an Exception is thrown.
+      //   If the dialog is cancelled then null is returned.
+      network::Socket* connect(const char* hostAndPort);
+    protected:
+      HWND dialog;
+      network::Socket* newSocket;
+      CharArray errMsg;
+      Handle readyEvent;
+      int dialogId;
+
+      class Thread;
+      friend class Thread;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/ConnectionDialog.cxx b/win/vncviewer/ConnectionDialog.cxx
new file mode 100644
index 0000000..e7c6b0a
--- /dev/null
+++ b/win/vncviewer/ConnectionDialog.cxx
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/AboutDialog.h>
+
+#include <tchar.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+ConnectionDialog::ConnectionDialog(CConn* conn_) : Dialog(GetModuleHandle(0)), conn(conn_) {
+}
+
+
+bool ConnectionDialog::showDialog() {
+  return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_DLG));
+}
+
+void ConnectionDialog::initDialog() {
+  HWND box = GetDlgItem(handle, IDC_SERVER_EDIT);
+
+  std::list<char*> mru = MRU::getEntries();
+  std::list<char*>::iterator i;
+
+  // Locate the combo-box
+  // NB: TCharArray converts the supplied char* and assumes ownership!
+  for (i=mru.begin(); i!=mru.end(); i++) {
+    int index = SendMessage(box, CB_ADDSTRING, 0, (LPARAM)TCharArray(*i).buf);
+  }
+
+  // Select the first item in the list
+  SendMessage(box, CB_SETCURSEL, 0, 0);
+
+  // Fill out the Security: drop-down and select the preferred option
+  HWND security = GetDlgItem(handle, IDC_SECURITY_LEVEL);
+  LRESULT n = SendMessage(security, CB_ADDSTRING, 0, (LPARAM)_T("Always Off"));
+  if (n != CB_ERR)
+    SendMessage(security, CB_SETCURSEL, n, 0);
+  enableItem(IDC_SECURITY_LEVEL, false);
+}
+
+
+bool ConnectionDialog::onOk() {
+  delete [] hostname.buf;
+  hostname.buf = 0;
+  hostname.buf = getItemString(IDC_SERVER_EDIT);
+  return hostname.buf[0] != 0;
+}
+
+bool ConnectionDialog::onCommand(int id, int cmd) {
+  switch (id) {
+  case IDC_ABOUT:
+    AboutDialog::instance.showDialog();
+    return true;
+  case IDC_OPTIONS:
+    conn->showOptionsDialog();
+    return true;
+  };
+  return false;
+}
diff --git a/win/vncviewer/ConnectionDialog.h b/win/vncviewer/ConnectionDialog.h
new file mode 100644
index 0000000..f739280
--- /dev/null
+++ b/win/vncviewer/ConnectionDialog.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- ConnectionDialog.h
+
+// Connection dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_CONN_DIALOG_H__
+#define __RFB_WIN32_CONN_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <vncviewer/MRU.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConn;
+
+    class ConnectionDialog : Dialog {
+    public:
+      ConnectionDialog(CConn* view);
+      virtual bool showDialog();
+      virtual void initDialog();
+      virtual bool onOk();
+      virtual bool onCommand(int id, int cmd);
+      TCharArray hostname;
+    protected:
+      CConn* conn;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/DesktopWindow.cxx b/win/vncviewer/DesktopWindow.cxx
new file mode 100644
index 0000000..27ef2dc
--- /dev/null
+++ b/win/vncviewer/DesktopWindow.cxx
@@ -0,0 +1,1103 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/LowLevelKeyEvents.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/Win32Util.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/resource.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// - Statics & consts
+
+static LogWriter vlog("DesktopWindow");
+
+const int TIMER_BUMPSCROLL = 1;
+const int TIMER_POINTER_INTERVAL = 2;
+const int TIMER_POINTER_3BUTTON = 3;
+
+
+//
+// -=- DesktopWindowClass
+
+//
+// Window class used as the basis for all DesktopWindow instances
+//
+
+class DesktopWindowClass {
+public:
+  DesktopWindowClass();
+  ~DesktopWindowClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK DesktopWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  LRESULT result;
+  if (msg == WM_CREATE)
+    SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+  else if (msg == WM_DESTROY)
+    SetWindowLong(wnd, GWL_USERDATA, 0);
+  DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %u", wnd, msg);
+    return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processMessage(msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+};
+
+static HCURSOR dotCursor = (HCURSOR)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDC_DOT_CURSOR), IMAGE_CURSOR, 0, 0, LR_SHARED);
+static HCURSOR arrowCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); 
+
+DesktopWindowClass::DesktopWindowClass() : classAtom(0) {
+  WNDCLASS wndClass;
+  wndClass.style = 0;
+  wndClass.lpfnWndProc = DesktopWindowProc;
+  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 = NULL;
+  wndClass.lpszMenuName = 0;
+  wndClass.lpszClassName = _T("rfb::win32::DesktopWindowClass");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register DesktopWindow window class", GetLastError());
+  }
+}
+
+DesktopWindowClass::~DesktopWindowClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+DesktopWindowClass baseClass;
+
+//
+// -=- FrameClass
+
+//
+// Window class used for child windows that display pixel data
+//
+
+class FrameClass {
+public:
+  FrameClass();
+  ~FrameClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  LRESULT result;
+  if (msg == WM_CREATE)
+    SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+  else if (msg == WM_DESTROY)
+    SetWindowLong(wnd, GWL_USERDATA, 0);
+  DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %u", wnd, msg);
+    return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processFrameMessage(msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+}
+
+FrameClass::FrameClass() : 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 = NULL;
+  wndClass.hbrBackground = NULL;
+  wndClass.lpszMenuName = 0;
+  wndClass.lpszClassName = _T("rfb::win32::FrameClass");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register Frame window class", GetLastError());
+  }
+}
+
+FrameClass::~FrameClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+FrameClass frameClass;
+
+
+//
+// -=- DesktopWindow instance implementation
+//
+
+DesktopWindow::DesktopWindow(Callback* cb) 
+  : buffer(0),
+    showToolbar(false),
+    client_size(0, 0, 16, 16), window_size(0, 0, 32, 32),
+    cursorVisible(false), cursorAvailable(false), cursorInBuffer(false),
+    systemCursorVisible(true), trackingMouseLeave(false),
+    handle(0), frameHandle(0), has_focus(false), palette_changed(false),
+    fullscreenActive(false), fullscreenRestore(false),
+    bumpScroll(false), callback(cb) {
+
+  // Create the window
+  const char* name = "DesktopWindow";
+  handle = CreateWindow((const TCHAR*)baseClass.classAtom, TStr(name),
+    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+    0, 0, 10, 10, 0, 0, baseClass.instance, this);
+  if (!handle)
+    throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+  vlog.debug("created window \"%s\" (%x)", name, handle);
+
+  // Create the toolbar
+  tb.create(handle);
+  vlog.debug("created toolbar window \"%s\" (%x)", "ViewerToolBar", tb.getHandle());
+
+  // Create the frame window
+  frameHandle = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+    0, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+    CW_USEDEFAULT, CW_USEDEFAULT, handle, 0, frameClass.instance, this);
+  if (!frameHandle) {
+    throw rdr::SystemException("unable to create rfb frame window instance", GetLastError());
+  }
+  vlog.debug("created window \"%s\" (%x)", "Frame Window", frameHandle);
+
+  // Initialise the CPointer pointer handler
+  ptr.setHWND(frameHandle);
+  ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL);
+  ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON);
+
+  // Initialise the bumpscroll timer
+  bumpScrollTimer.setHWND(handle);
+  bumpScrollTimer.setId(TIMER_BUMPSCROLL);
+
+  // Hook the clipboard
+  clipboard.setNotifier(this);
+
+  // Create the backing buffer
+  buffer = new win32::ScaledDIBSectionBuffer(frameHandle);
+
+  // Show the window
+  centerWindow(handle, 0);
+  ShowWindow(handle, SW_SHOW);
+}
+
+DesktopWindow::~DesktopWindow() {
+  vlog.debug("~DesktopWindow");
+  showSystemCursor();
+  if (handle) {
+    disableLowLevelKeyEvents(handle);
+    DestroyWindow(handle);
+    handle = 0;
+  }
+  delete buffer;
+  vlog.debug("~DesktopWindow done");
+}
+
+
+void DesktopWindow::setFullscreen(bool fs) {
+  if (fs && !fullscreenActive) {
+    fullscreenActive = bumpScroll = true;
+
+    // Un-minimize the window if required
+    if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE)
+      ShowWindow(handle, SW_RESTORE);
+
+    // Save the current window position
+    GetWindowRect(handle, &fullscreenOldRect);
+
+    // Find the size of the display the window is on
+    MonitorInfo mi(handle);
+
+    // Hide the toolbar
+    if (tb.isVisible())
+      tb.hide();
+    SetWindowLong(frameHandle, GWL_EXSTYLE, 0);
+
+    // Set the window full-screen
+    DWORD flags = GetWindowLong(handle, GWL_STYLE);
+    fullscreenOldFlags = flags;
+    flags = flags & ~(WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZE | WS_MINIMIZE);
+    vlog.debug("flags=%x", flags);
+
+    SetWindowLong(handle, GWL_STYLE, flags);
+    SetWindowPos(handle, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
+      mi.rcMonitor.right-mi.rcMonitor.left,
+      mi.rcMonitor.bottom-mi.rcMonitor.top,
+      SWP_FRAMECHANGED);
+  } else if (!fs && fullscreenActive) {
+    fullscreenActive = bumpScroll = false;
+
+    // Show the toolbar
+    if (showToolbar)
+      tb.show();
+    SetWindowLong(frameHandle, GWL_EXSTYLE, WS_EX_CLIENTEDGE);
+
+    // Set the window non-fullscreen
+    SetWindowLong(handle, GWL_STYLE, fullscreenOldFlags);
+
+    // Set the window position
+    SetWindowPos(handle, HWND_NOTOPMOST,
+      fullscreenOldRect.left, fullscreenOldRect.top,
+      fullscreenOldRect.right - fullscreenOldRect.left, 
+      fullscreenOldRect.bottom - fullscreenOldRect.top,
+      SWP_FRAMECHANGED);
+  }
+
+  // Adjust the viewport offset to cope with change in size between FS
+  // and previous window state.
+  setViewportOffset(scrolloffset);
+}
+
+void DesktopWindow::setShowToolbar(bool st)
+{
+  showToolbar = st;
+
+  if (showToolbar && !tb.isVisible() && !fullscreenActive) {
+    tb.show();
+  } else if (!showToolbar && tb.isVisible()) {
+    tb.hide();
+  }
+}
+
+void DesktopWindow::setDisableWinKeys(bool dwk) {
+  // Enable low-level event hooking, so we get special keys directly
+  if (dwk)
+    enableLowLevelKeyEvents(handle);
+  else
+    disableLowLevelKeyEvents(handle);
+}
+
+
+void DesktopWindow::setMonitor(const char* monitor) {
+  MonitorInfo mi(monitor);
+  mi.moveTo(handle);
+}
+
+char* DesktopWindow::getMonitor() const {
+  MonitorInfo mi(handle);
+  return strDup(mi.szDevice);
+}
+
+
+bool DesktopWindow::setViewportOffset(const Point& tl) {
+  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(frameHandle, -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+    UpdateWindow(frameHandle);
+    return true;
+  }
+  return false;
+}
+
+
+bool DesktopWindow::processBumpScroll(const Point& pos)
+{
+  if (!bumpScroll) return false;
+  int bumpScrollPixels = 20;
+  bumpScrollDelta = Point();
+
+  if (pos.x == client_size.width()-1)
+    bumpScrollDelta.x = bumpScrollPixels;
+  else if (pos.x == 0)
+    bumpScrollDelta.x = -bumpScrollPixels;
+  if (pos.y == client_size.height()-1)
+    bumpScrollDelta.y = bumpScrollPixels;
+  else if (pos.y == 0)
+    bumpScrollDelta.y = -bumpScrollPixels;
+
+  if (bumpScrollDelta.x || bumpScrollDelta.y) {
+    if (bumpScrollTimer.isActive()) return true;
+    if (setViewportOffset(scrolloffset.translate(bumpScrollDelta))) {
+      bumpScrollTimer.start(25);
+      return true;
+    }
+  }
+
+  bumpScrollTimer.stop();
+  return false;
+}
+
+
+LRESULT
+DesktopWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+
+    // -=- Process standard window messages
+
+  case WM_NOTIFY:
+    if (wParam == ID_TOOLBAR)
+      tb.processWM_NOTIFY(wParam, lParam);
+    break;
+
+  case WM_DISPLAYCHANGE:
+    // Display format has changed - notify callback
+    callback->displayChanged();
+    break;
+
+    // -=- Window position
+
+    // Prevent the window from being resized to be too large if in normal mode.
+    // If maximized or fullscreen the allow oversized windows.
+
+  case WM_WINDOWPOSCHANGING:
+    {
+      WINDOWPOS* wpos = (WINDOWPOS*)lParam;
+      if (wpos->flags & SWP_NOSIZE)
+        break;
+
+      // Work out how big the window should ideally be
+      DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+      DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+      DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+
+      RECT r;
+      SetRect(&r, 0, 0, buffer->width(), buffer->height());
+      AdjustWindowRectEx(&r, style, FALSE, style_ex);
+      Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+      if (current_style & WS_VSCROLL)
+        reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+      if (current_style & WS_HSCROLL)
+        reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+
+      SetRect(&r, reqd_size.tl.x, reqd_size.tl.y, reqd_size.br.x, reqd_size.br.y);
+      if (tb.isVisible())
+        r.bottom += tb.getHeight();
+      AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+      reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+      RECT current;
+      GetWindowRect(handle, &current);
+
+      if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+        // Ensure that the window isn't resized too large
+        if (wpos->cx > reqd_size.width()) {
+          wpos->cx = reqd_size.width();
+          wpos->x = current.left;
+        }
+        if (wpos->cy > reqd_size.height()) {
+          wpos->cy = reqd_size.height();
+          wpos->y = current.top;
+        }
+      }
+    }
+    break;
+
+    // Resize child windows and update window size info we have cached.
+
+  case WM_SIZE:
+    {
+      Point old_offset = desktopToClient(Point(0, 0));
+      RECT r;
+
+      // Resize child windows
+      GetClientRect(handle, &r);
+      if (tb.isVisible()) {
+        MoveWindow(frameHandle, 0, tb.getHeight(),
+                   r.right, r.bottom - tb.getHeight(), TRUE);
+      } else {
+        MoveWindow(frameHandle, 0, 0, r.right, r.bottom, TRUE);
+      }
+      tb.autoSize();
+ 
+      // Update the cached sizing information
+      GetWindowRect(frameHandle, &r);
+      window_size = Rect(r.left, r.top, r.right, r.bottom);
+      GetClientRect(frameHandle, &r);
+      client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+      // Determine whether scrollbars are required
+      calculateScrollBars();
+
+      // Redraw if required
+      if ((!old_offset.equals(desktopToClient(Point(0, 0)))))
+        InvalidateRect(frameHandle, 0, TRUE);
+    }
+    break;
+
+    // -=- Bump-scrolling
+
+  case WM_TIMER:
+    switch (wParam) {
+    case TIMER_BUMPSCROLL:
+      if (!setViewportOffset(scrolloffset.translate(bumpScrollDelta)))
+        bumpScrollTimer.stop();
+      break;
+    case TIMER_POINTER_INTERVAL:
+    case TIMER_POINTER_3BUTTON:
+      ptr.handleTimer(callback, wParam);
+      break;
+    }
+    break;
+
+    // -=- Track whether or not the window has focus
+
+  case WM_SETFOCUS:
+    has_focus = true;
+    break;
+  case WM_KILLFOCUS:
+    has_focus = false;
+    cursorOutsideBuffer();
+    // Restore the keyboard to a consistent state
+    kbd.releaseAllKeys(callback);
+    break;
+
+    // -=- If the menu is about to be shown, make sure it's up to date
+
+  case WM_INITMENU:
+    callback->refreshMenu(true);
+    break;
+
+    // -=- Handle the extra window menu items
+
+    // Pass system menu messages to the callback and only attempt
+    // to process them ourselves if the callback returns false.
+  case WM_SYSCOMMAND:
+    // Call the supplied callback
+    if (callback->sysCommand(wParam, lParam))
+      break;
+
+    // - Not processed by the callback, so process it as a system message
+    switch (wParam & 0xfff0) {
+
+      // When restored, ensure that full-screen mode is re-enabled if required.
+    case SC_RESTORE:
+      {
+      if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE) {
+        rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+        setFullscreen(fullscreenRestore);
+      }
+      else if (fullscreenActive)
+        setFullscreen(false);
+      else
+        rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+
+      return 0;
+      }
+
+      // If we are maximized or minimized then that cancels full-screen mode.
+    case SC_MINIMIZE:
+    case SC_MAXIMIZE:
+      fullscreenRestore = fullscreenActive;
+      setFullscreen(false);
+      break;
+
+    }
+    break;
+
+    // Treat all menu commands as system menu commands
+  case WM_COMMAND:
+    SendMessage(handle, WM_SYSCOMMAND, wParam, lParam);
+    return 0;
+
+    // -=- Handle keyboard input
+
+  case WM_KEYUP:
+  case WM_KEYDOWN:
+    // Hook the MenuKey to pop-up the window menu
+    if (menuKey && (wParam == menuKey)) {
+
+      bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
+      bool altDown = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
+      bool shiftDown = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0;
+      if (!(ctrlDown || altDown || shiftDown)) {
+
+        // If MenuKey is being released then pop-up the menu
+        if ((msg == WM_KEYDOWN)) {
+          // Make sure it's up to date
+          //
+          // NOTE: Here we call refreshMenu only to grey out Move and Size
+          //       menu items. Other things will be refreshed once again
+          //       while processing the WM_INITMENU message.
+          //
+          callback->refreshMenu(false);
+
+          // Show it under the pointer
+          POINT pt;
+          GetCursorPos(&pt);
+          cursorInBuffer = false;
+          TrackPopupMenu(GetSystemMenu(handle, FALSE),
+            TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, handle, 0);
+        }
+
+        // Ignore the MenuKey keypress for both press & release events
+        return 0;
+      }
+    }
+	case WM_SYSKEYDOWN:
+	case WM_SYSKEYUP:
+    kbd.keyEvent(callback, wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN));
+    return 0;
+
+    // -=- Handle the window closing
+
+  case WM_CLOSE:
+    vlog.debug("WM_CLOSE %x", handle);
+    callback->closeWindow();
+    break;
+
+  }
+
+  return rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+}
+
+LRESULT
+DesktopWindow::processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+
+    // -=- Paint the remote frame buffer
+
+  case WM_PAINT:
+    {
+      PAINTSTRUCT ps;
+      HDC paintDC = BeginPaint(frameHandle, &ps);
+      if (!paintDC)
+        throw rdr::SystemException("unable to BeginPaint", GetLastError());
+      Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+      if (!pr.is_empty()) {
+
+        // Draw using the correct palette
+        PaletteSelector pSel(paintDC, windowPalette.getHandle());
+
+        if (buffer->bitmap) {
+          // Update the bitmap's palette
+          if (palette_changed) {
+            palette_changed = false;
+            buffer->refreshPalette();
+          }
+
+          // Get device context
+          BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+          // Blit the border if required
+          Rect bufpos = desktopToClient(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 = clientToDesktop(pr.tl);
+
+          if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+                      bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+            throw rdr::SystemException("unable to BitBlt to window", GetLastError());
+        }
+      }
+
+      EndPaint(frameHandle, &ps);
+
+      // - Notify the callback that a paint message has finished processing
+      callback->paintCompleted();
+    }
+    return 0;
+
+    // -=- Palette management
+
+  case WM_PALETTECHANGED:
+    vlog.debug("WM_PALETTECHANGED");
+    if ((HWND)wParam == frameHandle) {
+      vlog.debug("ignoring");
+      break;
+    }
+  case WM_QUERYNEWPALETTE:
+    vlog.debug("re-selecting palette");
+    {
+      WindowDC wdc(frameHandle);
+      PaletteSelector pSel(wdc, windowPalette.getHandle());
+      if (pSel.isRedrawRequired()) {
+        InvalidateRect(frameHandle, 0, FALSE);
+        UpdateWindow(frameHandle);
+      }
+    }
+    return TRUE;
+
+  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(frameHandle, (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE); 
+    }
+    break;
+
+    // -=- Cursor shape/visibility handling
+
+  case WM_SETCURSOR:
+    if (LOWORD(lParam) != HTCLIENT)
+      break;
+    SetCursor(cursorInBuffer ? dotCursor : arrowCursor);
+    return TRUE;
+
+  case WM_MOUSELEAVE:
+    trackingMouseLeave = false;
+    cursorOutsideBuffer();
+    return 0;
+
+    // -=- Mouse input handling
+
+  case WM_MOUSEMOVE:
+  case WM_LBUTTONUP:
+  case WM_MBUTTONUP:
+  case WM_RBUTTONUP:
+  case WM_LBUTTONDOWN:
+  case WM_MBUTTONDOWN:
+  case WM_RBUTTONDOWN:
+#ifdef WM_MOUSEWHEEL
+  case WM_MOUSEWHEEL:
+#endif
+    if (has_focus)
+    {
+      if (!trackingMouseLeave) {
+        TRACKMOUSEEVENT tme;
+        tme.cbSize = sizeof(TRACKMOUSEEVENT);
+        tme.dwFlags = TME_LEAVE;
+        tme.hwndTrack = frameHandle;
+        _TrackMouseEvent(&tme);
+        trackingMouseLeave = true;
+      }
+      int mask = 0;
+      if (LOWORD(wParam) & MK_LBUTTON) mask |= 1;
+      if (LOWORD(wParam) & MK_MBUTTON) mask |= 2;
+      if (LOWORD(wParam) & MK_RBUTTON) mask |= 4;
+
+#ifdef WM_MOUSEWHEEL
+      if (msg == WM_MOUSEWHEEL) {
+        int delta = (short)HIWORD(wParam);
+        int repeats = (abs(delta)+119) / 120;
+        int wheelMask = (delta > 0) ? 8 : 16;
+        vlog.debug("repeats %d, mask %d\n",repeats,wheelMask);
+        for (int i=0; i<repeats; i++) {
+          ptr.pointerEvent(callback, oldpos, mask | wheelMask);
+          ptr.pointerEvent(callback, oldpos, mask);
+        }
+      } else {
+#endif
+        Point clientPos = Point(LOWORD(lParam), HIWORD(lParam));
+        Point p = clientToDesktop(clientPos);
+
+        // If the mouse is not within the server buffer area, do nothing
+        cursorInBuffer = buffer->getRect().contains(p);
+        if (!cursorInBuffer) {
+          cursorOutsideBuffer();
+          break;
+        }
+
+        // If we're locally rendering the cursor then redraw it
+        if (cursorAvailable) {
+          // - Render the cursor!
+          if (!p.equals(cursorPos)) {
+            hideLocalCursor();
+            cursorPos = p;
+            showLocalCursor();
+            if (cursorVisible)
+              hideSystemCursor();
+          }
+        }
+
+        // If we are doing bump-scrolling then try that first...
+        if (processBumpScroll(clientPos))
+          break;
+
+        // Send a pointer event to the server
+        oldpos = p;
+        if (buffer->isScaling()) {
+          p.x /= double(buffer->getScale()) / 100.0;
+          p.y /= double(buffer->getScale()) / 100.0;
+        }
+        ptr.pointerEvent(callback, p, mask);
+#ifdef WM_MOUSEWHEEL
+      }
+#endif
+    } else {
+      cursorOutsideBuffer();
+    }
+    break;
+  }
+
+  return rfb::win32::SafeDefWindowProc(frameHandle, msg, wParam, lParam);
+}
+
+
+void
+DesktopWindow::hideLocalCursor() {
+  // - Blit the cursor backing store over the cursor
+  // *** ALWAYS call this BEFORE changing buffer PF!!!
+  if (cursorVisible) {
+    cursorVisible = false;
+    buffer->DIBSectionBuffer::imageRect(cursorBackingRect, cursorBacking.data);
+    invalidateDesktopRect(cursorBackingRect, false);
+  }
+}
+
+void
+DesktopWindow::showLocalCursor() {
+  if (cursorAvailable && !cursorVisible && cursorInBuffer) {
+    if (!buffer->getPF().equal(cursor.getPF()) ||
+      cursor.getRect().is_empty()) {
+      vlog.info("attempting to render invalid local cursor");
+      cursorAvailable = false;
+      showSystemCursor();
+      return;
+    }
+    cursorVisible = true;
+    
+    cursorBackingRect = cursor.getRect().translate(cursorPos).translate(cursor.hotspot.negate());
+    cursorBackingRect = cursorBackingRect.intersect(buffer->getRect());
+    buffer->getImage(cursorBacking.data, cursorBackingRect);
+
+    renderLocalCursor();
+
+    invalidateDesktopRect(cursorBackingRect, false);
+  }
+}
+
+void DesktopWindow::cursorOutsideBuffer()
+{
+  cursorInBuffer = false;
+  hideLocalCursor();
+  showSystemCursor();
+}
+
+void
+DesktopWindow::renderLocalCursor()
+{
+  Rect r = cursor.getRect();
+  r = r.translate(cursorPos).translate(cursor.hotspot.negate());
+  buffer->DIBSectionBuffer::maskRect(r, cursor.data, cursor.mask.buf);
+}
+
+void
+DesktopWindow::hideSystemCursor() {
+  if (systemCursorVisible) {
+    vlog.debug("hide system cursor");
+    systemCursorVisible = false;
+    ShowCursor(FALSE);
+  }
+}
+
+void
+DesktopWindow::showSystemCursor() {
+  if (!systemCursorVisible) {
+    vlog.debug("show system cursor");
+    systemCursorVisible = true;
+    ShowCursor(TRUE);
+  }
+}
+
+
+bool
+DesktopWindow::invalidateDesktopRect(const Rect& crect, bool scaling) {
+  Rect rect;
+  if (buffer->isScaling() && scaling) {
+    rect = desktopToClient(buffer->calculateScaleBoundary(crect));
+  } else rect = desktopToClient(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(frameHandle, &invalid, FALSE);
+  return true;
+}
+
+
+void
+DesktopWindow::notifyClipboardChanged(const char* text, int len) {
+  callback->clientCutText(text, len);
+}
+
+
+void
+DesktopWindow::setPF(const PixelFormat& pf) {
+  // If the cursor is the wrong format then clear it
+  if (!pf.equal(buffer->getPF()))
+    setCursor(0, 0, Point(), 0, 0);
+
+  // Update the desktop buffer
+  buffer->setPF(pf);
+  
+  // Redraw the window
+  InvalidateRect(frameHandle, 0, FALSE);
+}
+
+void
+DesktopWindow::setSize(int w, int h) {
+  vlog.debug("setSize %dx%d", w, h);
+
+  // If the locally-rendered cursor is visible then remove it
+  hideLocalCursor();
+
+  // Resize the backing buffer
+  buffer->setSize(w, h);
+
+  // If the window is not maximised or full-screen then resize it
+  if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+    // Resize the window to the required size
+    RECT r = {0, 0, w, h};
+    AdjustWindowRectEx(&r, GetWindowLong(frameHandle, GWL_STYLE), FALSE,
+                       GetWindowLong(frameHandle, GWL_EXSTYLE));
+    if (tb.isVisible())
+      r.bottom += tb.getHeight();
+    AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+
+    // Resize about the center of the window, and clip to current monitor
+    MonitorInfo mi(handle);
+    resizeWindow(handle, r.right-r.left, r.bottom-r.top);
+    mi.clipTo(handle);
+  } else {
+    // Ensure the screen contents are consistent
+    InvalidateRect(frameHandle, 0, FALSE);
+  }
+
+  // Enable/disable scrollbars as appropriate
+  calculateScrollBars();
+}
+
+void
+DesktopWindow::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+  hideLocalCursor();
+
+  cursor.hotspot = hotspot;
+
+  cursor.setSize(w, h);
+  cursor.setPF(buffer->getPF());
+  cursor.imageRect(cursor.getRect(), data);
+  memcpy(cursor.mask.buf, mask, cursor.maskLen());
+  cursor.crop();
+
+  cursorBacking.setSize(w, h);
+  cursorBacking.setPF(buffer->getPF());
+
+  cursorAvailable = true;
+
+  showLocalCursor();
+}
+
+PixelFormat
+DesktopWindow::getNativePF() const {
+  vlog.debug("getNativePF()");
+  return WindowDC(handle).getPF();
+}
+
+
+void
+DesktopWindow::refreshWindowPalette(int start, int count) {
+  vlog.debug("refreshWindowPalette(%d, %d)", start, count);
+
+  Colour colours[256];
+  if (count > 256) {
+    vlog.debug("%d palette entries", count);
+    throw rdr::Exception("too many palette entries");
+  }
+
+  // Copy the palette from the DIBSectionBuffer
+  ColourMap* cm = buffer->getColourMap();
+  if (!cm) return;
+  for (int i=0; i<count; i++) {
+    int r, g, b;
+    cm->lookup(i, &r, &g, &b);
+    colours[i].r = r;
+    colours[i].g = g;
+    colours[i].b = b;
+  }
+
+  // Set the window palette
+  windowPalette.setEntries(start, count, colours);
+
+  // Cause the window to be redrawn
+  palette_changed = true;
+  InvalidateRect(handle, 0, FALSE);
+}
+
+
+void DesktopWindow::calculateScrollBars() {
+  // Calculate the required size of window
+  DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+  DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+  DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+  DWORD old_style;
+  RECT r;
+  SetRect(&r, 0, 0, buffer->width(), buffer->height());
+  AdjustWindowRectEx(&r, style, FALSE, style_ex);
+  Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+  if (!bumpScroll) {
+    // We only enable scrollbars if bump-scrolling is not active.
+    // Effectively, this means if full-screen is not active,
+    // but I think it's better to make these things explicit.
+    
+    // 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(frameHandle, GWL_STYLE, style);
+    SetWindowPos(frameHandle, 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(frameHandle, 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(frameHandle, SB_HORZ, &si, TRUE);
+  }
+
+  // Update the cached client size
+  GetClientRect(frameHandle, &r);
+  client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+
+void
+DesktopWindow::setName(const char* name) {
+  SetWindowText(handle, TStr(name));
+}
+
+
+void
+DesktopWindow::serverCutText(const char* str, int len) {
+  CharArray t(len+1);
+  memcpy(t.buf, str, len);
+  t.buf[len] = 0;
+  clipboard.setClipText(t.buf);
+}
+
+
+void DesktopWindow::fillRect(const Rect& r, Pixel pix) {
+  Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+  if (cursorBackingRect.overlaps(img_rect)) hideLocalCursor();
+  buffer->fillRect(r, pix);
+  invalidateDesktopRect(r);
+}
+void DesktopWindow::imageRect(const Rect& r, void* pixels) {
+  Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+  if (cursorBackingRect.overlaps(img_rect)) hideLocalCursor();
+  buffer->imageRect(r, pixels);
+  invalidateDesktopRect(r);
+}
+void DesktopWindow::copyRect(const Rect& r, int srcX, int srcY) {
+  Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+  if (cursorBackingRect.overlaps(img_rect) ||
+      cursorBackingRect.overlaps(Rect(srcX, srcY, srcX+img_rect.width(), srcY+img_rect.height())))
+    hideLocalCursor();
+  buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+  invalidateDesktopRect(r);
+}
+
+void DesktopWindow::invertRect(const Rect& r) {
+  int stride;
+  rdr::U8* p = buffer->isScaling() ? buffer->getPixelsRW(buffer->calculateScaleBoundary(r), &stride) 
+   : buffer->getPixelsRW(r, &stride);
+  for (int y = 0; y < r.height(); y++) {
+    for (int x = 0; x < r.width(); x++) {
+      switch (buffer->getPF().bpp) {
+      case 8:  ((rdr::U8* )p)[x+y*stride] ^= 0xff;       break;
+      case 16: ((rdr::U16*)p)[x+y*stride] ^= 0xffff;     break;
+      case 32: ((rdr::U32*)p)[x+y*stride] ^= 0xffffffff; break;
+      }
+    }
+  }
+  invalidateDesktopRect(r);
+}
diff --git a/win/vncviewer/DesktopWindow.h b/win/vncviewer/DesktopWindow.h
new file mode 100644
index 0000000..3d2211f
--- /dev/null
+++ b/win/vncviewer/DesktopWindow.h
@@ -0,0 +1,254 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- DesktopWindow.h
+
+// Each VNC connection instance (CConn) creates a DesktopWindow the
+// server initialisation message has been received.  The CConn is
+// responsible for all RFB-specific and network issues.  The
+// DesktopWindow is responsible for all GUI management issues.
+//
+// DesktopWindow provides a FullFramePixelBuffer interface for the
+// CConn to render updates into.  It also requires a callback object
+// to be supplied, which will be notified when various events occur.
+
+#ifndef __RFB_WIN32_DESKTOP_WINDOW_H__
+#define __RFB_WIN32_DESKTOP_WINDOW_H__
+
+#include <rfb/Cursor.h>
+#include <rfb_win32/CKeyboard.h>
+#include <rfb_win32/CPointer.h>
+#include <rfb_win32/Clipboard.h>
+#include <rfb_win32/ScaledDIBSectionBuffer.h>
+#include <rfb_win32/LogicalPalette.h>
+#include <vncviewer/ViewerToolBar.h>
+
+
+namespace rfb {
+
+  namespace win32 {
+
+    class DesktopWindow : rfb::win32::Clipboard::Notifier {
+    public:
+      class Callback;
+
+      DesktopWindow(Callback* cb_);
+      ~DesktopWindow();
+
+      // - Window message handling procedure
+      LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      // - Window message handling procedure for the framebuffer window
+      LRESULT processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      // - Determine the native pixel format of the window
+      //   This can (and often will) differ from the PixelBuffer format
+      PixelFormat getNativePF() const;
+
+      // - Get the underlying window handle
+      //   This is used by F8Menu to modify the window's menu
+      HWND getHandle() const {return handle;}
+
+      // - Get the framebuffer window handle
+      HWND getFrameHandle() const {return frameHandle;}
+
+      // - Set the window title
+      void setName(const char* name);
+
+      // - Set the key that causes the system/F8 menu to be displayed
+      void setMenuKey(rdr::U8 key) { menuKey = key; }
+
+      // - Pointer event handling
+      void setEmulate3(bool em3) { ptr.enableEmulate3(em3); }
+      void setPointerEventInterval(int interval) { ptr.enableInterval(interval); }
+
+      // - Set the pixel format, size etc of the underlying PixelBuffer
+      void setPF(const PixelFormat& pf);
+      PixelFormat getPF() const { return buffer->getPF(); }
+      void setSize(int w, int h);
+      void setColour(int i, int r, int g, int b) {buffer->setColour(i, r, g, b);}
+
+      // - Set the cursor to render when the pointer is within the desktop buffer
+      void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+      void showCursor() { showLocalCursor(); }
+
+      // - Set the window fullscreen / determine whether it is fullscreen
+      void setFullscreen(bool fs);
+      bool isFullscreen() { return fullscreenActive; }
+
+      // - Set/get the toolbar's state
+      void setShowToolbar(bool st);
+      bool isToolbarEnabled() { return showToolbar; }
+
+      // - Set whether to disable special Windows keys & pass them straight to server
+      void setDisableWinKeys(bool dwk);
+
+      // - Set/get which monitor the window should be displayed on
+      void setMonitor(const char* monitor);
+      char* getMonitor() const;
+
+      // - Set the local clipboard
+      void serverCutText(const char* str, int len);
+
+      // - Draw into the desktop buffer & update the window
+      void fillRect(const Rect& r, Pixel pix);
+      void imageRect(const Rect& r, void* pixels);
+      void copyRect(const Rect& r, int srcX, int srcY);
+
+      void invertRect(const Rect& r);
+
+      // - Update the window palette if the display is palette-based.
+      //   Colours are pulled from the desktop buffer's ColourMap.
+      //   Only the specified range of indexes is dealt with.
+      //   After the update, the entire window is redrawn.
+      void refreshWindowPalette(int start, int count);
+
+      // Clipboard::Notifier interface
+      void notifyClipboardChanged(const char* text, int len);
+
+      // DesktopWindow Callback interface
+      class Callback : public InputHandler {
+      public:
+        virtual ~Callback() {}
+        virtual void displayChanged() = 0;
+        virtual void paintCompleted() = 0;
+        virtual bool sysCommand(WPARAM wParam, LPARAM lParam) = 0;
+        virtual void closeWindow() = 0;
+        virtual void refreshMenu(bool enableSysItems) = 0;
+      };
+
+      // Currently accessible so that the CConn can releaseAllKeys & check
+      // whether Ctrl and Alt are down...
+      rfb::win32::CKeyboard kbd;
+
+    protected:
+      // Routines to convert between Desktop and client (window) coordinates
+      Point desktopToClient(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;
+      }
+      Rect desktopToClient(const Rect& r) {
+        return Rect(desktopToClient(r.tl), desktopToClient(r.br));
+      }
+      Point clientToDesktop(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;
+      }
+      Rect clientToDesktop(const Rect& r) {
+        return Rect(clientToDesktop(r.tl), clientToDesktop(r.br));
+      }
+
+      // Internal routine used by the scrollbars & bump scroller to select
+      // the portion of the Desktop to display
+      bool setViewportOffset(const Point& tl);
+    
+      // Bump scroll handling.  Bump scrolling is used if the window is
+      // in fullscreen mode and the Desktop is larger than the window
+      bool processBumpScroll(const Point& cursorPos);
+      void setBumpScroll(bool on);
+      bool bumpScroll;
+      Point bumpScrollDelta;
+      IntervalTimer bumpScrollTimer;
+
+      // Locally-rendered VNC cursor
+      void hideLocalCursor();
+      void showLocalCursor();
+      void renderLocalCursor();
+
+      // The system-rendered cursor
+      void hideSystemCursor();
+      void showSystemCursor();
+
+      // cursorOutsideBuffer() is called whenever we detect that the mouse has
+      // moved outside the desktop.  It restores the system arrow cursor.
+      void cursorOutsideBuffer();
+
+      // Returns true if part of the supplied rect is visible, false otherwise
+      bool invalidateDesktopRect(const Rect& crect, bool scaling=true);
+
+      // Determine whether or not we need to enable/disable scrollbars and set the
+      // window style accordingly
+      void calculateScrollBars();
+
+      // Win32-specific input handling
+      rfb::win32::CPointer ptr;
+      Point oldpos;
+      rfb::win32::Clipboard clipboard;
+
+      // Palette handling
+      LogicalPalette windowPalette;
+      bool palette_changed;
+
+      // - Full-screen mode
+      RECT fullscreenOldRect;
+      DWORD fullscreenOldFlags;
+      bool fullscreenActive;
+      bool fullscreenRestore;
+
+      // Cursor handling
+      Cursor cursor;
+      bool systemCursorVisible;  // Should system-cursor be drawn?
+      bool trackingMouseLeave;
+      bool cursorInBuffer;    // Is cursor position within server buffer? (ONLY for LocalCursor)
+      bool cursorVisible;     // Is cursor currently rendered?
+      bool cursorAvailable;   // Is cursor available for rendering?
+      Point cursorPos;
+      ManagedPixelBuffer cursorBacking;
+      Rect cursorBackingRect;
+
+      // ToolBar handling
+      ViewerToolBar tb;
+      bool showToolbar;
+
+      // Local window state
+      win32::ScaledDIBSectionBuffer* buffer;
+      bool has_focus;
+      Rect window_size;
+      Rect client_size;
+      Point scrolloffset;
+      Point maxscrolloffset;
+      HWND handle;
+      HWND frameHandle;
+      rdr::U8 menuKey;
+
+      Callback* callback;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_DESKTOP_WINDOW_H__
+
+
diff --git a/win/vncviewer/FTBrowseDlg.cxx b/win/vncviewer/FTBrowseDlg.cxx
new file mode 100644
index 0000000..1b6dfb6
--- /dev/null
+++ b/win/vncviewer/FTBrowseDlg.cxx
@@ -0,0 +1,196 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTBrpwseDlg.cxx
+
+#include <vncviewer/FTBrowseDlg.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTBrowseDlg::FTBrowseDlg(FTDialog *pFTDlg)
+{
+  m_pFTDlg = pFTDlg;
+  m_hwndDlg = NULL;
+  m_hwndTree = NULL;
+  m_hParentItem = NULL;
+}
+
+FTBrowseDlg::~FTBrowseDlg()
+{
+  destroy();
+}
+
+bool
+FTBrowseDlg::create()
+{
+  m_hwndDlg = CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FTBROWSE), 
+                                m_pFTDlg->getWndHandle(), (DLGPROC) FTBrowseDlgProc, 
+                                (LONG) this);
+
+  if (m_hwndDlg == NULL) return false;
+
+  m_hwndTree = GetDlgItem(m_hwndDlg, IDC_FTBROWSETREE);
+
+  ShowWindow(m_hwndDlg, SW_SHOW);
+  UpdateWindow(m_hwndDlg);
+
+  return true;
+}
+
+void
+FTBrowseDlg::destroy()
+{
+  EndDialog(m_hwndDlg, 0);
+}
+
+void
+FTBrowseDlg::addItems(FileInfo *pFI)
+{
+  TVITEM tvi;
+  TVINSERTSTRUCT tvins;
+
+  if (pFI->getNumEntries() <= 0) return;
+
+  for (unsigned int i = 0; i < pFI->getNumEntries(); i++)
+  {
+    tvi.mask = TVIF_TEXT;
+    tvi.pszText = pFI->getNameAt(i);;
+    tvins.hParent = m_hParentItem;
+    tvins.item = tvi;
+    tvins.hParent = TreeView_InsertItem(m_hwndTree, &tvins);
+    TreeView_InsertItem(m_hwndTree, &tvins);
+  }
+}
+
+char *
+FTBrowseDlg::getTVPath(HTREEITEM hTItem)
+{
+  char path[FT_FILENAME_SIZE];
+  char szText[FT_FILENAME_SIZE];
+
+  TVITEM tvi;
+  path[0] = '\0';
+
+  do {
+    tvi.mask = TVIF_TEXT | TVIF_HANDLE;
+    tvi.hItem = hTItem;
+    tvi.pszText = szText;
+    tvi.cchTextMax = FT_FILENAME_SIZE;
+    TreeView_GetItem(m_hwndTree, &tvi);
+    sprintf(path, "%s\\%s", path, tvi.pszText);
+    hTItem = TreeView_GetParent(m_hwndTree, hTItem);
+  } while(hTItem != NULL);
+
+  return pathInvert(path);
+}
+
+char *
+FTBrowseDlg::pathInvert(char *pPath)
+{
+  int len = strlen(pPath);
+  m_szPath[0] = '\0';
+  char *pos = NULL;
+  
+  while ((pos = strrchr(pPath, '\\')) != NULL) {
+    if (strlen(m_szPath) == 0) {
+      strcpy(m_szPath, (pos + 1));
+    } else {
+      sprintf(m_szPath, "%s\\%s", m_szPath, (pos + 1));
+    }
+    *pos = '\0';
+  }
+
+  m_szPath[len] = '\0';
+  return m_szPath;
+}
+
+char *
+FTBrowseDlg::getPath()
+{
+  GetDlgItemText(m_hwndDlg, IDC_FTBROWSEPATH, m_szPath, FT_FILENAME_SIZE);
+  return m_szPath;
+}
+
+void
+FTBrowseDlg::deleteChildItems()
+{
+  while (TreeView_GetChild(m_hwndTree, m_hParentItem) != NULL) {
+    TreeView_DeleteItem(m_hwndTree, TreeView_GetChild(m_hwndTree, m_hParentItem));
+  }
+}
+
+BOOL CALLBACK 
+FTBrowseDlg::FTBrowseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  FTBrowseDlg *_this = (FTBrowseDlg *) GetWindowLong(hwnd, GWL_USERDATA);
+  switch (uMsg)
+  {
+  case WM_INITDIALOG:
+    {
+      SetWindowLong(hwnd, GWL_USERDATA, lParam);
+      return FALSE;
+    }
+    break;
+  case WM_COMMAND:
+    {
+      switch (LOWORD(wParam))
+      {
+      case IDOK:
+        _this->m_pFTDlg->onEndBrowseDlg(true);
+        return FALSE;
+      case IDCANCEL:
+        _this->m_pFTDlg->onEndBrowseDlg(false);
+        return FALSE;
+      }
+    }
+    break;
+  case WM_NOTIFY:
+    switch (LOWORD(wParam))
+    {
+    case IDC_FTBROWSETREE:
+      switch (((LPNMHDR) lParam)->code)
+      {
+      case TVN_SELCHANGED:
+        SetDlgItemText(hwnd, IDC_FTBROWSEPATH, _this->getTVPath(((NMTREEVIEW *) lParam)->itemNew.hItem));
+        return FALSE;
+//      case TVN_ITEMEXPANDING:
+      case TVN_ITEMEXPANDED:
+        {
+          NMTREEVIEW *nmCode = (NMTREEVIEW *) lParam;
+          if (nmCode->action == 2) {
+            _this->m_hParentItem = nmCode->itemNew.hItem;
+            _this->deleteChildItems();
+            _this->m_pFTDlg->getBrowseItems(_this->getTVPath(_this->m_hParentItem));
+          }
+        }
+        return FALSE;
+      }
+    break;
+    case WM_CLOSE:
+      _this->m_pFTDlg->onEndBrowseDlg(false);
+      return FALSE;
+    }
+  }
+    return 0;
+}
diff --git a/win/vncviewer/FTBrowseDlg.h b/win/vncviewer/FTBrowseDlg.h
new file mode 100644
index 0000000..5c9ba35
--- /dev/null
+++ b/win/vncviewer/FTBrowseDlg.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTBrowseDlg.h
+
+#ifndef __RFB_WIN32_FTBROWSEDLG_H__
+#define __RFB_WIN32_FTBROWSEDLG_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <vncviewer/FTDialog.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+  namespace win32 {
+    class FTDialog;
+
+    class FTBrowseDlg
+    {
+    public:
+      FTBrowseDlg(FTDialog *pFTDlg);
+      ~FTBrowseDlg();
+
+      static BOOL CALLBACK FTBrowseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+      bool create();
+      void destroy();
+
+      void addItems(FileInfo *pFI);
+      char *getPath();
+
+      void deleteChildItems();
+
+    private:
+      HWND m_hwndDlg;
+      HWND m_hwndTree;
+      FTDialog *m_pFTDlg;
+      HTREEITEM m_hParentItem;
+
+      char m_szPath[FT_FILENAME_SIZE];
+
+      char *pathInvert(char *pPath);
+      char *getTVPath(HTREEITEM hTItem);
+    };
+  }
+}
+
+#endif // __RFB_WIN32_FTBROWSEDLG_H__
diff --git a/win/vncviewer/FTDialog.cxx b/win/vncviewer/FTDialog.cxx
new file mode 100644
index 0000000..5f71f7d
--- /dev/null
+++ b/win/vncviewer/FTDialog.cxx
@@ -0,0 +1,1162 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTDialog.cxx
+
+#include <vncviewer/FTDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+const char FTDialog::szCheckDeleteQueueText[]    = "TightVNC.Viewer.CheckDeleteQueue.Msg";
+const char FTDialog::szCheckTransferQueueText[]  = "TightVNC.Viewer.CheckTransferQueue.Msg";
+const char FTDialog::szUploadFilePortionText[]   = "TightVNC.Viewer.UploadFilePortion.Msg";
+
+FTDialog::FTDialog(HINSTANCE hInst, FileTransfer *pFT)
+{
+  m_pFileTransfer = pFT;
+  m_hInstance = hInst;
+
+  m_bDlgShown = false;
+  m_bLocalBrowsing = true;
+  m_bCloseDlgAfterCancel = false;
+
+  m_pLocalLV = NULL;
+  m_pRemoteLV = NULL;
+  m_pProgress = NULL;
+  m_pCancelingDlg = NULL;
+  m_pCreateFolderDlg = NULL;
+  m_pRenameDlg = NULL;
+  m_pBrowseDlg = NULL;
+
+  m_hwndFTDialog = NULL;
+  m_hwndLocalPath = NULL;
+  m_hwndRemotePath = NULL;
+
+  m_FTMenuSource = 0;
+  m_dwNumStatusStrings = 0;
+
+  m_szLocalPath[0] = '\0';
+  m_szRemotePath[0] = '\0';
+  m_szLocalPathTmp[0] = '\0';
+  m_szRemotePathTmp[0] = '\0';
+  m_szCreateFolderName[0] = '\0';
+}
+
+FTDialog::~FTDialog()
+{
+  destroyFTDialog();
+}
+
+bool
+FTDialog::createFTDialog(HWND hwndParent)
+{
+  if (m_hwndFTDialog != NULL) {
+    ShowWindow(m_hwndFTDialog, SW_SHOW);
+    m_bDlgShown = true;
+    showLocalLVItems();
+    showRemoteLVItems();
+    return true;
+  }
+
+  if (!initFTWndMsgs()) return false;
+
+  m_hwndFTDialog = CreateDialogParam(m_hInstance, 
+                                     MAKEINTRESOURCE(IDD_FILETRANSFER_DLG),
+                                     hwndParent, 
+                                     (DLGPROC) FTDialogProc,
+                                     (LONG) this);
+  
+  if (m_hwndFTDialog == NULL) return false;
+
+  HWND hwndLocalList = GetDlgItem(m_hwndFTDialog, IDC_FTLOCALLIST);
+  HWND hwndRemoteList = GetDlgItem(m_hwndFTDialog, IDC_FTREMOTELIST);
+
+  if ((hwndLocalList == NULL) || (hwndRemoteList == NULL)) {
+    destroyFTDialog();
+    return false;
+  }
+
+  m_pLocalLV = new FTListView(hwndLocalList);
+  m_pRemoteLV = new FTListView(hwndRemoteList);
+  
+  m_pProgress = new FTProgress(m_hwndFTDialog);
+  
+  if ((m_pLocalLV == NULL) || (m_pRemoteLV == NULL) || (m_pProgress == NULL)) {
+    destroyFTDialog();
+    return false;
+  }
+
+  initFTDialog();
+  
+  ShowWindow(m_hwndFTDialog, SW_SHOW);
+  UpdateWindow(m_hwndFTDialog);
+  m_bDlgShown = true;
+  return true;
+}
+
+bool
+FTDialog::initFTDialog()
+{
+  m_pLocalLV->initialize(m_hInstance);
+  m_pRemoteLV->initialize(m_hInstance);
+
+  m_hwndLocalPath = GetDlgItem(m_hwndFTDialog, IDC_FTLOCALPATH);
+  m_hwndRemotePath = GetDlgItem(m_hwndFTDialog, IDC_FTREMOTEPATH);
+
+  setIcon(IDC_FTLOCALUP, IDI_FTUP);
+  setIcon(IDC_FTREMOTEUP, IDI_FTUP);
+  setIcon(IDC_FTLOCALRELOAD, IDI_FTRELOAD);
+  setIcon(IDC_FTREMOTERELOAD, IDI_FTRELOAD);
+
+  showLocalLVItems();
+  showRemoteLVItems();
+
+  return true;
+}
+
+bool
+FTDialog::initFTWndMsgs()
+{
+  m_msgCheckDeleteQueue    = RegisterWindowMessage(szCheckDeleteQueueText);
+  m_msgCheckTransferQueue  = RegisterWindowMessage(szCheckTransferQueueText);
+  m_msgUploadFilePortion   = RegisterWindowMessage(szUploadFilePortionText);
+
+  if ((m_msgCheckDeleteQueue) && 
+      (m_msgCheckTransferQueue) && 
+      (m_msgUploadFilePortion)) return true;
+
+  return false;
+}
+
+bool
+FTDialog::closeFTDialog()
+{
+  ShowWindow(m_hwndFTDialog, SW_HIDE);
+  m_bDlgShown = false;
+  return true;
+}
+
+void
+FTDialog::destroyFTDialog()
+{
+  if (m_pLocalLV != NULL) {
+    delete m_pLocalLV;
+    m_pLocalLV = NULL;
+  }
+
+  if (m_pRemoteLV != NULL) {
+    delete m_pRemoteLV;
+    m_pRemoteLV = NULL;
+  }
+
+  if (m_pProgress != NULL) {
+    delete m_pProgress;
+    m_pProgress = NULL;
+  }
+
+  if(m_pCancelingDlg != NULL) {
+    delete m_pCancelingDlg;
+    m_pCancelingDlg = NULL;
+  }
+
+  if (m_pCreateFolderDlg != NULL) {
+    delete m_pCreateFolderDlg;
+    m_pCreateFolderDlg = NULL;
+  }
+
+  if(m_pRenameDlg != NULL) {
+    delete m_pRenameDlg;
+    m_pRenameDlg = NULL;
+  }
+
+  if (DestroyWindow(m_hwndFTDialog)) m_hwndFTDialog = NULL;
+}
+
+BOOL CALLBACK 
+FTDialog::FTDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  FTDialog *_this = (FTDialog *) GetWindowLong(hwnd, GWL_USERDATA);
+
+  switch (uMsg)
+  {
+  case WM_INITDIALOG:
+    _this = (FTDialog*)lParam;
+    SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
+    SetForegroundWindow(hwnd);
+    return TRUE;
+  case WM_COMMAND:
+    {
+      switch (LOWORD(wParam))
+      {
+      case IDC_FTLOCALPATH:
+        switch (HIWORD (wParam))
+        {
+        case CBN_SETFOCUS:
+          _this->setButtonsState();
+          return FALSE;
+        }
+        break;
+      case IDC_FTREMOTEPATH:
+        switch (HIWORD (wParam))
+        {
+        case CBN_SETFOCUS:
+          _this->setButtonsState();
+          return FALSE;
+        }
+        break;
+      case IDC_FTCLOSE:
+        _this->onClose();
+        return FALSE;
+      case IDC_FTLOCALBROWSE:
+        _this->onLocalBrowse();
+        return FALSE;
+      case IDC_FTREMOTEBROWSE:
+        _this->onRemoteBrowse();
+        return FALSE;
+      case IDC_FTLOCALUP:
+        _this->setButtonsState();
+        _this->onLocalOneUpFolder();
+        return FALSE;
+      case IDC_FTREMOTEUP:
+        _this->setButtonsState();
+        _this->onRemoteOneUpFolder();
+        return FALSE;
+      case IDC_FTLOCALRELOAD:
+        _this->setButtonsState();
+        _this->onLocalReload();
+        return FALSE;
+      case IDC_FTREMOTERELOAD:
+       _this->setButtonsState();
+       _this->onRemoteReload();
+        return FALSE;
+      case IDC_FTUPLOAD:
+        _this->onUpload();
+        return FALSE;
+      case IDC_FTDOWNLOAD:
+        _this->onDownload();
+        return FALSE;
+      case IDC_FTCANCEL:
+        _this->onFTCancel();
+        return FALSE;
+      case IDM_FTCOPY:
+      case IDM_FTRENAME:
+      case IDM_FTDELETE:
+      case IDM_FTCANCEL:
+      case IDM_FTCREATEFOLDER:
+        _this->onFTMenuCommand(LOWORD(wParam));
+        return FALSE;
+      }
+    }
+    break;
+    
+  case WM_NOTIFY:
+    switch (LOWORD(wParam))
+    {
+    case IDC_FTLOCALLIST:
+      switch (((LPNMHDR) lParam)->code)
+      {
+      case NM_CLICK:
+      case NM_SETFOCUS:
+      case LVN_ITEMCHANGED:
+        _this->setButtonsState();
+        return FALSE;
+      case LVN_GETDISPINFO:
+        _this->m_pLocalLV->onGetDispInfo((NMLVDISPINFO *) lParam);
+        return FALSE;
+      case LVN_ITEMACTIVATE:
+        _this->onLocalItemActivate((LPNMITEMACTIVATE) lParam);
+        return FALSE;
+      case NM_RCLICK:
+        _this->onLocalRButton();
+        return FALSE;
+      }
+      break;
+    case IDC_FTREMOTELIST:
+      switch (((LPNMHDR) lParam)->code)
+      {
+      case NM_CLICK:
+      case NM_SETFOCUS:
+      case LVN_ITEMCHANGED:
+        _this->setButtonsState();
+      case LVN_GETDISPINFO:
+        _this->m_pRemoteLV->onGetDispInfo((NMLVDISPINFO *) lParam);
+        return FALSE;
+      case LVN_ITEMACTIVATE:
+        _this->onRemoteItemActivate((LPNMITEMACTIVATE) lParam);
+        return FALSE;
+      case NM_RCLICK:
+        _this->onRemoteRButton();
+        return FALSE;
+      }
+      break;
+    }
+    break;
+    case WM_CLOSE:
+      _this->onClose();
+      return FALSE;
+  }
+
+  if (_this != NULL) {
+    if (uMsg == _this->m_msgCheckTransferQueue)
+      _this->m_pFileTransfer->checkTransferQueue();
+
+    if (uMsg == _this->m_msgUploadFilePortion)
+      _this->m_pFileTransfer->uploadFilePortion();
+    
+    if (uMsg == _this->m_msgCheckDeleteQueue)
+      _this->m_pFileTransfer->checkDeleteQueue();
+  }
+
+  return FALSE;
+}
+
+void
+FTDialog::onClose()
+{
+  if (m_pFileTransfer->isTransferEnable()) {
+    m_bCloseDlgAfterCancel = true;
+    onFTCancel();
+  } else {
+    closeFTDialog();
+  }  
+}
+
+void 
+FTDialog::onLocalItemActivate(LPNMITEMACTIVATE lpnmia)
+{
+  if (strlen(m_szLocalPath) == 0) {
+   strcpy(m_szLocalPathTmp, m_pLocalLV->getActivateItemName(lpnmia)); 
+  } else {
+    sprintf(m_szLocalPathTmp, "%s\\%s", m_szLocalPath, m_pLocalLV->getActivateItemName(lpnmia));
+  }
+  showLocalLVItems();
+}
+
+void 
+FTDialog::onRemoteItemActivate(LPNMITEMACTIVATE lpnmia)
+{
+  if (strlen(m_szRemotePath) == 0) {
+   strcpy(m_szRemotePathTmp, m_pRemoteLV->getActivateItemName(lpnmia)); 
+  } else {
+    sprintf(m_szRemotePathTmp, "%s\\%s", m_szRemotePath, m_pRemoteLV->getActivateItemName(lpnmia));
+  }
+  showRemoteLVItems();
+}
+
+void 
+FTDialog::onEndBrowseDlg(bool bResult)
+{
+  if (m_pBrowseDlg == NULL) return;
+
+  if (bResult) {
+    if (m_bLocalBrowsing) {
+      strcpy(m_szLocalPathTmp, m_pBrowseDlg->getPath());
+      showLocalLVItems();
+    } else {
+      strcpy(m_szRemotePathTmp, m_pBrowseDlg->getPath());
+      showRemoteLVItems();
+    }
+  }
+  delete m_pBrowseDlg;
+  m_pBrowseDlg = NULL;
+}
+
+void 
+FTDialog::onLocalBrowse()
+{
+  if (m_pBrowseDlg != NULL) return;
+  
+  m_bLocalBrowsing = true;
+
+  m_pBrowseDlg = new FTBrowseDlg(this);
+  m_pBrowseDlg->create();
+
+  getBrowseItems("");
+}
+
+void 
+FTDialog::onRemoteBrowse()
+{
+  if (m_pBrowseDlg != NULL) return;
+  
+  m_bLocalBrowsing = false;
+
+  m_pBrowseDlg = new FTBrowseDlg(this);
+  if (m_pBrowseDlg->create()) {
+    m_pFileTransfer->requestFileList("", FT_FLR_DEST_BROWSE, true);
+  } else {
+    delete m_pBrowseDlg;
+    m_pBrowseDlg = NULL;
+  }
+}
+
+void 
+FTDialog::onLocalReload()
+{
+  strcpy(m_szLocalPathTmp, m_szLocalPath);
+  showLocalLVItems();
+}
+
+void 
+FTDialog::onRemoteReload()
+{
+  strcpy(m_szRemotePathTmp, m_szRemotePath);
+  showRemoteLVItems();
+}
+
+void
+FTDialog::showLocalLVItems()
+{
+  FolderManager fm;
+  FileInfo fileInfo;
+  if (fm.getDirInfo(m_szLocalPathTmp, &fileInfo, 0)) {
+    fileInfo.sort();
+    m_pLocalLV->deleteAllItems();
+    m_pLocalLV->addItems(&fileInfo);
+    strcpy(m_szLocalPath, m_szLocalPathTmp);
+    SetWindowText(m_hwndLocalPath, m_szLocalPath);
+  }
+}
+
+void
+FTDialog::showRemoteLVItems()
+{
+  m_pFileTransfer->requestFileList(m_szRemotePathTmp, FT_FLR_DEST_MAIN, false);
+}
+
+void 
+FTDialog::addRemoteLVItems(FileInfo *pFI)
+{
+  pFI->sort();
+  m_pRemoteLV->deleteAllItems();
+  m_pRemoteLV->addItems(pFI);
+  strcpy(m_szRemotePath, m_szRemotePathTmp);
+  SetWindowText(m_hwndRemotePath, m_szRemotePath);
+  UpdateWindow(m_hwndFTDialog);
+}
+
+void 
+FTDialog::onLocalOneUpFolder()
+{
+  strcpy(m_szLocalPathTmp, m_szLocalPath);
+  makeOneUpFolder(m_szLocalPathTmp);
+  showLocalLVItems();
+}
+
+void 
+FTDialog::onRemoteOneUpFolder()
+{
+  strcpy(m_szRemotePathTmp, m_szRemotePath);
+  makeOneUpFolder(m_szRemotePathTmp);
+  showRemoteLVItems();
+}
+
+void 
+FTDialog::reqFolderUnavailable()
+{
+  strcpy(m_szRemotePathTmp, m_szRemotePath);
+  SetWindowText(m_hwndRemotePath, m_szRemotePath);
+  UpdateWindow(m_hwndFTDialog);
+}
+
+int
+FTDialog::makeOneUpFolder(char *pPath)
+{
+  if (strcmp(pPath, "") == 0) return strlen(pPath);
+  for (int i=(strlen(pPath)-2); i>=0; i--) {
+    if (pPath[i] == '\\') {
+      pPath[i] = '\0';
+      break;
+    }
+    if (i == 0) pPath[0] = '\0';
+  }
+  return strlen(pPath);
+}
+
+void 
+FTDialog::onUpload()
+{
+  FileInfo fi;
+  char prefix[FT_FILENAME_SIZE];
+  prefix[0] = '\0';
+
+  if (m_pFileTransfer->isTransferEnable())
+    strcpy(prefix, "File Transfer is active.\nDo you want to add selected file(s)/folder(s) to transfer queue?\n\n");
+  
+  int numSel = m_pLocalLV->getSelectedItems(&fi);
+  if (numSel > 0) {
+    char *pBuf = new char [(numSel + 4) * (MAX_PATH + 3) + strlen(prefix) + 1];
+    sprintf(pBuf, "%sFrom: Local Computer %s\\\n\n", prefix, m_szLocalPath);
+    
+    for (unsigned int i = 0; i < fi.getNumEntries(); i++)
+      sprintf(pBuf, "%s%s, ", pBuf, fi.getNameAt(i));
+    
+    sprintf(pBuf, "%s\n\nTo: Remote Computer %s\\", pBuf, m_szRemotePath);
+    
+    if (strlen(pBuf) > 2048) 
+      sprintf(pBuf, "%sFrom: Local Computer %s\\\n\nTo: Remote Computer %s\\\n\nTotal %d file(s)/folder(s)",
+        prefix, m_szLocalPath, m_szRemotePath, numSel);
+    
+    if (MessageBox(m_hwndFTDialog, pBuf, "Copy Selected Files and Folders", MB_OKCANCEL) == IDOK)
+      m_pFileTransfer->addTransferQueue(m_szLocalPath, m_szRemotePath, &fi, FT_ATTR_COPY_UPLOAD);
+
+    setButtonsState();
+    
+    delete [] pBuf;
+    return;
+  }
+  
+  setButtonsState();
+  setStatusText("File Transfer Impossible. No file(s) selected for transfer");
+}
+
+void 
+FTDialog::onDownload()
+{
+  FileInfo fi;
+  char prefix[FT_FILENAME_SIZE];
+  prefix[0] = '\0';
+
+  if (m_pFileTransfer->isTransferEnable())
+    strcpy(prefix, "File Transfer is active.\nDo you want to add selected file(s)/folder(s) to transfer queue?\n\n");
+  
+  int numSel = m_pRemoteLV->getSelectedItems(&fi);
+  if (numSel > 0) {
+    char *pBuf = new char [(numSel + 4) * (MAX_PATH + 3) + strlen(prefix) + 1];
+    sprintf(pBuf, "%sFrom: Remote Computer %s\\\n\n", prefix, m_szRemotePath);
+    
+    for (unsigned int i = 0; i < fi.getNumEntries(); i++)
+      sprintf(pBuf, "%s%s, ", pBuf, fi.getNameAt(i));
+    
+    sprintf(pBuf, "%s\n\nTo: Local Computer %s\\", pBuf, m_szLocalPath);
+    
+    if (strlen(pBuf) > 2048) 
+      sprintf(pBuf, "%sFrom: Remote Computer %s\\\n\nTo: Local Computer %s\\\n\nTotal %d file(s)/folder(s)",
+        prefix, m_szRemotePath, m_szLocalPath, numSel);
+    
+    if (MessageBox(m_hwndFTDialog, pBuf, "Copy Selected Files and Folders", MB_OKCANCEL) == IDOK)
+      m_pFileTransfer->addTransferQueue(m_szLocalPath, m_szRemotePath, &fi, FT_ATTR_COPY_DOWNLOAD);
+
+    setButtonsState();
+    
+    delete [] pBuf;
+    return;
+  }
+  
+  setButtonsState();
+  setStatusText("File Transfer Impossible. No file(s) selected for transfer");
+}
+
+void 
+FTDialog::onLocalRename()
+{
+  if (m_pRenameDlg != NULL) return;
+
+  FileInfo fi;
+  if (m_pLocalLV->getSelectedItems(&fi) == 1) {
+    unsigned int flags = fi.getFlagsAt(0);
+    m_pRenameDlg = new FTDialog::RenameDlg(this);
+    if (m_pRenameDlg != NULL) {
+      if (flags & FT_ATTR_DIR) {
+        m_pRenameDlg->create(fi.getNameAt(0), true);
+      } else {
+        m_pRenameDlg->create(fi.getNameAt(0), false);
+      }
+      if (strlen(m_pRenameDlg->getFolderName()) > 0) {
+        FolderManager fm;
+        fm.renameIt(m_szLocalPath, fi.getNameAt(0), m_pRenameDlg->getFolderName());
+        showLocalLVItems();
+      }
+      delete m_pRenameDlg;
+      m_pRenameDlg = NULL;
+    }
+  }
+  setButtonsState();
+}
+
+void 
+FTDialog::onRemoteRename()
+{
+  if (m_pRenameDlg != NULL) return;
+
+  FileInfo fi;
+  if (m_pRemoteLV->getSelectedItems(&fi) == 1) {
+    unsigned int flags = fi.getFlagsAt(0);
+    m_pRenameDlg = new FTDialog::RenameDlg(this);
+    if (m_pRenameDlg != NULL) {
+      if (flags & FT_ATTR_DIR) {
+        m_pRenameDlg->create(fi.getNameAt(0), true);
+      } else {
+        m_pRenameDlg->create(fi.getNameAt(0), false);
+      }
+      if (strlen(m_pRenameDlg->getFolderName()) > 0) {
+        m_pFileTransfer->renameRemote(m_szRemotePath, fi.getNameAt(0), m_pRenameDlg->getFolderName());
+      }
+      delete m_pRenameDlg;
+      m_pRenameDlg = NULL;
+    }
+  }
+  setButtonsState();
+}
+
+void 
+FTDialog::onLocalDelete()
+{
+  FileInfo fi;
+  if (m_pLocalLV->getSelectedItems(&fi) > 0) {
+    m_pFileTransfer->addDeleteQueue(m_szLocalPath, &fi, FT_ATTR_DELETE_LOCAL);
+  }
+  setButtonsState();
+}
+
+void 
+FTDialog::onRemoteDelete()
+{
+  FileInfo fi;
+  if (m_pRemoteLV->getSelectedItems(&fi) > 0) {
+    m_pFileTransfer->addDeleteQueue(m_szRemotePath, &fi, FT_ATTR_DELETE_REMOTE);
+  }
+  setButtonsState();
+}
+
+bool
+FTDialog::getCreateFolderName()
+{
+  if (m_pCreateFolderDlg != NULL) return false;
+
+  bool bResult = false;
+
+  m_pCreateFolderDlg = new FTDialog::CreateFolderDlg(this);
+  m_pCreateFolderDlg->create();
+  if (strlen(m_pCreateFolderDlg->getFolderName()) != 0) {
+    strcpy(m_szCreateFolderName, m_pCreateFolderDlg->getFolderName());
+    bResult = true;
+  } else {
+    m_szCreateFolderName[0] = '\0';
+    bResult = false;
+  }
+  delete m_pCreateFolderDlg;
+  m_pCreateFolderDlg = NULL;
+
+  return bResult;
+}
+
+void 
+FTDialog::onLocalCreateFolder()
+{
+  if (getCreateFolderName()) {
+    char path[FT_FILENAME_SIZE];
+    sprintf(path, "%s\\%s", m_szLocalPath, m_szCreateFolderName);
+    setStatusText("Creating Local Folder: %s", path);
+    FolderManager fm;
+    if (fm.createDir(path)) showLocalLVItems();
+  }
+}
+
+void 
+FTDialog::onRemoteCreateFolder()
+{
+  if (getCreateFolderName()) {
+    m_pFileTransfer->createRemoteFolder(m_szRemotePath, m_szCreateFolderName);
+  }
+}
+
+void 
+FTDialog::onFTCancel()
+{
+  if (m_pCancelingDlg != NULL) return;
+
+  m_pCancelingDlg = new CancelingDlg(this);
+
+  m_pCancelingDlg->create();
+}
+
+void 
+FTDialog::cancelTransfer(bool bResult)
+{
+  if (m_pCancelingDlg != NULL) {
+    delete m_pCancelingDlg;
+    m_pCancelingDlg = NULL;
+  }
+
+  setButtonsState();
+
+  if ((m_bCloseDlgAfterCancel) && (bResult)) {
+    m_bCloseDlgAfterCancel = false;
+    closeFTDialog();
+  }
+
+  m_pFileTransfer->m_bCancel = bResult;
+}
+
+void 
+FTDialog::afterCancelTransfer()
+{
+  if (m_pCancelingDlg != NULL) {
+    delete m_pCancelingDlg;
+    m_pCancelingDlg = NULL;
+  }
+}
+
+void
+FTDialog::onFTMenuCommand(int command)
+{
+  switch (command) 
+  {
+  case IDM_FTCOPY:
+    {
+      switch (m_FTMenuSource)
+      {
+        case IDC_FTLOCALLIST:  onUpload();   break;
+        case IDC_FTREMOTELIST: onDownload(); break;
+        default: break;
+      }
+    }
+    break;
+  case IDM_FTRENAME:
+    {
+      switch (m_FTMenuSource)
+      {
+        case IDC_FTLOCALLIST:  onLocalRename();  break;
+        case IDC_FTREMOTELIST: onRemoteRename(); break;
+        default: break;
+      }
+    }
+    break;
+  case IDM_FTDELETE:
+    {
+      switch (m_FTMenuSource)
+      {
+        case IDC_FTLOCALLIST:  onLocalDelete();  break;
+        case IDC_FTREMOTELIST: onRemoteDelete(); break;
+        default: break;
+      }
+    }
+    break;
+  case IDM_FTCANCEL: onFTCancel(); break;
+  case IDM_FTCREATEFOLDER:
+    {
+      switch (m_FTMenuSource)
+      {
+        case IDC_FTLOCALLIST:  onLocalCreateFolder();  break;
+        case IDC_FTREMOTELIST: onRemoteCreateFolder(); break;
+        default: break;
+      }
+    }
+    break;
+  default:
+    break;
+  }
+}
+
+void 
+FTDialog::onLocalRButton()
+{
+  refreshBtnState();
+  m_FTMenuSource = IDC_FTLOCALLIST;
+  showFTMenu(m_BtnState.uploadBtn, m_BtnState.createLocalFldBtn, 
+             m_BtnState.renameLocalBtn, m_BtnState.deleteLocalBtn, 
+             m_BtnState.cancelBtn);
+}
+
+void 
+FTDialog::onRemoteRButton()
+{
+  refreshBtnState();
+  m_FTMenuSource = IDC_FTREMOTELIST;
+  showFTMenu(m_BtnState.downloadBtn, m_BtnState.createRemoteFldBtn, 
+             m_BtnState.renameRemoteBtn, m_BtnState.deleteRemoteBtn, 
+             m_BtnState.cancelBtn);
+}
+
+void
+FTDialog::showFTMenu(bool copyBtnState, bool createFldBtnState, bool renameBtnState, 
+                     bool deleteBtnState, bool cancelBtnState)
+{
+  HMENU hMenu = LoadMenu(m_hInstance, MAKEINTRESOURCE(IDR_FTMENU));
+  HMENU hFTMenu = GetSubMenu(hMenu, 0);
+
+  SetMenuDefaultItem(hFTMenu, IDM_FTCOPY, FALSE);
+
+  SetForegroundWindow(m_hwndFTDialog);
+
+  if (copyBtnState) {
+    EnableMenuItem(hMenu, IDM_FTCOPY, MF_ENABLED);
+  } else {
+    EnableMenuItem(hMenu, IDM_FTCOPY, MF_DISABLED | MF_GRAYED);
+  }
+  if (createFldBtnState) {
+    EnableMenuItem(hMenu, IDM_FTCREATEFOLDER, MF_ENABLED);
+  } else {
+    EnableMenuItem(hMenu, IDM_FTCREATEFOLDER, MF_DISABLED | MF_GRAYED);
+  }
+  if (renameBtnState) {
+    EnableMenuItem(hMenu, IDM_FTRENAME, MF_ENABLED);
+  } else {
+    EnableMenuItem(hMenu, IDM_FTRENAME, MF_DISABLED | MF_GRAYED);
+  }
+  if (deleteBtnState) {
+    EnableMenuItem(hMenu, IDM_FTDELETE, MF_ENABLED);
+  } else {
+    EnableMenuItem(hMenu, IDM_FTDELETE, MF_DISABLED | MF_GRAYED);
+  }
+  if (cancelBtnState) {
+    EnableMenuItem(hMenu, IDM_FTCANCEL, MF_ENABLED);
+  } else {
+    EnableMenuItem(hMenu, IDM_FTCANCEL, MF_DISABLED | MF_GRAYED);
+  }
+  DrawMenuBar(m_hwndFTDialog);
+
+  POINT cursorPosition;
+  GetCursorPos(&cursorPosition);
+  TrackPopupMenu(hFTMenu, 0, cursorPosition.x, cursorPosition.y, 0, m_hwndFTDialog, 0);
+  DestroyMenu(hFTMenu);
+}
+
+void
+FTDialog::setIcon(int dest, int idIcon)
+{
+  HANDLE hIcon = LoadImage(m_hInstance, MAKEINTRESOURCE(idIcon), IMAGE_ICON, 16, 16, LR_SHARED);
+  SendMessage(GetDlgItem(m_hwndFTDialog, dest), BM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) hIcon);
+  DestroyIcon((HICON) hIcon);
+}
+
+void
+FTDialog::refreshBtnState()
+{
+  if (!m_bDlgShown) return;
+  
+  int locPathLen = strlen(m_szLocalPath);
+  int remPathLen = strlen(m_szRemotePath);
+  
+  if (GetFocus() == m_pLocalLV->getWndHandle()) {
+    m_BtnState.downloadBtn = false;
+    if (strlen(m_szLocalPath) != 0) {
+      m_BtnState.createLocalFldBtn = true;
+      int nCount = ListView_GetSelectedCount(m_pLocalLV->getWndHandle());
+      if (nCount <= 0) {
+        m_BtnState.uploadBtn = false;
+        m_BtnState.deleteLocalBtn = false;
+        m_BtnState.renameLocalBtn = false;
+      } else {
+        m_BtnState.deleteLocalBtn = true;
+        if (remPathLen == 0) {
+          m_BtnState.uploadBtn = false;
+        } else {
+          m_BtnState.uploadBtn = true;
+        }
+        if (nCount == 1) {
+          m_BtnState.renameLocalBtn = true;
+        } else {
+          m_BtnState.renameLocalBtn = false;
+        }
+      }
+    } else {
+      m_BtnState.uploadBtn = false;
+      m_BtnState.createLocalFldBtn = false;
+      m_BtnState.deleteLocalBtn = false;
+      m_BtnState.renameLocalBtn = false;
+      m_BtnState.downloadBtn = false;
+    }
+  } else {
+    if (GetFocus() == m_pRemoteLV->getWndHandle()) {
+      m_BtnState.uploadBtn = false;
+      if (strlen(m_szRemotePath) != 0) {
+        m_BtnState.createRemoteFldBtn = true;
+        int nCount = ListView_GetSelectedCount(m_pRemoteLV->getWndHandle());
+        if (nCount <= 0) {
+          m_BtnState.downloadBtn = false;
+          m_BtnState.deleteRemoteBtn = false;
+          m_BtnState.renameRemoteBtn = false;
+        } else {
+          m_BtnState.deleteRemoteBtn = true;
+          if (locPathLen == 0) {
+            m_BtnState.downloadBtn = false;
+          } else {
+            m_BtnState.downloadBtn = true;
+          }
+          if (nCount == 1) {
+            m_BtnState.renameRemoteBtn = true;
+          } else {
+            m_BtnState.renameRemoteBtn = false;
+          }
+        }
+      } else {
+        m_BtnState.downloadBtn = false;
+        m_BtnState.createRemoteFldBtn = false;
+        m_BtnState.deleteRemoteBtn = false;
+        m_BtnState.renameRemoteBtn = false;
+        m_BtnState.uploadBtn = false;
+      }
+    } else {
+    }
+  }
+  if (m_pFileTransfer->isTransferEnable()) 
+    m_BtnState.cancelBtn = true;
+  else
+    m_BtnState.cancelBtn = false;
+}
+
+void
+FTDialog::setButtonsState()
+{
+  refreshBtnState();
+
+  switch (m_BtnState.uploadBtn)
+  {
+  case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTUPLOAD), FALSE); break;
+  case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTUPLOAD), TRUE); break;
+  }
+
+  switch (m_BtnState.downloadBtn)
+  {
+  case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTDOWNLOAD), FALSE); break;
+  case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTDOWNLOAD), TRUE); break;
+  }
+
+  switch (m_BtnState.cancelBtn)
+  {
+  case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTCANCEL), FALSE); break;
+  case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTCANCEL), TRUE); break;
+  }
+
+  UpdateWindow(m_hwndFTDialog);
+}
+
+void 
+FTDialog::setStatusText(LPCSTR format,...)
+{
+  char text[1024];
+  va_list args;
+  va_start(args, format);
+  int nSize = _vsnprintf(text, sizeof(text), format, args);
+
+  HWND hStatusBox = GetDlgItem(m_hwndFTDialog, IDC_FTSTATUS);
+
+  LRESULT lRes = SendMessage(hStatusBox, (UINT) CB_INSERTSTRING, (WPARAM) 0, (LPARAM) text);
+  if ((lRes != CB_ERR) && (lRes != CB_ERRSPACE)) {
+    lRes = SendMessage(hStatusBox, (UINT) CB_SETCURSEL, (WPARAM) lRes, (LPARAM) 0);
+  }
+  
+  m_dwNumStatusStrings++;
+  if (m_dwNumStatusStrings > FT_MAX_STATUS_STRINGS) {
+    int numItems = SendMessage(hStatusBox, (UINT) CB_GETCOUNT, (WPARAM) 0, (LPARAM) 0); 
+    if (numItems != CB_ERR) {
+      m_dwNumStatusStrings--;
+      SendMessage(hStatusBox, (UINT) CB_DELETESTRING, (WPARAM) numItems - 1, (LPARAM) 0); 
+    }
+  }
+}
+
+void 
+FTDialog::getBrowseItems(char *pPath)
+{
+  if (m_bLocalBrowsing) {
+    FileInfo fi;
+    FolderManager fm;
+    fm.getDirInfo(pPath, &fi, 1);
+    if (m_pBrowseDlg != NULL) m_pBrowseDlg->addItems(&fi);
+  } else {
+    m_pFileTransfer->requestFileList(pPath, FT_FLR_DEST_BROWSE, true);
+  }
+}
+
+void 
+FTDialog::addBrowseItems(FileInfo *pFI)
+{
+  if (m_pBrowseDlg == NULL) return;
+
+  m_pBrowseDlg->addItems(pFI);
+}
+
+void 
+FTDialog::processDlgMsgs()
+{
+  MSG msg;
+  while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+}
+
+void 
+FTDialog::postCheckTransferQueueMsg()
+{
+  PostMessage(m_hwndFTDialog, m_msgCheckTransferQueue, 0, 0);
+}
+
+void 
+FTDialog::postUploadFilePortionMsg()
+{
+  PostMessage(m_hwndFTDialog, m_msgUploadFilePortion, 0, 0);
+}
+
+void 
+FTDialog::postCheckDeleteQueueMsg()
+{
+  PostMessage(m_hwndFTDialog, m_msgCheckDeleteQueue, 0, 0);
+}
+
+FTDialog::CancelingDlg::CancelingDlg(FTDialog *pFTDlg)
+{
+  m_pFTDlg = pFTDlg;
+  m_hwndDlg = NULL;
+}
+
+FTDialog::CancelingDlg::~CancelingDlg()
+{
+  destroy();
+}
+
+bool 
+FTDialog::CancelingDlg::create()
+{
+  if (m_hwndDlg != NULL) return false;
+
+  m_hwndDlg = CreateDialogParam(GetModuleHandle(0), 
+                                MAKEINTRESOURCE(IDD_FTCANCELING),
+                                NULL, 
+                                (DLGPROC) cancelingDlgProc,
+                                (LONG) this);
+
+  if (m_hwndDlg == NULL) return false;
+
+  ShowWindow(m_hwndDlg, SW_SHOW);
+  DrawIcon(GetDC(m_hwndDlg), 15, 22, LoadIcon(NULL, IDI_QUESTION));
+  UpdateWindow(m_hwndDlg);
+
+  return true;
+}
+
+bool 
+FTDialog::CancelingDlg::destroy()
+{
+  if (m_hwndDlg == NULL) return true;
+
+  if (DestroyWindow(m_hwndDlg)) {
+    m_hwndDlg = NULL;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool
+FTDialog::CancelingDlg::close(bool bResult)
+{
+  if (m_hwndDlg == NULL) return true;
+
+  destroy();
+
+  m_pFTDlg->cancelTransfer(bResult);
+
+  return false;
+}
+
+BOOL CALLBACK 
+FTDialog::CancelingDlg::cancelingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  FTDialog::CancelingDlg *_this = (FTDialog::CancelingDlg *) GetWindowLong(hwnd, GWL_USERDATA);
+  switch (uMsg)
+  {
+  case WM_INITDIALOG:
+      SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
+      SetForegroundWindow(hwnd);
+    return TRUE;
+
+  case WM_COMMAND:
+    switch (LOWORD(wParam))
+    {
+    case IDOK:
+      _this->close(true);
+      return TRUE;
+    case IDCANCEL:
+      _this->close(false);
+      return TRUE;
+    }
+    break;
+    case WM_CLOSE:
+      _this->close(false);
+      return TRUE;
+  }
+  return FALSE;
+}
+
+FTDialog::CreateFolderDlg::CreateFolderDlg(FTDialog *pFTDlg) : Dialog(GetModuleHandle(0))
+{
+  m_pFTDlg = pFTDlg;
+  m_szFolderName[0] = '\0';
+}
+
+FTDialog::CreateFolderDlg::~CreateFolderDlg()
+{
+
+}
+
+bool
+FTDialog::CreateFolderDlg::create()
+{
+  return showDialog(MAKEINTRESOURCE(IDD_FTCREATEFOLDER), m_pFTDlg->getWndHandle());
+}
+
+bool 
+FTDialog::CreateFolderDlg::onOk()
+{
+  strcpy(m_szFolderName, getItemString(IDC_FTFOLDERNAME));
+  return true;
+}
+
+FTDialog::RenameDlg::RenameDlg(FTDialog *pFTDlg) : CreateFolderDlg(pFTDlg)
+{
+  m_bFolder = false;
+}
+
+FTDialog::RenameDlg::~RenameDlg()
+{
+}
+
+bool 
+FTDialog::RenameDlg::create(char *pFilename, bool bFolder)
+{
+  m_bFolder = bFolder;
+  strcpy(m_szFilename, pFilename);
+  return showDialog(MAKEINTRESOURCE(IDD_FTCREATEFOLDER), m_pFTDlg->getWndHandle());
+}
+
+void
+FTDialog::RenameDlg::initDialog()
+{
+  char buf[2*FT_FILENAME_SIZE];
+  if (m_bFolder) {
+    SetWindowText(handle, "Rename Folder");
+    sprintf(buf, "Rename Folder '%s'", m_szFilename);
+  } else {
+    SetWindowText(handle, "Rename File");
+    sprintf(buf, "Rename File '%s'", m_szFilename);
+  }
+
+  setItemString(IDC_FTTEXT, buf);
+  setItemString(IDC_FTFOLDERNAME, m_szFilename);
+  SendDlgItemMessage(handle, IDC_FTFOLDERNAME, EM_SETSEL, (WPARAM) 0, (LPARAM) -1);
+}
diff --git a/win/vncviewer/FTDialog.h b/win/vncviewer/FTDialog.h
new file mode 100644
index 0000000..a4b5546
--- /dev/null
+++ b/win/vncviewer/FTDialog.h
@@ -0,0 +1,243 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTDialog.h
+
+#ifndef __RFB_WIN32_FTDIALOG_H__
+#define __RFB_WIN32_FTDIALOG_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb_win32/Dialog.h>
+#include <vncviewer/FileTransfer.h>
+#include <vncviewer/FTListView.h>
+#include <vncviewer/FTProgress.h>
+#include <vncviewer/FTBrowseDlg.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+  namespace win32 {
+    class FileTransfer;
+    class FTBrowseDlg;
+
+    class FTDialog
+    {
+    public:
+      FTDialog(HINSTANCE hInst, FileTransfer *pFT);
+      ~FTDialog();
+      
+      bool createFTDialog(HWND hwndParent);
+      bool closeFTDialog();
+      void destroyFTDialog();
+
+      void processDlgMsgs();
+
+      void cancelTransfer(bool bResult);
+      void afterCancelTransfer();
+      
+      static BOOL CALLBACK FTDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+      
+      void addRemoteLVItems(FileInfo *pFI);
+      void reqFolderUnavailable();
+
+      void onEndBrowseDlg(bool bResult);
+      void getBrowseItems(char *pPath);
+      void addBrowseItems(FileInfo *pFI);
+
+      void setStatusText(LPCSTR format,...);
+
+      HWND getWndHandle() { return m_hwndFTDialog; }
+
+      void postCheckDeleteQueueMsg();
+      void postCheckTransferQueueMsg();
+      void postUploadFilePortionMsg();
+      void postDownloadFilePortionMsg();
+
+      char *getLocalPath() { return m_szLocalPath; }
+      char *getRemotePath() { return m_szRemotePath; }
+
+      FTProgress *m_pProgress;
+      FileTransfer *m_pFileTransfer;
+      
+    private:
+      HWND m_hwndFTDialog;
+      HWND m_hwndLocalPath;
+      HWND m_hwndRemotePath;
+      HINSTANCE m_hInstance;
+      
+      void showLocalLVItems();
+      void showRemoteLVItems();
+
+      void onClose();
+
+      void onLocalItemActivate(LPNMITEMACTIVATE lpnmia);
+      void onRemoteItemActivate(LPNMITEMACTIVATE lpnmia);
+
+      void onLocalBrowse();
+      void onRemoteBrowse();
+
+      void onLocalReload();
+      void onRemoteReload();
+
+      void onLocalRButton();
+      void onRemoteRButton();
+
+      bool getCreateFolderName();
+      void onLocalCreateFolder();
+      void onRemoteCreateFolder();
+
+      void showFTMenu(bool copyBtnState, bool createFldBtnState, 
+                      bool renameBtnState, bool deleteBtnState, 
+                      bool cancelBtnState);
+      void onFTMenuCommand(int command);
+
+      void onUpload();
+      void onDownload();
+
+      void onLocalRename();
+      void onRemoteRename();
+
+      void onLocalDelete();
+      void onRemoteDelete();
+
+      void onFTCancel();
+
+      void setIcon(int dest, int idIcon);
+      bool initFTDialog();
+      bool initFTWndMsgs();
+      
+      void onLocalOneUpFolder();
+      void onRemoteOneUpFolder();
+      int makeOneUpFolder(char *pPath);
+
+      void refreshBtnState();
+      void setButtonsState();
+      
+      bool m_bDlgShown;
+      bool m_bLocalBrowsing;
+      bool m_bCloseDlgAfterCancel;
+
+      UINT m_msgCheckDeleteQueue;
+      UINT m_msgCheckTransferQueue;
+      UINT m_msgUploadFilePortion;
+      UINT m_msgDownloadFilePortion;
+
+      DWORD m_dwNumStatusStrings;
+
+      FTListView *m_pLocalLV;
+      FTListView *m_pRemoteLV;
+
+      FTBrowseDlg *m_pBrowseDlg;
+
+      int m_FTMenuSource;
+
+      char m_szLocalPath[FT_FILENAME_SIZE];
+      char m_szRemotePath[FT_FILENAME_SIZE];
+      char m_szLocalPathTmp[FT_FILENAME_SIZE];
+      char m_szRemotePathTmp[FT_FILENAME_SIZE];
+      char m_szCreateFolderName[FT_FILENAME_SIZE];
+
+      static const char szCheckDeleteQueueText[];
+      static const char szCheckTransferQueueText[];
+      static const char szUploadFilePortionText[];
+
+      typedef struct tagFTBUTTONSSTATE
+      {
+        bool uploadBtn;
+        bool downloadBtn;
+        bool createLocalFldBtn;
+        bool createRemoteFldBtn;
+        bool renameLocalBtn;
+        bool renameRemoteBtn;
+        bool deleteLocalBtn;
+        bool deleteRemoteBtn;
+        bool cancelBtn;
+      } FTBUTTONSSTATE;
+
+      FTBUTTONSSTATE m_BtnState;
+
+    public:
+      class CancelingDlg
+      {
+      public:
+        CancelingDlg(FTDialog *pFTDlg);
+        ~CancelingDlg();
+
+        static BOOL CALLBACK cancelingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+        bool create();
+        bool destroy();
+
+      private:
+        FTDialog *m_pFTDlg;
+        HWND m_hwndDlg;
+
+        bool close(bool bResult);
+      };
+
+    private:
+        CancelingDlg *m_pCancelingDlg;
+
+    public:
+      class CreateFolderDlg : public Dialog
+      {
+      public:
+        CreateFolderDlg(FTDialog *pFTDlg);
+        ~CreateFolderDlg();
+
+        bool onOk();
+        bool create();
+        char *getFolderName() { return m_szFolderName; }
+
+      protected:
+        FTDialog *m_pFTDlg;
+        char m_szFolderName[FT_FILENAME_SIZE];
+      };
+
+      private:
+        CreateFolderDlg *m_pCreateFolderDlg;
+
+    public:
+      class RenameDlg : public CreateFolderDlg
+      {
+      public:
+        RenameDlg(FTDialog *pFTDlg);
+        ~RenameDlg();
+
+        bool create(char *pFilename, bool bFolder);
+        void initDialog();
+
+      private:
+        bool m_bFolder;
+        char m_szFilename[FT_FILENAME_SIZE];
+      };
+
+    private:
+        RenameDlg *m_pRenameDlg;
+    };
+  }
+}
+
+#endif // __RFB_WIN32_FTDIALOG_H__
diff --git a/win/vncviewer/FTListView.cxx b/win/vncviewer/FTListView.cxx
new file mode 100644
index 0000000..8f41abf
--- /dev/null
+++ b/win/vncviewer/FTListView.cxx
@@ -0,0 +1,211 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTListView.cxx
+
+#include <vncviewer/FTListView.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTListView::FTListView(HWND hListView)
+{
+  m_bInitialized = false;
+  m_hListView = hListView;
+  m_fileInfo.free();
+}
+
+FTListView::~FTListView()
+{
+  m_fileInfo.free();
+}
+
+
+bool 
+FTListView::initialize(HINSTANCE hInst)
+{
+  if (m_bInitialized) return false;
+
+  initImageList(hInst);
+  
+  RECT Rect;
+  GetClientRect(m_hListView, &Rect);
+  Rect.right -= GetSystemMetrics(SM_CXHSCROLL);
+  int xwidth0 = (int) (0.35 * Rect.right);
+  int xwidth1 = (int) (0.22 * Rect.right);
+  int xwidth2 = (int) (0.43 * Rect.right);
+  
+  addColumn("Name", 0, xwidth0, LVCFMT_LEFT);
+  addColumn("Size", 1, xwidth1, LVCFMT_RIGHT);
+  addColumn("Data", 2, xwidth2, LVCFMT_LEFT);
+
+  ListView_SetExtendedListViewStyleEx(m_hListView, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
+ 
+  return true;
+}
+
+void 
+FTListView::onGetDispInfo(NMLVDISPINFO *pDI)
+{
+  if (m_fileInfo.getFlagsAt(pDI->item.iItem) & FT_ATTR_DIR) {
+    pDI->item.iImage = 0;
+  } else {
+    pDI->item.iImage = 1;
+  }
+  
+  switch (pDI->item.iSubItem)
+  {
+  case 0:
+    pDI->item.pszText = m_fileInfo.getNameAt(pDI->item.iItem);
+    break;
+  case 1:
+    {
+      unsigned int flags = m_fileInfo.getFlagsAt(pDI->item.iItem);
+      switch(flags & 0x000000FF)
+      {
+      case FT_ATTR_FILE:
+        {
+          char buf[32];
+          unsigned int size = m_fileInfo.getSizeAt(pDI->item.iItem);
+          sprintf(buf, "%u", size);
+          pDI->item.pszText = buf;
+        }
+        break;
+      case FT_ATTR_DIR:
+        pDI->item.pszText = "";
+        break;
+      default:
+        pDI->item.pszText = "Unspecified";
+      }
+    }
+    break;
+  case 2:
+    {
+      unsigned int data = m_fileInfo.getDataAt(pDI->item.iItem);
+      if (data == 0) {
+        pDI->item.pszText = "Unspecified";
+      } else {
+        FILETIME ft;
+        FolderManager fm;
+        fm.getFiletime(data, &ft);
+        
+        SYSTEMTIME st;
+        FileTimeToSystemTime(&ft, &st);
+        
+        char pDateTimeStr[1024];
+        char timeFmt[128];
+        GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, timeFmt, 128);
+        char dateFmt[128];
+        GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, dateFmt, 128);
+        
+        char timeStr[128];
+        GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, timeFmt, timeStr, 128);
+        char dateStr[128];
+        GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, dateFmt, dateStr, 128);
+        
+        sprintf(pDateTimeStr, "%s %s", dateStr, timeStr);
+        pDI->item.pszText = pDateTimeStr;
+      }
+    }
+    break;
+  default:
+    break;
+  }
+}
+
+void 
+FTListView::addItems(FileInfo *pFI)
+{
+  m_fileInfo.add(pFI);
+  LVITEM LVItem;
+  LVItem.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE; 
+  LVItem.state = 0; 
+  LVItem.stateMask = 0; 
+  for (unsigned int i = 0; i < m_fileInfo.getNumEntries(); i++) {
+    LVItem.iItem = i;
+    LVItem.iSubItem = 0;
+    LVItem.iImage = I_IMAGECALLBACK;
+    LVItem.pszText = LPSTR_TEXTCALLBACK;
+    ListView_InsertItem(m_hListView, &LVItem);
+  }
+}
+
+void 
+FTListView::deleteAllItems()
+{
+  ListView_DeleteAllItems(m_hListView);
+  m_fileInfo.free();
+}
+
+char *
+FTListView::getActivateItemName(LPNMITEMACTIVATE lpnmia)
+{
+  return m_fileInfo.getNameAt(lpnmia->iItem);
+}
+
+int 
+FTListView::getSelectedItems(FileInfo *pFI)
+{
+  int selCount = ListView_GetSelectedCount(m_hListView);
+  int selItem = ListView_GetSelectionMark(m_hListView);
+  if ((selCount < 1) || (selItem < 0)) return -1;
+  
+  selItem = -1;
+  selItem = ListView_GetNextItem(m_hListView, selItem, LVNI_SELECTED);
+  do {
+    pFI->add(m_fileInfo.getFullDataAt(selItem));
+    selItem = ListView_GetNextItem(m_hListView, selItem, LVNI_SELECTED);
+  } while (selItem >= 0);
+  
+  return selCount;
+}
+
+void
+FTListView::initImageList(HINSTANCE hInst)
+{
+  m_hImageList = ImageList_Create(16, 16, ILC_MASK, 2, 2); 
+  
+  HICON hiconItem = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FTDIR)); 
+  ImageList_AddIcon(m_hImageList, hiconItem);  
+  DestroyIcon(hiconItem); 
+  
+  hiconItem = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FTFILE)); 
+  ImageList_AddIcon(m_hImageList, hiconItem); 
+  DestroyIcon(hiconItem); 
+  
+  ListView_SetImageList(m_hListView, m_hImageList, LVSIL_SMALL); 
+}
+
+void 
+FTListView::addColumn(char *iText, int iOrder, int xWidth, int alignFmt)
+{
+	LVCOLUMN lvc; 
+	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
+	lvc.fmt = alignFmt;
+	lvc.iSubItem = iOrder;
+	lvc.pszText = iText;	
+	lvc.cchTextMax = 32;
+	lvc.cx = xWidth;
+	lvc.iOrder = iOrder;
+	ListView_InsertColumn(m_hListView, iOrder, &lvc);
+}
diff --git a/win/vncviewer/FTListView.h b/win/vncviewer/FTListView.h
new file mode 100644
index 0000000..c920fa0
--- /dev/null
+++ b/win/vncviewer/FTListView.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTListView.h
+
+#ifndef __RFB_WIN32_FTLISTVIEW_H__
+#define __RFB_WIN32_FTLISTVIEW_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb_win32/FolderManager.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+  namespace win32{
+    class FTListView
+    {
+    public:
+      FTListView(HWND hListView);
+      ~FTListView();
+
+      bool initialize(HINSTANCE hInst);
+      
+      void onGetDispInfo(NMLVDISPINFO *di);
+      void addItems(FileInfo *pFI);
+      void deleteAllItems();
+      
+      char *getActivateItemName(LPNMITEMACTIVATE lpnmia);
+      int getSelectedItems(FileInfo *pFI);
+      
+      HWND getWndHandle() { return m_hListView; };
+      
+    private:
+      HWND m_hListView;
+      FileInfo m_fileInfo;
+      HIMAGELIST m_hImageList;
+
+      bool m_bInitialized;
+
+      void addColumn(char *iText, int iOrder, int xWidth, int alignFmt);
+      void initImageList(HINSTANCE hInst);
+      
+    };
+  }
+}
+
+#endif // __RFB_WIN32_FTLISTVIEW_H__
diff --git a/win/vncviewer/FTProgress.cxx b/win/vncviewer/FTProgress.cxx
new file mode 100644
index 0000000..e6cc952
--- /dev/null
+++ b/win/vncviewer/FTProgress.cxx
@@ -0,0 +1,151 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTProgress.cxx
+
+#include <vncviewer/FTProgress.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTProgress::FTProgress(HWND hwndParent)
+{
+  m_bInitialized = false;
+  m_hwndParent = hwndParent;
+
+  m_pSingleProgress = NULL;
+  m_pGeneralProgress = NULL;
+
+  m_hwndSinglePercent = GetDlgItem(m_hwndParent, IDC_FTSINGLEPERCENT);
+  m_hwndGeneralPercent = GetDlgItem(m_hwndParent, IDC_FTGENERALPERCENT);
+
+  m_bInitialized = createProgressBarObjects();
+}
+
+FTProgress::~FTProgress()
+{
+  destroyProgressBarObjects();
+}
+
+void
+FTProgress::increase(DWORD value)
+{
+  if (!m_bInitialized) return;
+
+  m_pSingleProgress->increase(value);
+  m_pGeneralProgress->increase(value);
+
+  setProgressText();
+}
+
+void
+FTProgress::clearAndInitGeneral(DWORD64 dw64MaxValue, DWORD64 dw64Position)
+{
+  if (!m_bInitialized) return;
+
+  m_pGeneralProgress->clear();
+  m_pGeneralProgress->init(dw64MaxValue, dw64Position);
+
+  setProgressText();
+}
+
+void
+FTProgress::clearAndInitSingle(DWORD dwMaxValue, DWORD dwPosition)
+{
+  if (!m_bInitialized) return;
+
+  m_pSingleProgress->clear();
+  m_pSingleProgress->init(dwMaxValue, dwPosition);
+
+  setProgressText();
+}
+
+void
+FTProgress::clearAll()
+{
+  if (!m_bInitialized) return;
+
+  m_pSingleProgress->clear();
+  m_pGeneralProgress->clear();
+
+  setProgressText();
+}
+
+bool 
+FTProgress::createProgressBarObjects()
+{
+  if ((m_pSingleProgress != NULL) || (m_pGeneralProgress != NULL)) {
+    return false;
+  } else {
+    HWND hwndSingleProgr = GetDlgItem(m_hwndParent, IDC_FTSINGLEPROGRESS);
+    HWND hwndGeneralProgr = GetDlgItem(m_hwndParent, IDC_FTGENERALPROGRESS);
+    
+    m_pSingleProgress = new ProgressControl(hwndSingleProgr);
+    if (m_pSingleProgress == NULL) return false;
+    
+    m_pGeneralProgress = new ProgressControl(hwndGeneralProgr);
+    if (m_pGeneralProgress == NULL) {
+      delete m_pSingleProgress;
+      m_pSingleProgress = NULL;
+      return false;
+    }
+  }
+  return true;
+}
+
+bool 
+FTProgress::destroyProgressBarObjects()
+{
+  clearAll();
+
+  if (m_pSingleProgress != NULL) {
+    delete m_pSingleProgress;
+    m_pSingleProgress = NULL;
+  }
+
+  if (m_pGeneralProgress != NULL) {
+    delete m_pGeneralProgress;
+    m_pGeneralProgress = NULL;
+  }
+
+  return true;
+}
+
+void
+FTProgress::setProgressText()
+{
+  char buf[16] = {0};
+  char buf2[16] = {0};
+  
+  int percent = m_pSingleProgress->getCurrentPercent();
+  sprintf(buf, "%d%%", percent);
+  GetWindowText(m_hwndSinglePercent, buf2, 16);
+  if (strcmp(buf, buf2) != 0)
+    SetWindowText(m_hwndSinglePercent, buf);
+  
+  percent = m_pGeneralProgress->getCurrentPercent();
+  sprintf(buf, "%d%%", percent);
+  GetWindowText(m_hwndGeneralPercent, buf2, 16);
+  if (strcmp(buf, buf2) != 0)
+    SetWindowText(m_hwndGeneralPercent, buf);
+}
\ No newline at end of file
diff --git a/win/vncviewer/FTProgress.h b/win/vncviewer/FTProgress.h
new file mode 100644
index 0000000..caad779
--- /dev/null
+++ b/win/vncviewer/FTProgress.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTProgress.h
+
+#ifndef __RFB_WIN32_FTPROGRESS_H__
+#define __RFB_WIN32_FTPROGRESS_H__
+
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#include <rfb_win32/ProgressControl.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+  namespace win32 {
+    class FTProgress
+    {
+    public:
+      FTProgress(HWND hwndParent);
+      ~FTProgress();
+      
+      void increase(DWORD value);
+      void clearAndInitGeneral(DWORD64 dw64MaxValue, DWORD64 dw64Position);
+      void clearAndInitSingle(DWORD dwMaxValue, DWORD dwPosition);
+      void clearAll();
+
+    private:
+      ProgressControl *m_pSingleProgress;
+      ProgressControl *m_pGeneralProgress;
+
+      HWND m_hwndParent;
+      HWND m_hwndSinglePercent;
+      HWND m_hwndGeneralPercent;
+
+      bool m_bInitialized;
+
+      void setProgressText();
+      bool createProgressBarObjects();
+      bool destroyProgressBarObjects();
+    };
+  }
+}
+
+#endif // __RFB_WIN32_FTPROGRESS_H__
diff --git a/win/vncviewer/FileTransfer.cxx b/win/vncviewer/FileTransfer.cxx
new file mode 100644
index 0000000..cf57072
--- /dev/null
+++ b/win/vncviewer/FileTransfer.cxx
@@ -0,0 +1,803 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileTransfer.cxx
+
+#include <vncviewer/FileTransfer.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FileTransfer::FileTransfer()
+{
+  m_bFTDlgShown = false;
+  m_bInitialized = false;
+  m_bResized = false;
+  m_bCancel = false;
+  m_bOverwriteAll = false;
+
+  m_pFTDialog = new FTDialog(GetModuleHandle(0), this);
+
+  m_pReader = NULL;
+  m_pWriter = NULL;
+
+  m_dw64SizeSending = 0;
+  m_dirSizeRqstNum = 0;
+}
+
+FileTransfer::~FileTransfer()
+{
+  if (m_pFTDialog != NULL) {
+    delete m_pFTDialog;
+    m_pFTDialog = NULL;
+  }
+  
+  if (m_pReader != NULL) {
+    delete m_pReader;
+    m_pReader = NULL;
+  }
+
+  if (m_pWriter != NULL) {
+    delete m_pWriter;
+    m_pWriter = NULL;
+  }
+
+  freeQueues();
+}
+
+bool 
+FileTransfer::initialize(rdr::InStream *pIS, rdr::OutStream *pOS)
+{
+  if (m_bInitialized) return false;
+
+  m_pReader = new CFTMsgReader(pIS);
+  m_pWriter = new CFTMsgWriter(pOS);
+
+  freeQueues();
+
+  m_bInitialized = true;
+  return true;
+}
+
+bool 
+FileTransfer::show(HWND hwndParent)
+{
+  if (!m_bInitialized) return false;
+
+  m_bFTDlgShown = m_pFTDialog->createFTDialog(hwndParent);
+
+  return m_bFTDlgShown;
+}
+
+bool
+FileTransfer::processFTMsg(int type)
+{
+  if (!m_bInitialized) return false;
+
+  switch (type)
+  {
+  case msgTypeFileListData:
+    return procFileListDataMsg();
+  case msgTypeFileDownloadData:
+    return procFileDownloadDataMsg();
+  case msgTypeFileUploadCancel:
+    return procFileUploadCancelMsg();
+  case msgTypeFileDownloadFailed:
+    return procFileDownloadFailedMsg();
+  case msgTypeFileDirSizeData:
+    return procFileDirSizeDataMsg();
+  case msgTypeFileLastRequestFailed:
+    return procFileLastRqstFailedMsg();
+  default:
+    return false;
+  }
+}
+
+bool 
+FileTransfer::isTransferEnable()
+{
+  if (m_TransferQueue.getNumEntries() > 0) return true; else return false;
+}
+
+void 
+FileTransfer::addDeleteQueue(char *pPathPrefix, FileInfo *pFI, unsigned int flags)
+{
+  if ((m_bFTDlgShown) && (m_DeleteQueue.getNumEntries() > 0)) 
+    m_pFTDialog->setStatusText("Starting Delete Operation");
+
+  m_DeleteQueue.add(pPathPrefix, pPathPrefix, pFI, flags);
+
+  checkDeleteQueue();
+}
+
+void
+FileTransfer::checkDeleteQueue()
+{
+  if (m_DeleteQueue.getNumEntries() > 0) {
+    if (m_bFTDlgShown) 
+      m_pFTDialog->setStatusText("Delete Operation Executing: %s", m_DeleteQueue.getFullLocPathAt(0));
+    if (m_DeleteQueue.getFlagsAt(0) & FT_ATTR_DELETE_LOCAL) {
+      FolderManager fm;
+      if (!fm.deleteIt(m_DeleteQueue.getFullLocPathAt(0))) {
+        if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Failed");
+      } else {
+        if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Completed");
+      }
+      m_DeleteQueue.deleteAt(0);
+      m_pFTDialog->postCheckDeleteQueueMsg();
+    } else {
+      if (m_DeleteQueue.getFlagsAt(0) & FT_ATTR_DELETE_REMOTE) {
+        writeFileDeleteRqst(strlen(m_DeleteQueue.getFullLocPathAt(0)), 
+                            m_DeleteQueue.getFullLocPathAt(0));
+
+        char *pPath = m_DeleteQueue.getLocPathAt(0);
+        m_queueFileListRqst.add(pPath, 0, 0, FT_FLR_DEST_DELETE);
+        writeFileListRqst(strlen(pPath), pPath, false);
+      }
+    }
+  } else {
+    if (m_bFTDlgShown) {
+      m_pFTDialog->setStatusText("Delete Operation Completed Successfully");
+      PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+      PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTREMOTERELOAD, 0), 0);
+    }
+  }
+}
+
+void 
+FileTransfer::addTransferQueue(char *pLocalPath, char *pRemotePath, 
+                               FileInfo *pFI, unsigned int flags)
+{
+  if (!isTransferEnable()) {
+    if (m_bFTDlgShown) m_pFTDialog->setStatusText("Starting Copy Operation");
+    m_bTransferSuccess = true;
+  }
+  
+  m_TransferQueue.add(pLocalPath, pRemotePath, pFI, (flags | FT_ATTR_RESIZE_NEEDED));
+
+  checkTransferQueue();
+}
+
+bool
+FileTransfer::resizeSending()
+{
+  for (unsigned int i = 0; i < m_TransferQueue.getNumEntries(); i++) {
+    unsigned int flags = m_TransferQueue.getFlagsAt(i);
+    if (flags & FT_ATTR_RESIZE_NEEDED) {
+      if (flags & FT_ATTR_FILE) {
+        m_bResized = true;
+        m_dw64SizeSending += m_TransferQueue.getSizeAt(i);
+        m_TransferQueue.clearFlagAt(i, FT_ATTR_RESIZE_NEEDED);
+      } else {
+        if (flags & FT_ATTR_DIR) {
+          if (flags & FT_ATTR_COPY_DOWNLOAD) {
+            m_bResized = true;
+            char *pPath = m_TransferQueue.getFullRemPathAt(i);
+            m_dirSizeRqstNum = i;
+            writeFileDirSizeRqst(strlen(pPath), pPath);
+            return false;
+          } else {
+            if (flags & FT_ATTR_COPY_UPLOAD) {
+              FolderManager fm;
+              DWORD64 dw64Size;
+              m_bResized = true;
+              fm.getDirSize(m_TransferQueue.getFullLocPathAt(i), &dw64Size);
+              m_dw64SizeSending += dw64Size;
+              m_TransferQueue.clearFlagAt(i, FT_ATTR_RESIZE_NEEDED);
+            }
+          } // if (flags & FT_ATTR_COPY_DOWNLOAD)
+        } // if (flags & FT_ATTR_FOLDER)
+      } // if (flags & FT_ATTR_FILE)
+    } // if (flags & FT_ATTR_NEEDED_RESIZE)
+  } // for (unsigned int i = 0; i < m_TransferQueue.getNumEntries(); i++)
+
+  if ((m_bFTDlgShown) && (m_bResized)) {
+    m_pFTDialog->m_pProgress->clearAndInitGeneral(m_dw64SizeSending, 0);
+    m_bResized = false;
+  }
+
+  return true;
+}
+
+void
+FileTransfer::checkTransferQueue()
+{
+  if (!isTransferEnable()) {
+    if (m_bFTDlgShown) {
+      m_pFTDialog->m_pProgress->clearAll();
+      m_dw64SizeSending = 0;
+      m_bResized = false;
+
+      if (m_bTransferSuccess) 
+        m_pFTDialog->setStatusText("File Transfer Operation Completed Successfully");
+      else 
+        m_pFTDialog->setStatusText("File Transfer Operation Completed");
+
+      m_pFTDialog->afterCancelTransfer();
+      PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+      PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTREMOTERELOAD, 0), 0);
+      return;
+    }
+  } else {
+    if (!resizeSending()) return;
+
+    unsigned int flag0 = m_TransferQueue.getFlagsAt(0);
+   
+    if (flag0 & FT_ATTR_COPY_UPLOAD) {
+      if (flag0 & FT_ATTR_FILE) {
+        uploadFile();
+        return;
+      }
+      if (flag0 & FT_ATTR_DIR) {
+        char *pFullPath = m_TransferQueue.getFullRemPathAt(0);
+        if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Remote Folder. %s", pFullPath);
+        writeFileCreateDirRqst(strlen(pFullPath), pFullPath);
+
+        char *pPath = m_TransferQueue.getRemPathAt(0);
+        m_TransferQueue.setFlagsAt(0, (flag0 | FT_ATTR_FLR_UPLOAD_CHECK));
+        m_queueFileListRqst.add(pPath, 0, 0, FT_FLR_DEST_UPLOAD);
+        writeFileListRqst(strlen(pPath), pPath, false);
+        return;
+      }
+    } else {
+      if (flag0 & FT_ATTR_COPY_DOWNLOAD) {
+        if (flag0 & FT_ATTR_FILE) {
+          downloadFile();
+          return;
+        }
+        if (flag0 & FT_ATTR_DIR) {
+          FolderManager fm;
+          char *pLocPath = m_TransferQueue.getFullLocPathAt(0);
+          if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Local Folder. %s", pLocPath);
+          
+          if (!fm.createDir(pLocPath)) {
+            if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Local Folder Failed.");
+            m_bTransferSuccess = false;
+            m_TransferQueue.deleteAt(0);
+            m_pFTDialog->postCheckTransferQueueMsg();
+            return;
+          } else {
+            if ((m_bFTDlgShown) && (strcmp(m_TransferQueue.getLocPathAt(0), m_pFTDialog->getLocalPath()) == 0))
+              PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+
+            m_TransferQueue.setFlagsAt(0, (m_TransferQueue.getFlagsAt(0) | FT_ATTR_FLR_DOWNLOAD_ADD));
+            char *pRemPath = m_TransferQueue.getFullRemPathAt(0);
+            m_queueFileListRqst.add(pRemPath, 0, 0, FT_FLR_DEST_DOWNLOAD);
+            writeFileListRqst(strlen(pRemPath), pRemPath, 0);
+            return;
+          }
+        }
+      }
+    }
+    m_bTransferSuccess = false;
+    if (m_bFTDlgShown) m_pFTDialog->setStatusText("File Transfer Operation Failed. Unknown data in the transfer queue");
+  } // if (!isTransferEnable())
+}
+
+bool
+FileTransfer::uploadFile()
+{
+  if (m_TransferQueue.getFlagsAt(0) & FT_ATTR_FILE) {
+    if (m_fileReader.create(m_TransferQueue.getFullLocPathAt(0))) {
+      
+      if (m_bFTDlgShown) {
+        m_pFTDialog->setStatusText("Upload Started: %s to %s", 
+                                   m_TransferQueue.getFullLocPathAt(0), 
+                                   m_TransferQueue.getFullRemPathAt(0));
+        m_pFTDialog->m_pProgress->clearAndInitSingle(m_TransferQueue.getSizeAt(0), 0);
+      }
+
+      writeFileUploadRqst(strlen(m_TransferQueue.getFullRemPathAt(0)),
+                          m_TransferQueue.getFullRemPathAt(0), 0);
+      uploadFilePortion();
+    }
+  }
+  return false;
+}
+
+bool
+FileTransfer::downloadFile()
+{
+  if (m_TransferQueue.getFlagsAt(0) & FT_ATTR_FILE) {
+    if (m_fileWriter.create(m_TransferQueue.getFullLocPathAt(0))) {
+      if (m_bFTDlgShown) {
+        m_pFTDialog->setStatusText("Download Started: %s to %s", 
+                                   m_TransferQueue.getFullRemPathAt(0), 
+                                   m_TransferQueue.getFullLocPathAt(0));
+        m_pFTDialog->m_pProgress->clearAndInitSingle(m_TransferQueue.getSizeAt(0), 0);
+      }
+      writeFileDownloadRqst(strlen(m_TransferQueue.getFullRemPathAt(0)),
+                            m_TransferQueue.getFullRemPathAt(0), 0);
+      return true;
+    } else return false;
+  }
+  return false;
+}
+
+void
+FileTransfer::uploadFilePortion()
+{
+  if (checkCancelOperations()) {
+    char reason[] = "The user cancel transfer";
+    m_pWriter->writeFileUploadFailed(strlen(reason), reason);
+  }
+
+  if (m_fileReader.isCreated()) {
+    char buf[FT_MAX_SENDING_SIZE];
+    unsigned int bytesRead = 0;
+    if (m_fileReader.read((void *)buf, FT_MAX_SENDING_SIZE, &bytesRead)) {
+      if (bytesRead == 0) {
+        m_pWriter->writeFileUploadData(m_TransferQueue.getDataAt(0));
+        m_fileReader.close();
+        if (m_bFTDlgShown) {
+          m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+          m_pFTDialog->setStatusText("Upload Completed");
+        }
+        m_TransferQueue.deleteAt(0);
+        m_pFTDialog->postCheckTransferQueueMsg();
+      } else {
+        if (m_bFTDlgShown) m_pFTDialog->m_pProgress->increase(bytesRead);
+        m_pWriter->writeFileUploadData(bytesRead, (char *)buf);
+        m_pFTDialog->postUploadFilePortionMsg();
+      }
+    } else {
+      m_fileReader.close();
+      m_bTransferSuccess = false;
+      char reason[] = "Error While Reading File";
+      m_pWriter->writeFileUploadFailed(strlen(reason), reason);
+      if (m_bFTDlgShown) {
+          m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+          m_pFTDialog->setStatusText("Upload Failed");
+      }
+      m_TransferQueue.deleteAt(0);
+      m_pFTDialog->postCheckTransferQueueMsg();
+    }
+  }
+}
+
+void 
+FileTransfer::createRemoteFolder(char *pPath, char *pName)
+{
+  char fullPath[FT_FILENAME_SIZE];
+  sprintf(fullPath, "%s\\%s", pPath, pName);
+  m_pFTDialog->setStatusText("Creating Remote Folder: %s", fullPath);
+  writeFileCreateDirRqst(strlen(fullPath), fullPath);
+  requestFileList(pPath, FT_FLR_DEST_MAIN, false);
+}
+
+void 
+FileTransfer::renameRemote(char *pPath, char *pOldName, char *pNewName)
+{
+  char fullOldName[FT_FILENAME_SIZE];
+  char fullNewName[FT_FILENAME_SIZE];
+
+  sprintf(fullOldName, "%s\\%s", pPath, pOldName);
+  sprintf(fullNewName, "%s\\%s", pPath, pNewName);
+
+  writeFileRenameRqst(strlen(fullOldName), strlen(fullNewName),
+                      fullOldName, fullNewName);
+  requestFileList(pPath, FT_FLR_DEST_MAIN, false);
+}
+
+bool 
+FileTransfer::procFileListDataMsg()
+{
+  FileInfo fileInfo;
+  int res = m_pReader->readFileListData(&fileInfo);
+
+  bool bResult;
+  switch (m_queueFileListRqst.getFlagsAt(0))
+  {
+  case FT_FLR_DEST_MAIN:
+    if (!m_bFTDlgShown) break;
+    
+    if (res < 0) {
+      m_pFTDialog->reqFolderUnavailable();
+      bResult = true;
+    } else {
+      bResult = procFLRMain(&fileInfo);
+    }
+    break;
+  case FT_FLR_DEST_BROWSE:
+    bResult = procFLRBrowse(&fileInfo);
+    break;
+  case FT_FLR_DEST_UPLOAD:
+    bResult = procFLRUpload(&fileInfo);
+    break;
+  case FT_FLR_DEST_DOWNLOAD:
+    bResult = procFLRDownload(&fileInfo);
+    break;
+  case FT_FLR_DEST_DELETE:
+    bResult = procFLRDelete(&fileInfo);
+    break;
+  case FT_FLR_DEST_RENAME:
+    bResult = procFLRRename(&fileInfo);
+    break;
+  }
+  m_queueFileListRqst.deleteAt(0);
+  return bResult;
+}
+
+bool 
+FileTransfer::procFileDownloadDataMsg()
+{
+  unsigned int bufSize = 0;
+  unsigned int modTime = 0;
+
+  void *pFile = m_pReader->readFileDownloadData(&bufSize, &modTime);
+
+  if (checkCancelOperations()) {
+    char reason[] = "The user cancel transfer";
+    m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+  }
+
+  if ((!m_fileWriter.isCreated()) || (!isTransferEnable())) {
+    m_bTransferSuccess = false;
+    if (pFile != NULL) delete [] pFile;
+    return false;
+  }
+
+  if (bufSize > 0) {
+    unsigned int bytesWritten = 0;
+    m_fileWriter.write(pFile, bufSize, &bytesWritten);
+    delete [] pFile;
+    if (bytesWritten != bufSize) {
+      m_bTransferSuccess = false;
+      char reason[] = "Error File Writting to File";
+      m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+      if (m_bFTDlgShown) {
+        m_pFTDialog->setStatusText("Download Failed");
+        m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+      }
+      m_TransferQueue.deleteAt(0);
+      m_pFTDialog->postCheckTransferQueueMsg();
+      return false;
+    } else {
+      if (m_bFTDlgShown) {
+        m_pFTDialog->m_pProgress->increase(bufSize);
+      }
+    }
+    return true;
+  } else {
+    if (modTime != 0) {
+      m_fileWriter.setTime(modTime);
+      m_fileWriter.close();
+      if (m_bFTDlgShown) {
+        m_pFTDialog->setStatusText("Download Completed");
+        m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+      }
+      m_TransferQueue.deleteAt(0);
+      m_pFTDialog->postCheckTransferQueueMsg();
+      return true;
+    } else {
+      m_fileWriter.close();
+      m_bTransferSuccess = false;
+      char reason[] = "Error File Writting";
+      if (m_bFTDlgShown) {
+        m_pFTDialog->setStatusText("Download Failed");
+        m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+      }
+      m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+      m_TransferQueue.deleteAt(0);
+      m_pFTDialog->postCheckTransferQueueMsg();
+    }
+  }
+  return false;
+}
+
+bool 
+FileTransfer::procFileUploadCancelMsg()
+{
+  unsigned int reasonSize = 0;
+  char *pReason = m_pReader->readFileUploadCancel(&reasonSize);
+
+  if (m_bFTDlgShown) {
+    m_pFTDialog->setStatusText("Upload Canceled by Remote Computer : %s", pReason);
+  }
+  endUndoneOperation();
+  m_pFTDialog->postCheckTransferQueueMsg();
+
+  delete [] pReason;
+  return true;
+}
+
+bool 
+FileTransfer::procFileDownloadFailedMsg()
+{
+  unsigned int reasonSize = 0;
+  char *pReason = m_pReader->readFileDownloadFailed(&reasonSize);
+
+  if (m_bFTDlgShown) {
+    m_pFTDialog->setStatusText("Download Failed by Remote Computer : %s", pReason);
+  }
+  endUndoneOperation();
+  m_pFTDialog->postCheckTransferQueueMsg();
+
+  delete [] pReason;
+  return true;
+}
+
+bool 
+FileTransfer::procFileDirSizeDataMsg()
+{
+  DWORD64 dw64DirSize = 0;
+  unsigned short dirSizeLow16 = 0;
+  unsigned int dirSizeHigh32 = 0;
+  m_pReader->readFileDirSizeData(&dirSizeLow16, &dirSizeHigh32);
+
+  dw64DirSize = dirSizeLow16;
+  dw64DirSize = (dw64DirSize << 32) + dirSizeHigh32;
+  
+  m_dw64SizeSending += dw64DirSize;
+  m_TransferQueue.clearFlagAt(m_dirSizeRqstNum, FT_ATTR_RESIZE_NEEDED);
+  checkTransferQueue();
+  return true;
+}
+
+bool 
+FileTransfer::procFileLastRqstFailedMsg()
+{
+  unsigned int reasonSize = 0;
+  int requestType;
+  char *pReason = m_pReader->readFileLastRqstFailed(&requestType, &reasonSize);
+  delete [] pReason;
+  return true;
+}
+
+bool 
+FileTransfer::procFLRMain(FileInfo *pFI)
+{
+  if (m_bFTDlgShown) m_pFTDialog->addRemoteLVItems(pFI);
+  return true;
+}
+
+bool 
+FileTransfer::procFLRBrowse(FileInfo *pFI)
+{
+  m_pFTDialog->addBrowseItems(pFI);
+  return false;
+}
+
+bool 
+FileTransfer::procFLRUpload(FileInfo *pFI)
+{
+  unsigned int flags = m_TransferQueue.getFlagsAt(0);
+  if (flags & FT_ATTR_FLR_UPLOAD_CHECK) {
+    int num = isExistName(pFI, m_TransferQueue.getRemNameAt(0));
+    if (num >= 0) { 
+      if ((m_bFTDlgShown) && (strcmp(m_TransferQueue.getRemPathAt(0), m_pFTDialog->getRemotePath()) == 0)) {
+        m_pFTDialog->addRemoteLVItems(pFI);
+      }
+    } else {
+      if (flags & FT_ATTR_DIR) {
+        m_TransferQueue.deleteAt(0);
+        m_bTransferSuccess = false;
+        if (m_bFTDlgShown) m_pFTDialog->setStatusText("Create Remote Folder Failed.");
+      }
+    }
+  }
+  FolderManager fm;
+  FileInfo fi;
+  flags = m_TransferQueue.getFlagsAt(0);
+  if (flags & FT_ATTR_FILE) {
+    uploadFile();
+    return true;
+  } else {
+    if (fm.getDirInfo(m_TransferQueue.getFullLocPathAt(0), &fi, 0)) {
+      m_TransferQueue.add(m_TransferQueue.getFullLocPathAt(0),
+        m_TransferQueue.getFullRemPathAt(0),
+        &fi, FT_ATTR_COPY_UPLOAD);
+    }
+  }
+  m_TransferQueue.deleteAt(0);
+  m_pFTDialog->postCheckTransferQueueMsg();
+  return true;
+}
+
+bool 
+FileTransfer::procFLRDownload(FileInfo *pFI)
+{
+  unsigned int flags = m_TransferQueue.getFlagsAt(0);
+  
+  if ((flags & FT_ATTR_DIR) && (flags & FT_ATTR_FLR_DOWNLOAD_ADD)) {
+    m_TransferQueue.add(m_TransferQueue.getFullLocPathAt(0), 
+                        m_TransferQueue.getFullRemPathAt(0), 
+                        pFI, FT_ATTR_COPY_DOWNLOAD);
+    m_TransferQueue.deleteAt(0);
+    m_pFTDialog->postCheckTransferQueueMsg();
+    return true;
+  } else {
+    m_bTransferSuccess = false;
+    if (m_bFTDlgShown) m_pFTDialog->setStatusText("File Transfer Operation Failed: Unknown data from server.");
+  }
+  return false;
+}
+
+bool 
+FileTransfer::procFLRDelete(FileInfo *pFI)
+{
+  if (isExistName(pFI, m_DeleteQueue.getLocNameAt(0)) >= 0) {
+    if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Failed.");
+  } else {
+    if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Completed.");
+  }
+  m_DeleteQueue.deleteAt(0);
+  checkDeleteQueue();
+  return true;
+}
+
+bool 
+FileTransfer::procFLRRename(FileInfo *pFI)
+{
+  return false;
+}
+
+void 
+FileTransfer::requestFileList(char *pPath, int dest, bool bDirOnly)
+{
+  m_queueFileListRqst.add(pPath, 0, 0, dest);
+
+  writeFileListRqst(strlen(pPath), pPath, bDirOnly);
+}
+
+int
+FileTransfer::isExistName(FileInfo *pFI, char *pName)
+{
+  for (unsigned int i = 0; i < pFI->getNumEntries(); i++) {
+    if (strcmp(pFI->getNameAt(i), pName) == 0) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+bool
+FileTransfer::checkCancelOperations()
+{
+  if (m_bFTDlgShown) m_pFTDialog->processDlgMsgs();
+  if (m_bCancel) {
+    endUndoneOperation();
+    if (m_bFTDlgShown) {
+      m_pFTDialog->setStatusText("All Operations Canceled");
+    }
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void 
+FileTransfer::endUndoneOperation()
+{
+  m_bCancel = false;
+  m_bTransferSuccess = false;
+  m_fileReader.close();
+  m_fileWriter.close();
+  freeQueues();
+  m_dw64SizeSending = 0;
+  m_pFTDialog->m_pProgress->clearAll();
+}
+
+void
+FileTransfer::freeQueues()
+{
+  m_TransferQueue.free();
+  m_DeleteQueue.free();
+  m_queueFileListRqst.free();
+}
+
+int
+FileTransfer::convertToUnixPath(char *path)
+{
+  int len = strlen(path);
+  if (len >= FT_FILENAME_SIZE) return -1;
+  if (len == 0) {strcpy(path, "/"); return 1;}
+  for (int i = (len - 1); i >= 0; i--) {
+    if (path[i] == '\\') path[i] = '/';
+    path[i+1] = path[i];
+  }
+  path[len + 1] = '\0';
+  path[0] = '/';
+  return strlen(path);
+}
+
+bool 
+FileTransfer::writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly)
+{
+  char dirName[FT_FILENAME_SIZE];
+  strcpy(dirName, pDirName);
+  int len = convertToUnixPath(dirName);
+  if (len <= 0) return false;
+
+  return m_pWriter->writeFileListRqst(len, dirName, bDirOnly);
+}
+
+bool 
+FileTransfer::writeFileDownloadRqst(unsigned short filenameLen, char *pFilename, 
+                                    unsigned int position)
+{
+  char filename[FT_FILENAME_SIZE];
+  strcpy(filename, pFilename);
+  unsigned short len = (unsigned short) convertToUnixPath(filename);
+  if (len <= 0) return false;
+
+  return m_pWriter->writeFileDownloadRqst(len, filename, position);
+}
+
+bool 
+FileTransfer::writeFileUploadRqst(unsigned short filenameLen, char *pFilename, 
+                                  unsigned int position)
+{
+  char filename[FT_FILENAME_SIZE];
+  strcpy(filename, pFilename);
+  unsigned short len = (unsigned short) convertToUnixPath(filename);
+  if (len <= 0) return false;
+
+  return m_pWriter->writeFileUploadRqst(len, filename, position);
+}
+
+bool 
+FileTransfer::writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName)
+{
+  char path[FT_FILENAME_SIZE];
+  strcpy(path, pDirName);
+  int nameLen = convertToUnixPath(path);
+
+  return m_pWriter->writeFileCreateDirRqst(nameLen, path);
+}
+
+bool 
+FileTransfer::writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName)
+{
+  char path[FT_FILENAME_SIZE];
+  strcpy(path, pDirName);
+  int nameLen = convertToUnixPath(path);
+
+  return m_pWriter->writeFileDirSizeRqst(nameLen, path);
+}
+
+bool 
+FileTransfer::writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+                                  char *pOldName, char *pNewName)
+{
+  char oldName[FT_FILENAME_SIZE];
+  char newName[FT_FILENAME_SIZE];
+
+  strcpy(oldName, pOldName);
+  strcpy(newName, pNewName);
+
+  int _oldNameLen = convertToUnixPath(oldName);
+  int _newNameLen = convertToUnixPath(newName);
+
+  return m_pWriter->writeFileRenameRqst(_oldNameLen, _newNameLen, oldName, newName);
+}
+
+bool 
+FileTransfer::writeFileDeleteRqst(unsigned short nameLen, char *pName)
+{
+  char path[FT_FILENAME_SIZE];
+  strcpy(path, pName);
+  int _nameLen = convertToUnixPath(path);
+
+  return m_pWriter->writeFileDeleteRqst(_nameLen, path);
+}
diff --git a/win/vncviewer/FileTransfer.h b/win/vncviewer/FileTransfer.h
new file mode 100644
index 0000000..1bfded2
--- /dev/null
+++ b/win/vncviewer/FileTransfer.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileTransfer.h
+
+#ifndef __RFB_WIN32_FILETRANSFER_H__
+#define __RFB_WIN32_FILETRANSFER_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/FileInfo.h>
+#include <rfb/FileReader.h>
+#include <rfb/FileWriter.h>
+#include <rfb/TransferQueue.h>
+#include <rfb/CFTMsgReader.h>
+#include <rfb/CFTMsgWriter.h>
+#include <vncviewer/FTDialog.h>
+
+namespace rfb {
+  namespace win32 {
+    class FTDialog;
+
+    class FileTransfer
+    {
+    public:
+      FileTransfer();
+      ~FileTransfer();
+
+      bool initialize(rdr::InStream *pIS, rdr::OutStream *pOS);
+      bool processFTMsg(int type);
+      bool show(HWND hwndParent);
+
+      void requestFileList(char *pPath, int dest, bool bDirOnly);
+
+      void addTransferQueue(char *pLocalPath, char *pRemotePath, 
+                            FileInfo *pFI, unsigned int flags);
+      void addDeleteQueue(char *pPathPrefix, FileInfo *pFI, 
+                          unsigned int flags);
+
+      bool isTransferEnable();
+
+      void checkTransferQueue();
+      void checkDeleteQueue();
+      bool checkCancelOperations();
+
+      void uploadFilePortion();
+
+      void createRemoteFolder(char *pPath, char *pName);
+      void renameRemote(char *pPath, char *pOldName, char *pNewName);
+
+      bool m_bCancel;
+
+    private:
+      bool m_bFTDlgShown;
+      bool m_bInitialized;
+      bool m_bResized;
+      bool m_bTransferSuccess;
+      bool m_bOverwriteAll;
+
+      FTDialog *m_pFTDialog;
+
+      rfb::CFTMsgReader *m_pReader;
+      rfb::CFTMsgWriter *m_pWriter;
+
+      FileReader m_fileReader;
+      FileWriter m_fileWriter;
+
+      FileInfo m_queueFileListRqst;
+
+      TransferQueue m_TransferQueue;
+      TransferQueue m_DeleteQueue;
+
+      bool resizeSending();
+      bool uploadFile();
+      bool downloadFile();
+
+      int  isExistName(FileInfo *pFI, char *pName);
+      void freeQueues();
+
+      void endUndoneOperation();
+      
+      bool procFileListDataMsg();
+      bool procFileDownloadDataMsg();
+      bool procFileUploadCancelMsg();
+      bool procFileDownloadFailedMsg();
+      bool procFileDirSizeDataMsg();
+      bool procFileLastRqstFailedMsg();
+      
+      bool procFLRMain(FileInfo *pFI);
+      bool procFLRBrowse(FileInfo *pFI);
+      bool procFLRUpload(FileInfo *pFI);
+      bool procFLRDownload(FileInfo *pFI);
+      bool procFLRDelete(FileInfo *pFI);
+      bool procFLRRename(FileInfo *pFI);
+
+      int convertToUnixPath(char *path);
+
+      bool writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly);
+      bool writeFileDownloadRqst(unsigned short filenameLen, char *pFilename, 
+                                 unsigned int position);
+      bool writeFileUploadRqst(unsigned short filenameLen, char *pFilename, 
+                               unsigned int position);
+      bool writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName);
+      bool writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName);
+      bool writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+                               char *pOldName, char *pNewName);
+      bool writeFileDeleteRqst(unsigned short nameLen, char *pName);
+
+      DWORD64 m_dw64SizeSending;
+      unsigned int m_dirSizeRqstNum;
+    };
+  }
+}
+
+#endif // __RFB_WIN32_FILETRANSFER_H__
diff --git a/win/vncviewer/InfoDialog.cxx b/win/vncviewer/InfoDialog.cxx
new file mode 100644
index 0000000..e74896d
--- /dev/null
+++ b/win/vncviewer/InfoDialog.cxx
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/resource.h>
+#include <vncviewer/CConn.h>
+#include <rfb/secTypes.h>
+#include <rfb/encodings.h>
+#include <rfb/CSecurity.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Info");
+
+
+bool InfoDialog::showDialog(CConn* cc) {
+  conn = cc;
+  return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_INFO));
+}
+
+void InfoDialog::initDialog() {
+  char buf[256];
+
+  setItemString(IDC_INFO_NAME, TStr(conn->cp.name()));
+
+  setItemString(IDC_INFO_HOST, TCharArray(conn->getSocket()->getPeerAddress()).buf);
+
+  sprintf(buf, "%dx%d", conn->cp.width, conn->cp.height);
+  setItemString(IDC_INFO_SIZE, TStr(buf));
+
+  conn->cp.pf().print(buf, 256);
+  setItemString(IDC_INFO_PF, TStr(buf));
+
+  conn->getServerDefaultPF().print(buf, 256);
+  setItemString(IDC_INFO_DEF_PF, TStr(buf));
+
+  setItemString(IDC_REQUESTED_ENCODING, TStr(encodingName(conn->getOptions().preferredEncoding)));
+  setItemString(IDC_LAST_ENCODING, TStr(encodingName(conn->lastUsedEncoding())));
+
+  sprintf(buf, "%d kbits/s", conn->getSocket()->inStream().kbitsPerSecond());
+  setItemString(IDC_INFO_LINESPEED, TStr(buf));
+
+  sprintf(buf, "%d.%d", conn->cp.majorVersion, conn->cp.minorVersion);
+  setItemString(IDC_INFO_VERSION, TStr(buf));
+
+  const CSecurity* cSec = conn->getCurrentCSecurity();
+  setItemString(IDC_INFO_SECURITY, TStr(secTypeName(cSec->getType())));
+  setItemString(IDC_INFO_ENCRYPTION, TStr(cSec->description()));
+}
diff --git a/win/vncviewer/InfoDialog.h b/win/vncviewer/InfoDialog.h
new file mode 100644
index 0000000..752d53c
--- /dev/null
+++ b/win/vncviewer/InfoDialog.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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
+
+// Info dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_INFO_DIALOG_H__
+#define __RFB_WIN32_INFO_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConn;
+
+    class InfoDialog : Dialog {
+    public:
+      InfoDialog() : Dialog(GetModuleHandle(0)), conn(0) {}
+      virtual bool showDialog(CConn* vw);
+      virtual void initDialog();
+    protected:
+      CConn* conn;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/ListenServer.h b/win/vncviewer/ListenServer.h
new file mode 100644
index 0000000..4d1590c
--- /dev/null
+++ b/win/vncviewer/ListenServer.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- ListenServer.h
+
+#ifndef __RFB_WIN32_LISTEN_SERVER_H__
+#define __RFB_WIN32_LISTEN_SERVER_H__
+
+#include <windows.h>
+#include <winsock2.h>
+#include <network/Socket.h>
+#include <rfb_win32/MsgWindow.h>
+#include <vncviewer/CConnThread.h>
+
+
+namespace rfb {
+  namespace win32 {
+
+    class ListenServer : MsgWindow {
+    public:
+      ListenServer(network::SocketListener* l) : MsgWindow(_T("rfb::win32::ListenServer")), sock(l) {
+        if (WSAAsyncSelect(l->getFd(), getHandle(), WM_USER, FD_ACCEPT) == SOCKET_ERROR)
+          throw rdr::SystemException("unable to monitor listen socket", WSAGetLastError());
+      }
+
+      LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+        if (msg == WM_USER) {
+          network::Socket* newConn = sock->accept();
+          Thread* newThread = new CConnThread(newConn, true);
+          return 0;
+        }
+        return MsgWindow::processMessage(msg, wParam, lParam);
+      }
+    protected:
+      network::SocketListener* sock;
+    };
+
+  };
+};
+
+#endif
\ No newline at end of file
diff --git a/win/vncviewer/ListenTrayIcon.h b/win/vncviewer/ListenTrayIcon.h
new file mode 100644
index 0000000..7e334d9
--- /dev/null
+++ b/win/vncviewer/ListenTrayIcon.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- ListenTrayIcon.h
+
+#ifndef __RFB_WIN32_LISTEN_TRAY_ICON_H__
+#define __RFB_WIN32_LISTEN_TRAY_ICON_H__
+
+#include <rfb_win32/TrayIcon.h>
+#include <rfb_win32/AboutDialog.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class ListenTrayIcon : public TrayIcon {
+    public:
+      ListenTrayIcon() {
+        setIcon(IDI_ICON);
+        setToolTip(_T("VNC Viewer"));
+      }
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+        switch(msg) {
+
+        case WM_USER:
+          switch (lParam) {
+          case WM_LBUTTONDBLCLK:
+            SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
+            break;
+          case WM_RBUTTONUP:
+            HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
+            HMENU trayMenu = GetSubMenu(menu, 0);
+
+            // First item is New Connection, the default
+            SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
+
+            // SetForegroundWindow is required, otherwise Windows ignores the
+            // TrackPopupMenu because the window isn't the foreground one, on
+            // some older Windows versions...
+            SetForegroundWindow(getHandle());
+
+            // Display the menu
+            POINT pos;
+            GetCursorPos(&pos);
+            TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
+            break;
+			    } 
+			    return 0;
+
+        case WM_COMMAND:
+          switch (LOWORD(wParam)) {
+          case ID_NEW_CONNECTION:
+            {
+              Thread* connThread = new CConnThread();
+              break;
+            }
+          case ID_OPTIONS:
+            OptionsDialog::global.showDialog(0);
+            break;
+          case ID_ABOUT:
+            AboutDialog::instance.showDialog();
+            break;
+          case ID_CLOSE:
+            SendMessage(getHandle(), WM_CLOSE, 0, 0);
+            break;
+          }
+          return 0;
+
+        case WM_CLOSE:
+          PostQuitMessage(0);
+          return 0;
+        }
+
+        return TrayIcon::processMessage(msg, wParam, lParam);
+      }
+    };
+
+  };
+};
+
+#endif // __RFB_WIN32_LISTEN_TRAY_ICON_H__
\ No newline at end of file
diff --git a/win/vncviewer/MRU.h b/win/vncviewer/MRU.h
new file mode 100644
index 0000000..ae703b3
--- /dev/null
+++ b/win/vncviewer/MRU.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+#ifndef __VIEWER_MRU_H__
+#define __VIEWER_MRU_H__
+
+#include <windows.h>
+#include <list>
+#include <set>
+#include <rfb_win32/Registry.h>
+#include <rfb/util.h>
+#include <rdr/HexOutStream.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    namespace MRU {
+
+      static const RegKey RegRoot = HKEY_CURRENT_USER;
+      static const TCHAR* RegPath = _T("Software\\TightVNC\\VNCViewer4\\MRU");
+      static const int MaxMRUEntries = 256;
+      static const int MRUEntries = 10;
+
+      static std::list<char*> getEntries() {
+        std::list<char*> mru;
+
+        try {
+          RegKey key;
+          key.openKey(RegRoot, RegPath);
+
+          CharArray order;
+          int length;
+          key.getBinary(_T("Order"), (void**)&order.buf, &length);
+
+          for (int i=0; i<length; i++) {
+            TCharArray keyname = rdr::HexOutStream::binToHexStr(&order.buf[i], 1);
+            try {
+              TCharArray entry = key.getString(keyname.buf);
+              mru.push_back(strDup(entry.buf));
+            } catch (rdr::Exception) {
+            }
+          }
+        } catch (rdr::Exception) {
+        }
+
+        return mru;
+      }
+
+      static void addToMRU(const char* name) {
+        RegKey key;
+        key.createKey(RegRoot, RegPath);
+
+        BYTE keycode;
+        CharArray old_order;
+        char order[MaxMRUEntries];
+        int orderlen;
+        
+        try {
+          key.getBinary(_T("Order"), (void**)&old_order.buf, &orderlen);
+          if (orderlen)
+            memcpy(order, old_order.buf, orderlen);
+
+          std::set<int> ordercodes;
+          keycode = 0;
+          bool found = false;
+          for (int i=0; i<orderlen; i++) {
+            TCharArray keyname = rdr::HexOutStream::binToHexStr(&order[i], 1);
+            try {
+              TCharArray hostname = key.getString(keyname.buf);
+              if (stricmp(name, CStr(hostname.buf)) == 0) {
+                keycode = order[i];
+                found = true;
+                break;
+              }
+            } catch (rdr::Exception) {
+            }
+            ordercodes.insert(order[i]);
+          }
+
+          if (!found) {
+            if (orderlen <= MRUEntries) {
+              while (ordercodes.find(keycode) != ordercodes.end()) keycode++;
+            } else {
+              keycode = order[orderlen-1];
+              orderlen--;
+            }
+          }
+
+        } catch (rdr::Exception) {
+          keycode = 0;
+          orderlen = 0;
+        }
+
+        orderlen++;
+        int i, j=orderlen-1;
+        for (i=0; i<orderlen-1; i++) {
+          if (order[i] == keycode) {
+            j = i;
+            orderlen--;
+            break;
+          }
+        }
+        for (i=j; i>0; i--)
+          order[i] = order[i-1];
+        order[0] = keycode;
+
+        TCharArray keyname = rdr::HexOutStream::binToHexStr((char*)&keycode, 1);
+        key.setString(keyname.buf, TStr(name));
+        key.setBinary(_T("Order"), order, orderlen);
+      }
+
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/OptionsDialog.cxx b/win/vncviewer/OptionsDialog.cxx
new file mode 100644
index 0000000..2e43b38
--- /dev/null
+++ b/win/vncviewer/OptionsDialog.cxx
@@ -0,0 +1,337 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb/encodings.h>
+#include <rfb/CConnection.h>
+#include <commdlg.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Options");
+
+
+struct OptionsInfo {
+  CConn* view;
+  CConnOptions options;
+};
+
+
+OptionsDialog rfb::win32::OptionsDialog::global;
+
+
+class ViewerOptions : public PropSheet {
+public:
+  ViewerOptions(OptionsInfo& info_, std::list<PropSheetPage*> pages)
+    : PropSheet(GetModuleHandle(0), 
+    info_.view ? _T("VNC Viewer Options") : _T("VNC Viewer Defaults"), pages),
+    info(info_), changed(false) {
+  }
+  ~ViewerOptions() {
+    if (changed) {
+      if (info.view)
+        // Apply the settings to the supplied session object
+        info.view->applyOptions(info.options);
+      else {
+        // Commit the settings to the user's registry area
+        info.options.writeDefaults();
+      }
+    }
+  }
+
+  void setChanged() {changed = true;}
+
+  bool changed;
+  OptionsInfo& info;
+};
+      
+
+class FormatPage : public PropSheetPage {
+public:
+  FormatPage(OptionsInfo* dlg_)
+    : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FORMAT)), dlg(dlg_) {
+  }
+  virtual void initDialog() {
+    setItemChecked(IDC_ENCODING_AUTO, dlg->options.autoSelect);
+    setItemChecked(IDC_FORMAT_FULLCOLOUR, dlg->options.fullColour);
+    if (!dlg->options.fullColour) {
+      switch (dlg->options.lowColourLevel) {
+      case 0: setItemChecked(IDC_FORMAT_VERYLOWCOLOUR, true); break;
+      case 1: setItemChecked(IDC_FORMAT_LOWCOLOUR, true); break;
+      case 2: setItemChecked(IDC_FORMAT_MEDIUMCOLOUR, true); break;
+      }
+    }
+    switch (dlg->options.preferredEncoding) {
+    case encodingTight: setItemChecked(IDC_ENCODING_TIGHT, true); break;
+    case encodingZRLE: setItemChecked(IDC_ENCODING_ZRLE, true); break;
+    case encodingHextile: setItemChecked(IDC_ENCODING_HEXTILE, true); break;
+    case encodingRaw: setItemChecked(IDC_ENCODING_RAW, true); break;
+    }
+    setItemChecked(IDC_CUSTOM_COMPRESSLEVEL, dlg->options.customCompressLevel);
+    setItemInt(IDC_COMPRESSLEVEL, dlg->options.compressLevel);
+    setItemChecked(IDC_ALLOW_JPEG, !dlg->options.noJpeg);
+    setItemInt(IDC_QUALITYLEVEL, dlg->options.qualityLevel);
+    onCommand(IDC_ENCODING_AUTO, 0 /* ? */); // Force enableItem status to refresh
+    onCommand(IDC_CUSTOM_COMPRESSLEVEL, 0 /* ? */); // Force enableItem status to refresh
+    onCommand(IDC_ALLOW_JPEG, 0 /* ? */); // Force enableItem status to refresh
+  }
+  virtual bool onOk() {
+    dlg->options.autoSelect = isItemChecked(IDC_ENCODING_AUTO);
+    dlg->options.fullColour = isItemChecked(IDC_FORMAT_FULLCOLOUR);
+    dlg->options.customCompressLevel = isItemChecked(IDC_CUSTOM_COMPRESSLEVEL);
+    dlg->options.compressLevel = getItemInt(IDC_COMPRESSLEVEL);
+    dlg->options.noJpeg = !isItemChecked(IDC_ALLOW_JPEG);
+    dlg->options.qualityLevel = getItemInt(IDC_QUALITYLEVEL);
+    if (isItemChecked(IDC_FORMAT_VERYLOWCOLOUR))
+      dlg->options.lowColourLevel = 0;
+    if (isItemChecked(IDC_FORMAT_LOWCOLOUR))
+      dlg->options.lowColourLevel = 1;
+    if (isItemChecked(IDC_FORMAT_MEDIUMCOLOUR))
+      dlg->options.lowColourLevel = 2;
+    dlg->options.preferredEncoding = encodingTight;
+    if (isItemChecked(IDC_ENCODING_ZRLE))
+      dlg->options.preferredEncoding = encodingZRLE;
+    if (isItemChecked(IDC_ENCODING_HEXTILE))
+      dlg->options.preferredEncoding = encodingHextile;
+    if (isItemChecked(IDC_ENCODING_RAW))
+      dlg->options.preferredEncoding = encodingRaw;
+    ((ViewerOptions*)propSheet)->setChanged();
+    return true;
+  }
+  virtual bool onCommand(int id, int cmd) {
+    if (id == IDC_ENCODING_AUTO) {
+      bool ok = !isItemChecked(IDC_ENCODING_AUTO);
+      enableItem(IDC_ENCODING_TIGHT, ok);
+      enableItem(IDC_ENCODING_ZRLE, ok);
+      enableItem(IDC_ENCODING_HEXTILE, ok);
+      enableItem(IDC_ENCODING_RAW, ok);
+      enableItem(IDC_FORMAT_FULLCOLOUR, ok);
+      enableItem(IDC_FORMAT_MEDIUMCOLOUR, ok);
+      enableItem(IDC_FORMAT_LOWCOLOUR, ok);
+      enableItem(IDC_FORMAT_VERYLOWCOLOUR, ok);
+      return true;
+    }
+    if (id == IDC_CUSTOM_COMPRESSLEVEL) {
+      enableItem(IDC_COMPRESSLEVEL, isItemChecked(IDC_CUSTOM_COMPRESSLEVEL));
+      return true;
+    }
+    if (id == IDC_ALLOW_JPEG) {
+      enableItem(IDC_QUALITYLEVEL, isItemChecked(IDC_ALLOW_JPEG));
+      return true;
+    }
+    return false;
+  }
+protected:
+  OptionsInfo* dlg;
+};
+
+class MiscPage : public PropSheetPage {
+public:
+  MiscPage(OptionsInfo* dlg_)
+    : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MISC)), dlg(dlg_) {
+  }
+  virtual void initDialog() {
+    setItemChecked(IDC_CONN_SHARED, dlg->options.shared);
+    enableItem(IDC_CONN_SHARED, (!dlg->view) || (dlg->view->state() != CConnection::RFBSTATE_NORMAL));
+    setItemChecked(IDC_FULL_SCREEN, dlg->options.fullScreen);
+    setItemChecked(IDC_LOCAL_CURSOR, dlg->options.useLocalCursor);
+    setItemChecked(IDC_DESKTOP_RESIZE, dlg->options.useDesktopResize);
+    enableItem(IDC_PROTOCOL_3_3, (!dlg->view) || (dlg->view->state() != CConnection::RFBSTATE_NORMAL));
+    setItemChecked(IDC_PROTOCOL_3_3, dlg->options.protocol3_3);
+    setItemChecked(IDC_ACCEPT_BELL, dlg->options.acceptBell);
+    setItemChecked(IDC_AUTO_RECONNECT, dlg->options.autoReconnect);
+    setItemChecked(IDC_SHOW_TOOLBAR, dlg->options.showToolbar);
+  }
+  virtual bool onOk() {
+    dlg->options.shared = isItemChecked(IDC_CONN_SHARED);
+    dlg->options.fullScreen = isItemChecked(IDC_FULL_SCREEN);
+    dlg->options.useLocalCursor = isItemChecked(IDC_LOCAL_CURSOR);
+    dlg->options.useDesktopResize = isItemChecked(IDC_DESKTOP_RESIZE);
+    dlg->options.protocol3_3 = isItemChecked(IDC_PROTOCOL_3_3);
+    dlg->options.acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+    dlg->options.autoReconnect = isItemChecked(IDC_AUTO_RECONNECT);
+    dlg->options.showToolbar = isItemChecked(IDC_SHOW_TOOLBAR);
+    ((ViewerOptions*)propSheet)->setChanged();
+    return true;
+  }
+protected:
+  OptionsInfo* dlg;
+};
+
+class InputsPage : public PropSheetPage {
+public:
+  InputsPage(OptionsInfo* dlg_)
+    : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_INPUTS)), dlg(dlg_) {
+  }
+  virtual void initDialog() {
+    setItemChecked(IDC_SEND_POINTER, dlg->options.sendPtrEvents);
+    setItemChecked(IDC_SEND_KEYS, dlg->options.sendKeyEvents);
+    setItemChecked(IDC_CLIENT_CUTTEXT, dlg->options.clientCutText);
+    setItemChecked(IDC_SERVER_CUTTEXT, dlg->options.serverCutText);
+    setItemChecked(IDC_DISABLE_WINKEYS, dlg->options.disableWinKeys && !osVersion.isPlatformWindows);
+    enableItem(IDC_DISABLE_WINKEYS, !osVersion.isPlatformWindows);
+    setItemChecked(IDC_EMULATE3, dlg->options.emulate3);
+    setItemChecked(IDC_POINTER_INTERVAL, dlg->options.pointerEventInterval != 0);
+
+    // Populate the Menu Key tab
+    HWND menuKey = GetDlgItem(handle, IDC_MENU_KEY);
+    SendMessage(menuKey, CB_RESETCONTENT, 0, 0);
+    SendMessage(menuKey, CB_ADDSTRING, 0, (LPARAM)_T("none"));
+    if (!dlg->options.menuKey)
+      SendMessage(menuKey, CB_SETCURSEL, 0, 0);
+    for (int i=0; i<12; i++) {
+      TCHAR buf[4];
+      _stprintf(buf, _T("F%d"), i+1);
+      int index = SendMessage(menuKey, CB_ADDSTRING, 0, (LPARAM)buf);
+      if (i == (dlg->options.menuKey - VK_F1))
+        SendMessage(menuKey, CB_SETCURSEL, index, 0);
+    }
+  }
+  virtual bool onOk() {
+    dlg->options.sendPtrEvents = isItemChecked(IDC_SEND_POINTER);
+    dlg->options.sendKeyEvents = isItemChecked(IDC_SEND_KEYS);
+    dlg->options.clientCutText = isItemChecked(IDC_CLIENT_CUTTEXT);
+    dlg->options.serverCutText = isItemChecked(IDC_SERVER_CUTTEXT);
+    dlg->options.disableWinKeys = isItemChecked(IDC_DISABLE_WINKEYS);
+    dlg->options.emulate3 = isItemChecked(IDC_EMULATE3);
+    dlg->options.pointerEventInterval = 
+      isItemChecked(IDC_POINTER_INTERVAL) ? 200 : 0;
+
+    HWND mkHwnd = GetDlgItem(handle, IDC_MENU_KEY);
+    int index = SendMessage(mkHwnd, CB_GETCURSEL, 0, 0);
+    TCharArray keyName(SendMessage(mkHwnd, CB_GETLBTEXTLEN, index, 0)+1);
+    SendMessage(mkHwnd, CB_GETLBTEXT, index, (LPARAM)keyName.buf);
+    if (_tcscmp(keyName.buf, _T("none")) == 0)
+      dlg->options.setMenuKey("");
+    else
+      dlg->options.setMenuKey(CStr(keyName.buf));
+
+    ((ViewerOptions*)propSheet)->setChanged();
+    return true;
+  }
+protected:
+  OptionsInfo* dlg;
+};
+
+class DefaultsPage : public PropSheetPage {
+public:
+  DefaultsPage(OptionsInfo* dlg_)
+    : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DEFAULTS)), dlg(dlg_) {
+  }
+  virtual void initDialog() {
+    enableItem(IDC_LOAD_CONFIG, dlg->options.configFileName.buf);
+    enableItem(IDC_SAVE_CONFIG, dlg->options.configFileName.buf);
+  }
+  virtual bool onCommand(int id, int cmd) {
+    switch (id) {
+    case IDC_LOAD_DEFAULTS:
+      dlg->options = CConnOptions();
+      break;
+    case IDC_SAVE_DEFAULTS:
+      propSheet->commitPages();
+      dlg->options.writeDefaults();
+      break;
+    case IDC_LOAD_CONFIG:
+      dlg->options.readFromFile(dlg->options.configFileName.buf);
+      break;
+    case IDC_SAVE_CONFIG:
+      propSheet->commitPages();
+      dlg->options.writeToFile(dlg->options.configFileName.buf);
+      MsgBox(handle, _T("Options saved successfully"),
+             MB_OK | MB_ICONINFORMATION);
+      return 0;
+    case IDC_SAVE_CONFIG_AS:
+      propSheet->commitPages();
+      // Get a filename to save to
+      TCHAR newFilename[4096];
+      TCHAR currentDir[4096];
+      if (dlg->options.configFileName.buf)
+        _tcscpy(newFilename, TStr(dlg->options.configFileName.buf));
+      else
+        newFilename[0] = 0;
+      OPENFILENAME ofn;
+      memset(&ofn, 0, sizeof(ofn));
+#ifdef OPENFILENAME_SIZE_VERSION_400
+      ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+#else
+      ofn.lStructSize = sizeof(ofn);
+#endif
+      ofn.hwndOwner = handle;
+      ofn.lpstrFilter = _T("VNC Connection Options\000*.vnc\000");
+      ofn.lpstrFile = newFilename;
+      currentDir[0] = 0;
+      GetCurrentDirectory(4096, currentDir);
+      ofn.lpstrInitialDir = currentDir;
+      ofn.nMaxFile = 4096;
+      ofn.lpstrDefExt = _T(".vnc");
+      ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
+      if (!GetSaveFileName(&ofn)) {
+        if (CommDlgExtendedError())
+          throw rdr::Exception("GetSaveFileName failed");
+        return 0;
+      }
+
+      // Save the Options
+      dlg->options.writeToFile(CStr(newFilename));
+      MsgBox(handle, _T("Options saved successfully"),
+             MB_OK | MB_ICONINFORMATION);
+      return 0;
+    };
+    propSheet->reInitPages();
+    return true;
+  }
+protected:
+  OptionsInfo* dlg;
+};
+
+
+OptionsDialog::OptionsDialog() : visible(false) {
+}
+
+bool OptionsDialog::showDialog(CConn* view, bool capture) {
+  if (visible) return false;
+  visible = true;
+
+  // Grab the current properties
+  OptionsInfo info;
+  if (view)
+    info.options = view->getOptions();
+  info.view = view;
+
+  // Build a list of pages to display
+  std::list<PropSheetPage*> pages;
+  FormatPage formatPage(&info); pages.push_back(&formatPage);
+  InputsPage inputsPage(&info); pages.push_back(&inputsPage);
+  MiscPage miscPage(&info); pages.push_back(&miscPage);
+  DefaultsPage defPage(&info); if (view) pages.push_back(&defPage);
+
+  // Show the property sheet
+  ViewerOptions dialog(info, pages);
+  dialog.showPropSheet(view && view->getWindow() ? view->getWindow()->getHandle() : 0,
+                       false, false, capture);
+
+  visible = false;
+  return dialog.changed;
+}
diff --git a/win/vncviewer/OptionsDialog.h b/win/vncviewer/OptionsDialog.h
new file mode 100644
index 0000000..fcddc71
--- /dev/null
+++ b/win/vncviewer/OptionsDialog.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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
+
+// Options dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_OPTIONS_DIALOG_H__
+#define __RFB_WIN32_OPTIONS_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConn;
+
+    class OptionsDialog {
+    public:
+      OptionsDialog();
+      virtual bool showDialog(CConn* cfg, bool capture=false);
+
+      static OptionsDialog global;
+    protected:
+      bool visible;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/UserPasswdDialog.cxx b/win/vncviewer/UserPasswdDialog.cxx
new file mode 100644
index 0000000..2eea0ea
--- /dev/null
+++ b/win/vncviewer/UserPasswdDialog.cxx
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/resource.h>
+#include <rfb/Exception.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+UserPasswdDialog::UserPasswdDialog() : Dialog(GetModuleHandle(0)),
+  showUsername(false), showPassword(false) {
+}
+
+
+void UserPasswdDialog::setCSecurity(const CSecurity* cs) {
+  description.replaceBuf(tstrDup(cs->description()));
+}
+
+bool UserPasswdDialog::showDialog() {
+  return Dialog::showDialog(MAKEINTRESOURCE(IDD_VNC_AUTH_DLG));
+}
+
+void UserPasswdDialog::initDialog() {
+  if (username.buf)
+    setItemString(IDC_USERNAME, username.buf);
+  if (password.buf)
+    setItemString(IDC_PASSWORD, password.buf);
+  if (!showUsername) {
+    setItemString(IDC_USERNAME, _T(""));
+    enableItem(IDC_USERNAME, false);
+  }
+  if (!showPassword) {
+    setItemString(IDC_PASSWORD, _T(""));
+    enableItem(IDC_PASSWORD, false);
+  }
+  if (description.buf) {
+    TCharArray title(128);
+    GetWindowText(handle, title.buf, 128);
+    _tcsncat(title.buf, _T(" ["), 128);
+    _tcsncat(title.buf, description.buf, 128);
+    _tcsncat(title.buf, _T("]"), 128);
+    SetWindowText(handle, title.buf);
+  }
+}
+
+bool UserPasswdDialog::onOk() {
+	username.replaceBuf(getItemString(IDC_USERNAME));
+	password.replaceBuf(getItemString(IDC_PASSWORD));
+  return true;
+}
+
+
+void UserPasswdDialog::getUserPasswd(char** user, char** passwd) {
+  showUsername = user != 0;
+  showPassword = passwd != 0;
+  if (user && *user)
+    username.replaceBuf(tstrDup(*user));
+  if (passwd && *passwd)
+    password.replaceBuf(tstrDup(*passwd));
+
+  if (!showDialog())
+    throw rfb::AuthCancelledException();
+
+  if (user)
+    *user = strDup(username.buf);
+  if (passwd)
+    *passwd = strDup(password.buf);
+}
diff --git a/win/vncviewer/UserPasswdDialog.h b/win/vncviewer/UserPasswdDialog.h
new file mode 100644
index 0000000..bf006f4
--- /dev/null
+++ b/win/vncviewer/UserPasswdDialog.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- UserPasswdDialog.h
+
+// Username and password dialog for VNC Viewer 4.0
+// Note that the password and username fields are only freed
+// when the dialog instance is deleted - it is important to
+// ensure that the instance is deleted as early as possible, to
+// avoid the password being retained in memory for too long.
+
+#ifndef __RFB_WIN32_USERPASSWD_DIALOG_H__
+#define __RFB_WIN32_USERPASSWD_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/CSecurity.h>
+#include <rfb/UserPasswdGetter.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class UserPasswdDialog : Dialog, public UserPasswdGetter {
+    public:
+      UserPasswdDialog();
+      virtual bool showDialog();
+      virtual void initDialog();
+      virtual bool onOk();
+      virtual void getUserPasswd(char** user, char** passwd);
+      void setCSecurity(const CSecurity* cs);
+    protected:
+      TCharArray username;
+      TPlainPasswd password;
+      bool showUsername, showPassword;
+      TCharArray description;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncviewer/ViewerToolBar.cxx b/win/vncviewer/ViewerToolBar.cxx
new file mode 100644
index 0000000..29b8030
--- /dev/null
+++ b/win/vncviewer/ViewerToolBar.cxx
@@ -0,0 +1,117 @@
+/* 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.
+ */
+
+// -=- ViewerToolBar.cxx
+
+#include <vncviewer/ViewerToolBar.h>
+#include <vncviewer/resource.h>
+
+void ViewerToolBar::create(HWND parentHwnd) {
+  // Create the toolbar panel
+  ToolBar::create(ID_TOOLBAR, parentHwnd, WS_CHILD | 
+    TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NORESIZE);
+  addBitmap(4, IDB_TOOLBAR);
+
+  // Create the control buttons
+  addButton(0, ID_OPTIONS);
+  addButton(1, ID_INFO);
+  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  addButton(2, ID_FULLSCREEN);
+  addButton(3, ID_REQUEST_REFRESH);
+  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  addButton(4, ID_SEND_CAD);
+  addButton(5, ID_SEND_CTLESC);
+  addButton(6, ID_CTRL_KEY);
+  addButton(7, ID_ALT_KEY);
+  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  addButton(8, ID_FILE_TRANSFER);
+  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  addButton(9, ID_NEW_CONNECTION);
+  addButton(10, ID_CONN_SAVE_AS);
+  addButton(11, ID_CLOSE);
+
+  // Resize the toolbar window
+  autoSize();
+}
+
+LRESULT ViewerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+  switch (((LPNMHDR)lParam)->code) { 
+    // Process tooltips text
+  case TTN_NEEDTEXT:
+    {
+      LPTOOLTIPTEXT TTStr = (LPTOOLTIPTEXT)lParam;
+      if (TTStr->hdr.code != TTN_NEEDTEXT)
+        return 0;
+
+      switch (TTStr->hdr.idFrom) {
+      case ID_OPTIONS:
+        TTStr->lpszText = "Connection options...";
+        break;
+      case ID_INFO:
+        TTStr->lpszText = "Connection info";
+        break;
+      case ID_FULLSCREEN:
+        TTStr->lpszText = "Full screen";
+        break;
+      case ID_REQUEST_REFRESH:
+        TTStr->lpszText = "Request screen refresh";
+        break;
+      case ID_SEND_CAD:
+        TTStr->lpszText = "Send Ctrl-Alt-Del";
+        break;
+      case ID_SEND_CTLESC:
+        TTStr->lpszText = "Send Ctrl-Esc";
+        break;
+      case ID_CTRL_KEY:
+        TTStr->lpszText = "Send Ctrl key press/release";
+        break;
+      case ID_ALT_KEY:
+        TTStr->lpszText = "Send Alt key press/release";
+        break;
+      case ID_FILE_TRANSFER:
+        TTStr->lpszText = "Transfer files...";
+        break;
+      case ID_NEW_CONNECTION:
+        TTStr->lpszText = "New connection...";
+        break;
+      case ID_CONN_SAVE_AS:
+        TTStr->lpszText = "Save connection info as...";
+        break;
+      case ID_CLOSE:
+        TTStr->lpszText = "Disconnect";
+        break;
+      default:
+        break;
+      }
+    }
+
+  default:
+    break;
+  }
+  return 0;
+}
+
+void ViewerToolBar::show() {
+  ShowWindow(getHandle(), SW_SHOW);
+  SendMessage(parentHwnd, WM_SIZE, 0, 0);
+}
+
+void ViewerToolBar::hide() {
+  ShowWindow(getHandle(), SW_HIDE);
+  SendMessage(parentHwnd, WM_SIZE, 0, 0);
+}
diff --git a/win/vncviewer/ViewerToolBar.h b/win/vncviewer/ViewerToolBar.h
new file mode 100644
index 0000000..30e7708
--- /dev/null
+++ b/win/vncviewer/ViewerToolBar.h
@@ -0,0 +1,38 @@
+/* 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.
+ */
+
+// -=- ViewerToolBar.h
+
+// ToolBar for the Vnc Viewer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+class ViewerToolBar : public ToolBar {
+public:
+  ViewerToolBar() {}
+  ~ViewerToolBar() {}
+
+  void create(HWND parentHwnd);
+
+  LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+  void show();
+  void hide();
+};
diff --git a/win/vncviewer/buildTime.cxx b/win/vncviewer/buildTime.cxx
new file mode 100644
index 0000000..9f37b38
--- /dev/null
+++ b/win/vncviewer/buildTime.cxx
@@ -0,0 +1,18 @@
+/* Copyright (C) 2005 RealVNC Ltd.  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.
+ */
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
diff --git a/win/vncviewer/cursor1.cur b/win/vncviewer/cursor1.cur
new file mode 100644
index 0000000..20a713f
--- /dev/null
+++ b/win/vncviewer/cursor1.cur
Binary files differ
diff --git a/win/vncviewer/ftdir.ico b/win/vncviewer/ftdir.ico
new file mode 100644
index 0000000..7a7f741
--- /dev/null
+++ b/win/vncviewer/ftdir.ico
Binary files differ
diff --git a/win/vncviewer/ftfile.ico b/win/vncviewer/ftfile.ico
new file mode 100644
index 0000000..a8084b8
--- /dev/null
+++ b/win/vncviewer/ftfile.ico
Binary files differ
diff --git a/win/vncviewer/ftreload.ico b/win/vncviewer/ftreload.ico
new file mode 100644
index 0000000..34383e9
--- /dev/null
+++ b/win/vncviewer/ftreload.ico
Binary files differ
diff --git a/win/vncviewer/ftup.ico b/win/vncviewer/ftup.ico
new file mode 100644
index 0000000..fc215ad
--- /dev/null
+++ b/win/vncviewer/ftup.ico
Binary files differ
diff --git a/win/vncviewer/resource.h b/win/vncviewer/resource.h
new file mode 100644
index 0000000..5493fd0
--- /dev/null
+++ b/win/vncviewer/resource.h
@@ -0,0 +1,154 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by vncviewer.rc
+//
+#define IDR_MANIFEST                    1
+#define IDI_ICON                        101
+#define IDD_VNC_AUTH_DLG                102
+#define IDD_CONNECTING_DLG              103
+#define IDD_CONNECTION_DLG              104
+#define IDC_DOT_CURSOR                  105
+#define IDD_ABOUT                       107
+#define IDD_FORMAT                      108
+#define IDD_MISC                        109
+#define IDD_INPUTS                      110
+#define IDD_SERVER_KEYS                 111
+#define IDR_TRAY                        112
+#define IDD_CONNECTION_INFO             113
+#define IDD_DEFAULTS                    116
+#define IDB_BITMAP                      120
+#define IDD_FILETRANSFER_DLG            121
+#define IDB_TOOLBAR                     122
+#define IDD_FTCONFIRM_DLG               124
+#define IDI_FTUP                        125
+#define IDI_FTDIR                       126
+#define IDI_FTFILE                      127
+#define IDI_FTRELOAD                    128
+#define IDR_FTMENU                      130
+#define IDD_FTCANCELING                 131
+#define IDD_FTCREATEFOLDER              132
+#define IDD_FTBROWSE                    133
+#define IDC_PASSWORD                    1000
+#define IDC_CONNECTING_TEXT             1001
+#define IDC_SERVER_EDIT                 1002
+#define IDC_USERNAME                    1005
+#define IDC_VERSION                     1008
+#define IDC_BUILDTIME                   1009
+#define IDC_ENCODING_AUTO               1010
+#define IDC_FORMAT_FULLCOLOUR           1011
+#define IDC_ENCODING_ZRLE               1012
+#define IDC_ENCODING_HEXTILE            1013
+#define IDC_CONN_SHARED                 1013
+#define IDC_ENCODING_RAW                1014
+#define IDC_FULL_SCREEN                 1014
+#define IDC_SEND_POINTER                1015
+#define IDC_SEND_KEYS                   1016
+#define IDC_CLIENT_CUTTEXT              1017
+#define IDC_SERVER_CUTTEXT              1018
+#define IDC_LOCAL_CURSOR                1019
+#define IDC_DESKTOP_RESIZE              1020
+#define IDC_COPYRIGHT                   1021
+#define IDC_DESCRIPTION                 1022
+#define IDC_OPTIONS                     1023
+#define IDC_ABOUT                       1024
+#define IDC_LIST1                       1025
+#define IDC_FTLOCALLIST                 1025
+#define IDC_INFO_NAME                   1026
+#define IDC_INFO_HOST                   1027
+#define IDC_INFO_SIZE                   1028
+#define IDC_INFO_PF                     1029
+#define IDC_INFO_DEF_PF                 1030
+#define IDC_INFO_LINESPEED              1031
+#define IDC_INFO_VERSION                1032
+#define IDC_PROTOCOL_3_3                1034
+#define IDC_ACCEPT_BELL                 1035
+#define IDC_FORMAT_VERYLOWCOLOUR        1036
+#define IDC_SHOW_TOOLBAR                1036
+#define IDC_FORMAT_LOWCOLOUR            1037
+#define IDC_FORMAT_MEDIUMCOLOUR         1038
+#define IDC_LOAD_DEFAULTS               1040
+#define IDC_SAVE_DEFAULTS               1041
+#define IDC_LOAD_CONFIG                 1042
+#define IDC_EMULATE3                    1043
+#define IDC_POINTER_INTERVAL            1044
+#define IDC_SAVE_CONFIG                 1045
+#define IDC_INFO_SECURITY               1046
+#define IDC_SAVE_CONFIG_AS              1048
+#define IDC_MENU_KEY                    1051
+#define IDC_REQUESTED_ENCODING          1052
+#define IDC_LAST_ENCODING               1053
+#define IDC_SECURITY_LEVEL              1054
+#define IDC_INFO_ENCRYPTION             1055
+#define IDC_AUTO_RECONNECT              1056
+#define IDC_DISABLE_WINKEYS             1057
+#define IDC_QUALITYLEVEL                1058
+#define IDC_FTLOCALUP                   1058
+#define IDC_SEND_SYSKEYS                1059
+#define IDC_FTLOCALBROWSE               1059
+#define IDC_FTREMOTERELOAD              1060
+#define IDC_FTREMOTEUP                  1061
+#define IDC_FTREMOTEBROWSE              1062
+#define IDC_FTPROGRESS                  1063
+#define IDC_FTGENERALPROGRESS           1063
+#define IDC_PROGRESS                    1064
+#define IDC_FTSINGLEPROGRESS            1064
+#define IDC_FTSTATUS                    1065
+#define IDC_FTCURRENTPROCENT            1066
+#define IDC_FTSINGLEPERCENT             1066
+#define IDC_FTTOTALPROCENT              1067
+#define IDC_FTGENERALPERCENT            1067
+#define IDC_FTUPLOAD                    1072
+#define IDC_FTCANCEL                    1073
+#define IDC_FTDOWNLOAD                  1074
+#define IDC_FTCLOSE                     1075
+#define IDC_FTLOCALLABEL                1076
+#define IDC_FTREMOTELABEL               1077
+#define IDC_FTDIRNAME                   1078
+#define IDC_CONFIRM_YESTOALL            1079
+#define IDC_CONFIRM_TEXT                1080
+#define IDC_EDIT2                       1082
+#define IDC_FTFOLDERNAME                1083
+#define IDC_FTTEXT                      1084
+#define IDC_FTBROWSEPATH                1085
+#define IDC_FTBROWSETREE                1086
+#define IDC_TYPE                        1088
+#define IDC_ENCODING_TIGHT              1089
+#define IDC_FTLOCALPATH                 1090
+#define IDC_CUSTOM_COMPRESSLEVEL        1091
+#define IDC_FTREMOTEPATH                1092
+#define IDC_COMPRESSLEVEL               1093
+#define IDC_FTREMOTELIST                1094
+#define IDC_ALLOW_JPEG                  1095
+#define IDC_FTLOCALRELOAD               1096
+#define ID_TOOLBAR                      40002
+#define ID_CLOSE                        40003
+#define ID_OPTIONS                      40004
+#define ID_NEW_CONNECTION               40005
+#define ID_ABOUT                        40006
+#define ID_FULLSCREEN                   40007
+#define ID_SEND_CAD                     40008
+#define ID_INFO                         40009
+#define ID_REQUEST_REFRESH              40010
+#define ID_CTRL_KEY                     40011
+#define ID_ALT_KEY                      40012
+#define ID_SEND_MENU_KEY                40013
+#define ID_SEND_CTLESC                  40014
+#define ID_CONN_SAVE_AS                 40015
+#define ID_FILE_TRANSFER                40016
+#define IDM_FTCOPY                      40022
+#define IDM_FTRENAME                    40023
+#define IDM_FTDELETE                    40024
+#define IDM_FTCANCEL                    40025
+#define IDM_FTCREATEFOLDER              40026
+#define IDM_SHOW_TOOLBAR                40027
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        134
+#define _APS_NEXT_COMMAND_VALUE         40028
+#define _APS_NEXT_CONTROL_VALUE         1097
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/win/vncviewer/toolbar.bmp b/win/vncviewer/toolbar.bmp
new file mode 100644
index 0000000..0a14636
--- /dev/null
+++ b/win/vncviewer/toolbar.bmp
Binary files differ
diff --git a/win/vncviewer/vncviewer.bmp b/win/vncviewer/vncviewer.bmp
new file mode 100644
index 0000000..4ea9c37
--- /dev/null
+++ b/win/vncviewer/vncviewer.bmp
Binary files differ
diff --git a/win/vncviewer/vncviewer.cxx b/win/vncviewer/vncviewer.cxx
new file mode 100644
index 0000000..3a5214a
--- /dev/null
+++ b/win/vncviewer/vncviewer.cxx
@@ -0,0 +1,295 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+
+// -=- VNC Viewer for Win32
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+#include <list>
+
+#include <vncviewer/resource.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/ListenServer.h>
+#include <vncviewer/ListenTrayIcon.h>
+#include <network/TcpSocket.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/Logger_file.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb_win32/RegConfig.h>
+#include <rfb_win32/MsgBox.h>
+
+#ifdef _DIALOG_CAPTURE
+#include <extra/LoadBMP.h>
+#endif
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+using namespace network;
+
+static LogWriter vlog("main");
+
+TStr rfb::win32::AppName("VNC Viewer");
+
+
+#ifdef _DIALOG_CAPTURE
+BoolParameter captureDialogs("CaptureDialogs", "", false);
+#endif
+
+//
+// -=- Listener
+//     Class to handle listening on a particular port for incoming connections
+//     from servers, and spawning of clients
+//
+
+static BoolParameter acceptIncoming("Listen", "Accept incoming connections from VNC servers.", false);
+
+
+//
+// -=- 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;
+
+
+//
+// -=- processParams
+//     Read in the command-line parameters and interpret them.
+//
+
+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() {
+  printf("usage: vncviewer <options> <hostname>[:<display>]\n");
+  printf("Command-line options:\n");
+  printf("  -help                                - Provide usage information.\n");
+  printf("  -config <file>                       - Load connection settings from VNC Viewer 3.3 settings file\n");
+  printf("  -console                             - Run with a console window visible.\n");
+  printf("  <setting>=<value>                    - Set the named configuration parameter.\n");
+  printf("    (Parameter values specified on the command-line override those specified by other configuration methods.)\n");
+  printf("\nLog names:\n");
+  LogWriter::listLogWriters();
+  printf("\nLog destinations:\n");
+  Logger::listLoggers();
+  printf("\nParameters:\n");
+  Configuration::listParams();
+  printf("Press Enter/Return key to continue\n");
+  char c = getchar();
+  exit(1);
+}
+
+
+bool print_usage = false;
+bool close_console = true;
+std::list<char*> hosts;
+std::list<char*> configFiles;
+
+void
+processParams(int argc, char* argv[]) {
+  for (int i=1; i<argc; i++) {
+    try {
+
+      if (strcasecmp(argv[i], "-console") == 0) {
+        close_console = false;
+
+      } else if (((strcasecmp(argv[i], "-config") == 0) ||
+                  (strcasecmp(argv[i], "/config") == 0)) && (i < argc-1)) {
+        configFiles.push_back(strDup(argv[i+1]));
+        i++;
+
+      } else if ((strcasecmp(argv[i], "-help") == 0) ||
+                 (strcasecmp(argv[i], "--help") == 0) ||
+                 (strcasecmp(argv[i], "-h") == 0) ||
+                 (strcasecmp(argv[i], "/?") == 0)) {
+        print_usage = true;
+        close_console = false;
+        break;
+
+      } else {
+        // Try to process <option>=<value>, or -<bool>
+        if (Configuration::setParam(argv[i], true))
+          continue;
+        // Try to process -<option> <value>
+        if ((argv[i][0] == '-') && (i+1 < argc)) {
+          if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
+            i++;
+            continue;
+          }
+        }
+        // If it's -<option> then it's not recognised - error
+        // If it's <host> then add it to the list to connect to.
+        if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
+          const char* fmt = "The option %s was not recognized.  Use -help to see VNC Viewer usage";
+          CharArray tmp(strlen(argv[i])+strlen(fmt)+1);
+          sprintf(tmp.buf, fmt, argv[i]);
+          MsgBox(0, TStr(tmp.buf), MB_ICONSTOP | MB_OK);
+          exit(1);
+        } else if (strContains(argv[i], '\\')) {
+          configFiles.push_back(strDup(argv[i]));
+        } else {
+          hosts.push_back(strDup(argv[i]));
+        }
+      }
+
+    } catch (rdr::Exception& e) {
+      vlog.error(e.str());
+    }
+  }
+}
+
+
+//
+// -=- main
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+  try {
+
+    // - Initialise the available loggers
+    initStdIOLoggers();
+    initFileLogger("C:\\temp\\vncviewer4.log");
+
+    // - By default, just log errors to stderr
+    logParams.setDefault("*:stderr:0");
+
+    // - Process the command-line
+    int argc = __argc;
+    char** argv = __argv;
+    processParams(argc, argv);
+
+    // - By default the console will be closed
+    if (close_console) {
+      if (!FreeConsole())
+        vlog.info("unable to close console:%u", GetLastError());
+    } else {
+      AllocConsole();
+      freopen("CONIN$","rb",stdin);
+      freopen("CONOUT$","wb",stdout);
+      freopen("CONOUT$","wb",stderr);
+      setbuf(stderr, 0);
+    }
+
+#ifdef _DIALOG_CAPTURE
+    if (captureDialogs) {
+      CConn::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+      OptionsDialog::global.showDialog(0, true);
+      return 0;
+    }
+#endif
+
+    // - If no clients are specified, bring up a connection dialog
+    if (configFiles.empty() && hosts.empty() && !acceptIncoming && !print_usage)
+      hosts.push_back(0);
+
+    programInfo();
+
+    // - Connect to the clients
+    if (!configFiles.empty() || !hosts.empty() || acceptIncoming) {
+      // - Configure the registry configuration reader
+      win32::RegConfigThread config;
+      config.start(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+
+      // - Tell the rest of VNC Viewer where to write config data to
+      CConn::userConfigKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+
+      if (acceptIncoming) {
+        int port = 5500;
+
+        // Listening viewer
+        if (hosts.size() > 1)
+          programUsage();
+        if (!hosts.empty())
+          port = atoi(hosts.front());  
+
+        // Show the tray icon & menu
+        ListenTrayIcon tray;
+
+        // Listen for reverse connections
+        network::TcpListener sock(port);
+        ListenServer listener(&sock);
+
+        // Run the view manager
+        // Also processes the tray icon if necessary
+        MSG msg;
+        while (GetMessage(&msg, NULL, 0, 0) > 0) {
+          TranslateMessage(&msg);
+          DispatchMessage(&msg);
+        }
+      } else {
+        // Read each config file in turn
+        while (!configFiles.empty()) {
+          char* filename = configFiles.front();
+          Thread* connThread = new CConnThread(filename, true);
+          strFree(filename);
+          configFiles.pop_front();
+        }
+
+        // Connect to each client in turn
+        while (!hosts.empty()) {
+          char* hostinfo = hosts.front();
+          Thread* connThread = new CConnThread(hostinfo);
+          strFree(hostinfo);
+          hosts.pop_front();
+        }
+
+        // Run the view manager
+        MSG msg;
+        while (CConnThread::getMessage(&msg, NULL, 0, 0) > 0) {
+          TranslateMessage(&msg);
+          DispatchMessage(&msg);
+        }
+
+        vlog.debug("quitting viewer");
+      }
+
+    }
+
+    // - If necessary, print the program's usage info
+    if (print_usage)
+      programUsage();
+
+    if (!close_console) {
+      printf("Press Enter/Return key to continue\n");
+      char c = getchar();
+    }
+
+  } catch (rdr::Exception& e) {
+    MsgBox(0, TStr(e.str()), MB_ICONSTOP | MB_OK);
+  }
+
+  return 0;
+}
diff --git a/win/vncviewer/vncviewer.dsp b/win/vncviewer/vncviewer.dsp
new file mode 100644
index 0000000..e245cd6
--- /dev/null
+++ b/win/vncviewer/vncviewer.dsp
@@ -0,0 +1,321 @@
+# Microsoft Developer Studio Project File - Name="vncviewer" - Package Owner=<4>

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

+# ** DO NOT EDIT **

+

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

+

+CFG=vncviewer - Win32 Debug Unicode

+!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 "vncviewer.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 "vncviewer.mak" CFG="vncviewer - Win32 Debug Unicode"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

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

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

+!MESSAGE "vncviewer - Win32 Debug Unicode" (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)" == "vncviewer - 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\vncviewer"

+# 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 RSC /l 0x809 /d "NDEBUG"

+# ADD RSC /l 0x809 /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 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 ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /machine:I386

+# Begin Special Build Tool

+SOURCE="$(InputPath)"

+PreLink_Desc=Updating buildTime

+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\vncviewer /MT buildTime.cxx

+# End Special Build Tool

+

+!ELSEIF  "$(CFG)" == "vncviewer - 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\vncviewer"

+# 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 RSC /l 0x809 /d "_DEBUG"

+# ADD RSC /l 0x809 /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 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 /incremental:no /debug /machine:I386 /pdbtype:sept

+# Begin Special Build Tool

+SOURCE="$(InputPath)"

+PreLink_Desc=Updating buildTime

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

+# End Special Build Tool

+

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

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "vncviewer___Win32_Debug_Unicode"

+# PROP BASE Intermediate_Dir "vncviewer___Win32_Debug_Unicode"

+# PROP BASE Ignore_Export_Lib 0

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "..\Debug_Unicode"

+# PROP Intermediate_Dir "..\Debug_Unicode\vncviewer"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

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

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

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

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

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.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_Desc=Updating buildTime

+PreLink_Cmds=cl /c /nologo /Fo..\Debug_Unicode\ /Fd..\Debug_Unicode\vncviewer /MTd buildTime.cxx

+# End Special Build Tool

+

+!ENDIF 

+

+# Begin Target

+

+# Name "vncviewer - Win32 Release"

+# Name "vncviewer - Win32 Debug"

+# Name "vncviewer - Win32 Debug Unicode"

+# 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=.\CConn.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CConnOptions.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CConnThread.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ConnectingDialog.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ConnectionDialog.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\DesktopWindow.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileTransfer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTBrowseDlg.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTDialog.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTListView.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTProgress.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\InfoDialog.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\OptionsDialog.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\UserPasswdDialog.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ViewerToolBar.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\vncviewer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\vncviewer.rc

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

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

+# Begin Source File

+

+SOURCE=.\CConn.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CConnOptions.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CConnThread.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ConnectingDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ConnectionDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\DesktopWindow.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileTransfer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTBrowseDlg.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTListView.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FTProgress.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\InfoDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ListenServer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ListenTrayIcon.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\MRU.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\OptionsDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\UserPasswdDialog.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ViewerToolBar.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=.\cursor1.cur

+# End Source File

+# Begin Source File

+

+SOURCE=.\ftdir.ico

+# End Source File

+# Begin Source File

+

+SOURCE=.\ftfile.ico

+# End Source File

+# Begin Source File

+

+SOURCE=.\ftreload.ico

+# End Source File

+# Begin Source File

+

+SOURCE=.\ftup.ico

+# End Source File

+# Begin Source File

+

+SOURCE=.\toolbar.bmp

+# End Source File

+# Begin Source File

+

+SOURCE=.\vncviewer.bmp

+# End Source File

+# Begin Source File

+

+SOURCE=.\vncviewer.exe.manifest

+# End Source File

+# Begin Source File

+

+SOURCE=.\vncviewer.ico

+# End Source File

+# End Group

+# End Target

+# End Project

diff --git a/win/vncviewer/vncviewer.exe.manifest b/win/vncviewer/vncviewer.exe.manifest
new file mode 100644
index 0000000..7fd947f
--- /dev/null
+++ b/win/vncviewer/vncviewer.exe.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+   version="4.0.0.26"
+   processorArchitecture="X86"
+   name="TightVNC.vncviewer.exe"
+   type="win32"
+/>
+<description>.NET control deployment tool</description>
+<dependency>
+   <dependentAssembly>
+     <assemblyIdentity
+       type="win32"
+       name="Microsoft.Windows.Common-Controls"
+       version="6.0.0.0"
+       processorArchitecture="X86"
+       publicKeyToken="6595b64144ccf1df"
+       language="*"
+     />
+   </dependentAssembly>
+</dependency>
+</assembly>
diff --git a/win/vncviewer/vncviewer.ico b/win/vncviewer/vncviewer.ico
new file mode 100644
index 0000000..6572661
--- /dev/null
+++ b/win/vncviewer/vncviewer.ico
Binary files differ
diff --git a/win/vncviewer/vncviewer.rc b/win/vncviewer/vncviewer.rc
new file mode 100644
index 0000000..ea5dd65
--- /dev/null
+++ b/win/vncviewer/vncviewer.rc
@@ -0,0 +1,708 @@
+//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.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
+
+#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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON                ICON    DISCARDABLE     "vncviewer.ico"
+IDI_FTDIR               ICON    DISCARDABLE     "ftdir.ico"
+IDI_FTFILE              ICON    DISCARDABLE     "ftfile.ico"
+IDI_FTRELOAD            ICON    DISCARDABLE     "ftreload.ico"
+IDI_FTUP                ICON    DISCARDABLE     "ftup.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,1,1,0
+ PRODUCTVERSION 4,1,1,0
+ 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", "Constantin Kaplinsky\0"
+            VALUE "FileDescription", "TightVNC Viewer for Win32\0"
+            VALUE "FileVersion", "4.1.1\0"
+            VALUE "InternalName", "free4/vncviewer/win\0"
+            VALUE "LegalCopyright", "Copyright (C) 1998-2006 [many holders]\0"
+            VALUE "LegalTrademarks", "TightVNC\0"
+            VALUE "OriginalFilename", "vncviewer.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "TightVNC Viewer\0"
+            VALUE "ProductVersion", "4.1.1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x809, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_VNC_AUTH_DLG DIALOG DISCARDABLE  0, 0, 241, 46
+STYLE DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION
+CAPTION "VNC Viewer : Authentication"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_USERNAME,85,6,100,14,ES_AUTOHSCROLL
+    EDITTEXT        IDC_PASSWORD,85,25,100,15,ES_PASSWORD | ES_AUTOHSCROLL | 
+                    ES_WANTRETURN
+    DEFPUSHBUTTON   "OK",IDOK,190,6,45,14
+    PUSHBUTTON      "Cancel",IDCANCEL,190,25,45,15
+    CONTROL         120,IDI_ICON,"Static",SS_BITMAP,7,6,21,20
+    LTEXT           "Username:",IDC_STATIC,45,6,35,14
+    LTEXT           "Password:",IDC_STATIC,45,25,35,15
+END
+
+IDD_CONNECTING_DLG DIALOG DISCARDABLE  0, 0, 185, 47
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION
+CAPTION "VNC Viewer : Connecting"
+FONT 8, "MS Sans Serif"
+BEGIN
+    PUSHBUTTON      "Cancel",IDCANCEL,128,26,50,14
+    CTEXT           "Attempting to connect to host...",IDC_CONNECTING_TEXT,7,
+                    7,171,14,SS_CENTERIMAGE
+END
+
+IDD_CONNECTION_DLG DIALOG DISCARDABLE  0, 0, 224, 66
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "VNC Viewer : Connection Details"
+FONT 8, "MS Sans Serif"
+BEGIN
+    COMBOBOX        IDC_SERVER_EDIT,85,6,105,234,CBS_DROPDOWN | 
+                    CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "&About...",IDC_ABOUT,5,45,50,14
+    PUSHBUTTON      "&Options...",IDC_OPTIONS,60,45,50,14
+    DEFPUSHBUTTON   "OK",IDOK,115,45,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,170,45,48,14
+    CONTROL         120,IDI_ICON,"Static",SS_BITMAP | SS_REALSIZEIMAGE,5,6,
+                    20,20
+    RTEXT           "Server:",IDC_STATIC,43,6,37,13,SS_CENTERIMAGE
+    RTEXT           "Encryption:",IDC_STATIC,43,24,37,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_SECURITY_LEVEL,85,24,105,76,CBS_DROPDOWNLIST | 
+                    CBS_SORT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_ABOUT DIALOG DISCARDABLE  0, 0, 249, 92
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "About VNC Viewer for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,195,70,47,15
+    CONTROL         120,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,7,
+                    10,33,31
+    LTEXT           ">appname<",IDC_DESCRIPTION,46,10,119,15
+    LTEXT           ">version<",IDC_VERSION,165,10,77,15
+    LTEXT           ">buildtime<",IDC_BUILDTIME,46,25,196,15
+    LTEXT           ">copyright<",IDC_COPYRIGHT,46,40,196,15
+    LTEXT           "Visit www.tightvnc.com for more information on TightVNC.",
+                    IDC_STATIC,46,55,196,15
+END
+
+IDD_FORMAT DIALOG DISCARDABLE  0, 0, 201, 161
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Colour && Encoding"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "&Auto select",IDC_ENCODING_AUTO,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,7,88,13
+    GROUPBOX        "Preferred encoding",IDC_STATIC,7,20,83,75
+    CONTROL         "Tight",IDC_ENCODING_TIGHT,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP,10,30,75,14
+    CONTROL         "ZRLE",IDC_ENCODING_ZRLE,"Button",BS_AUTORADIOBUTTON,10,
+                    45,75,14
+    CONTROL         "Hextile",IDC_ENCODING_HEXTILE,"Button",
+                    BS_AUTORADIOBUTTON,10,60,75,16
+    CONTROL         "Raw",IDC_ENCODING_RAW,"Button",BS_AUTORADIOBUTTON,10,75,
+                    75,15
+    GROUPBOX        "Color level",IDC_STATIC,95,20,99,75
+    CONTROL         "&Full (all available colors)",IDC_FORMAT_FULLCOLOUR,
+                    "Button",BS_AUTORADIOBUTTON | WS_GROUP,100,30,90,15
+    CONTROL         "&Medium (256 colors)",IDC_FORMAT_MEDIUMCOLOUR,"Button",
+                    BS_AUTORADIOBUTTON,100,45,90,14
+    CONTROL         "&Low (64 colors)",IDC_FORMAT_LOWCOLOUR,"Button",
+                    BS_AUTORADIOBUTTON,100,60,90,16
+    CONTROL         "&Very low (8 colors)",IDC_FORMAT_VERYLOWCOLOUR,"Button",
+                    BS_AUTORADIOBUTTON,100,75,90,15
+    CONTROL         "Custom compression level:",IDC_CUSTOM_COMPRESSLEVEL,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,100,99,10
+    EDITTEXT        IDC_COMPRESSLEVEL,25,111,15,12,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    LTEXT           "level (1=fast, 9=best)",IDC_STATIC,44,114,81,9,NOT 
+                    WS_GROUP
+    CONTROL         "Allow JPEG compression:",IDC_ALLOW_JPEG,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,10,126,96,10
+    EDITTEXT        IDC_QUALITYLEVEL,25,137,15,12,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "quality (1=poor, 9=best)",IDC_STATIC,44,140,81,9
+END
+
+IDD_MISC DIALOG DISCARDABLE  0, 0, 213, 137
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Misc"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Shared connection (do not disconnect other viewers)",
+                    IDC_CONN_SHARED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,
+                    10,199,15
+    CONTROL         "Full-screen mode",IDC_FULL_SCREEN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,25,99,15
+    CONTROL         "Show toolbar",IDC_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,106,25,100,15
+    CONTROL         "Render cursor locally",IDC_LOCAL_CURSOR,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,40,199,15
+    CONTROL         "Allow dynamic desktop resizing",IDC_DESKTOP_RESIZE,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,199,15
+    CONTROL         "Only use protocol version 3.3",IDC_PROTOCOL_3_3,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,70,199,15
+    CONTROL         "Beep when requested to by the server",IDC_ACCEPT_BELL,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,85,199,15
+    CONTROL         "Offer to automatically reconnect",IDC_AUTO_RECONNECT,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,199,15
+END
+
+IDD_INPUTS DIALOG DISCARDABLE  0, 0, 186, 162
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Inputs"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Send pointer events to server",IDC_SEND_POINTER,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,10,172,15
+    CONTROL         "Send keyboard events to server",IDC_SEND_KEYS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,25,172,15
+    CONTROL         "Send clipboard changes to server",IDC_CLIENT_CUTTEXT,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,172,15
+    CONTROL         "Accept clipboard changes from server",
+                    IDC_SERVER_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    7,55,172,15
+    CONTROL         "Enable 3-button mouse emulation",IDC_EMULATE3,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,70,172,15
+    CONTROL         "Rate-limit mouse move events",IDC_POINTER_INTERVAL,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,86,172,14
+    LTEXT           "Menu key",IDC_STATIC,7,100,98,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_MENU_KEY,105,100,74,105,CBS_DROPDOWNLIST | CBS_SORT | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Pass special keys directly to server",
+                    IDC_DISABLE_WINKEYS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,7,115,172,15
+END
+
+IDD_CONNECTION_INFO DIALOG DISCARDABLE  0, 0, 239, 199
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "VNC Connection Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,182,178,50,14
+    LTEXT           "Desktop Name:",IDC_STATIC,7,10,73,15
+    LTEXT           "Host:",IDC_STATIC,7,25,73,15
+    LTEXT           "Size:",IDC_STATIC,7,40,73,15
+    LTEXT           "Pixel Format:",IDC_STATIC,7,55,73,15
+    LTEXT           "Server Default:",IDC_STATIC,7,70,73,15
+    LTEXT           "Line Speed Estimate:",IDC_STATIC,7,115,73,15
+    LTEXT           "Protocol Version:",IDC_STATIC,7,130,73,15
+    LTEXT           "",IDC_INFO_NAME,80,10,152,15
+    LTEXT           "",IDC_INFO_HOST,80,25,152,15
+    LTEXT           "",IDC_INFO_SIZE,80,40,152,15
+    LTEXT           "",IDC_INFO_PF,80,55,152,15
+    LTEXT           "",IDC_INFO_DEF_PF,80,70,152,15
+    LTEXT           "",IDC_INFO_LINESPEED,80,115,152,15
+    LTEXT           "",IDC_INFO_VERSION,80,130,152,15
+    LTEXT           "Security Method:",IDC_STATIC,7,145,73,15
+    LTEXT           "",IDC_INFO_SECURITY,80,145,152,15
+    LTEXT           "Requested Encoding:",IDC_STATIC,7,85,73,15
+    LTEXT           "Last Used Encoding:",IDC_STATIC,7,100,73,15
+    LTEXT           "",IDC_REQUESTED_ENCODING,80,86,152,15
+    LTEXT           "",IDC_LAST_ENCODING,80,100,152,15
+    LTEXT           "Static",IDC_INFO_ENCRYPTION,80,160,152,15
+    LTEXT           "Encryption:",IDC_STATIC,7,160,73,15
+END
+
+IDD_DEFAULTS DIALOG DISCARDABLE  0, 0, 217, 87
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Load / Save"
+FONT 8, "MS Sans Serif"
+BEGIN
+    PUSHBUTTON      "&Reload",IDC_LOAD_CONFIG,15,20,85,15
+    PUSHBUTTON      "&Save",IDC_SAVE_CONFIG,15,40,85,15
+    PUSHBUTTON      "Save &As ...",IDC_SAVE_CONFIG_AS,15,60,85,15
+    PUSHBUTTON      "R&eload",IDC_LOAD_DEFAULTS,120,20,85,15
+    PUSHBUTTON      "S&ave",IDC_SAVE_DEFAULTS,120,40,85,15
+    GROUPBOX        "Configuration File",IDC_STATIC,7,7,100,74
+    GROUPBOX        "Defaults",IDC_STATIC,113,7,97,53
+END
+
+IDD_FILETRANSFER_DLG DIALOGEX 0, 0, 530, 282
+STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
+    WS_SYSMENU
+EXSTYLE WS_EX_CONTEXTHELP | WS_EX_CONTROLPARENT
+CAPTION "TightVNC File Transfers"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "List1",IDC_FTLOCALLIST,"SysListView32",LVS_REPORT | 
+                    LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | 
+                    WS_TABSTOP,7,40,200,196
+    CONTROL         "List2",IDC_FTREMOTELIST,"SysListView32",LVS_REPORT | 
+                    LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | 
+                    WS_TABSTOP,323,40,200,196
+    PUSHBUTTON      "Upload Files and Folders",IDC_FTUPLOAD,218,66,94,12,
+                    WS_DISABLED
+    PUSHBUTTON      "Download Files and Folders",IDC_FTDOWNLOAD,218,85,94,12,
+                    WS_DISABLED
+    PUSHBUTTON      "Cancel File Transfer",IDC_FTCANCEL,218,167,94,12,
+                    WS_DISABLED
+    PUSHBUTTON      "Close",IDC_FTCLOSE,218,217,94,12
+    EDITTEXT        IDC_FTLOCALPATH,7,20,155,12,ES_AUTOHSCROLL | NOT 
+                    WS_TABSTOP
+    CTEXT           "Local Computer",IDC_FTLOCALLABEL,7,7,200,10
+    PUSHBUTTON      "...",IDC_FTLOCALBROWSE,165,20,14,12,NOT WS_TABSTOP
+    PUSHBUTTON      "",IDC_FTLOCALUP,179,20,14,12,BS_ICON | NOT WS_TABSTOP
+    PUSHBUTTON      "",IDC_FTLOCALRELOAD,193,20,14,12,BS_ICON | NOT 
+                    WS_TABSTOP
+    CONTROL         "Progress1",IDC_FTGENERALPROGRESS,"msctls_progress32",
+                    WS_BORDER,55,244,128,10
+    LTEXT           "File Transfer",IDC_STATIC,7,245,40,8
+    COMBOBOX        IDC_FTSTATUS,7,263,516,65,CBS_DROPDOWNLIST | 
+                    CBS_NOINTEGRALHEIGHT | WS_VSCROLL
+    CONTROL         "Progress1",IDC_FTSINGLEPROGRESS,"msctls_progress32",
+                    WS_BORDER,370,244,128,10
+    EDITTEXT        IDC_FTREMOTEPATH,323,20,155,12,ES_AUTOHSCROLL | NOT 
+                    WS_TABSTOP
+    PUSHBUTTON      "...",IDC_FTREMOTEBROWSE,481,20,14,12,NOT WS_TABSTOP
+    PUSHBUTTON      "",IDC_FTREMOTEUP,495,20,14,12,BS_ICON | NOT WS_TABSTOP
+    PUSHBUTTON      "",IDC_FTREMOTERELOAD,509,20,14,12,BS_ICON | NOT 
+                    WS_TABSTOP
+    CTEXT           "TightVNC Server",IDC_FTREMOTELABEL,323,7,200,10
+    LTEXT           "Current File",IDC_STATIC,323,245,36,8
+    CTEXT           "0%",IDC_FTGENERALPERCENT,189,245,18,8
+    CTEXT           "0%",IDC_FTSINGLEPERCENT,505,245,18,8
+END
+
+IDD_FTBROWSE DIALOGEX 0, 0, 183, 196
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Browse Folders"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,38,175,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,95,175,50,14
+    EDITTEXT        IDC_FTBROWSEPATH,7,7,169,12,ES_AUTOHSCROLL | ES_READONLY | 
+                    NOT WS_TABSTOP
+    CONTROL         "Tree1",IDC_FTBROWSETREE,"SysTreeView32",TVS_HASBUTTONS | 
+                    TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | 
+                    TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,25,169,143
+END
+
+IDD_FTCANCELING DIALOG DISCARDABLE  0, 0, 193, 63
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Canceling Active File Transfer"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "Yes",IDOK,40,42,50,14
+    PUSHBUTTON      "No",IDCANCEL,102,42,50,14
+    LTEXT           "FileTransfer is active.\nAre you sure you want to cancel transfer?",
+                    IDC_STATIC,42,14,133,19
+END
+
+IDD_FTCONFIRM_DLG DIALOG DISCARDABLE  0, 0, 188, 143
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "Yes",IDOK,69,122,50,14,WS_GROUP
+    PUSHBUTTON      "No",IDCANCEL,131,122,50,14
+    PUSHBUTTON      "Yes to All",IDC_CONFIRM_YESTOALL,7,122,50,14
+    LTEXT           "Static",IDC_CONFIRM_TEXT,7,7,174,107
+END
+
+IDD_FTCREATEFOLDER DIALOG DISCARDABLE  0, 0, 193, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Create a New Folder"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_FTFOLDERNAME,7,19,179,14,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "OK",IDOK,80,42,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,136,42,50,14
+    LTEXT           "New folder name:",IDC_FTTEXT,7,7,179,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_VNC_AUTH_DLG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 235
+        VERTGUIDE, 45
+        VERTGUIDE, 80
+        VERTGUIDE, 85
+        VERTGUIDE, 185
+        VERTGUIDE, 190
+        TOPMARGIN, 6
+        BOTTOMMARGIN, 40
+        HORZGUIDE, 20
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+    END
+
+    IDD_CONNECTING_DLG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 178
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 40
+        HORZGUIDE, 21
+        HORZGUIDE, 26
+    END
+
+    IDD_CONNECTION_DLG, DIALOG
+    BEGIN
+        LEFTMARGIN, 5
+        RIGHTMARGIN, 218
+        VERTGUIDE, 30
+        VERTGUIDE, 43
+        VERTGUIDE, 55
+        VERTGUIDE, 60
+        VERTGUIDE, 80
+        VERTGUIDE, 85
+        VERTGUIDE, 110
+        VERTGUIDE, 115
+        VERTGUIDE, 165
+        VERTGUIDE, 170
+        VERTGUIDE, 190
+        TOPMARGIN, 6
+        BOTTOMMARGIN, 59
+        HORZGUIDE, 19
+        HORZGUIDE, 24
+        HORZGUIDE, 36
+        HORZGUIDE, 45
+    END
+
+    IDD_ABOUT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 242
+        VERTGUIDE, 46
+        VERTGUIDE, 165
+        VERTGUIDE, 195
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 85
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+    END
+
+    IDD_FORMAT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 194
+        VERTGUIDE, 10
+        VERTGUIDE, 85
+        VERTGUIDE, 90
+        VERTGUIDE, 95
+        VERTGUIDE, 100
+        VERTGUIDE, 105
+        VERTGUIDE, 190
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 154
+        HORZGUIDE, 10
+        HORZGUIDE, 20
+        HORZGUIDE, 25
+        HORZGUIDE, 35
+        HORZGUIDE, 49
+        HORZGUIDE, 65
+        HORZGUIDE, 80
+        HORZGUIDE, 85
+    END
+
+    IDD_MISC, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 206
+        VERTGUIDE, 106
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 130
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+        HORZGUIDE, 100
+        HORZGUIDE, 115
+        HORZGUIDE, 130
+    END
+
+    IDD_INPUTS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 179
+        VERTGUIDE, 105
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 155
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+        HORZGUIDE, 100
+        HORZGUIDE, 115
+        HORZGUIDE, 130
+        HORZGUIDE, 145
+    END
+
+    IDD_CONNECTION_INFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 232
+        VERTGUIDE, 80
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 192
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+        HORZGUIDE, 100
+        HORZGUIDE, 115
+        HORZGUIDE, 130
+        HORZGUIDE, 145
+        HORZGUIDE, 160
+        HORZGUIDE, 175
+    END
+
+    IDD_DEFAULTS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 210
+        VERTGUIDE, 15
+        VERTGUIDE, 100
+        VERTGUIDE, 107
+        VERTGUIDE, 113
+        VERTGUIDE, 120
+        VERTGUIDE, 205
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 80
+        HORZGUIDE, 20
+        HORZGUIDE, 35
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 60
+        HORZGUIDE, 75
+    END
+
+    IDD_FILETRANSFER_DLG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 523
+        VERTGUIDE, 207
+        VERTGUIDE, 265
+        VERTGUIDE, 323
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 275
+        HORZGUIDE, 12
+        HORZGUIDE, 26
+        HORZGUIDE, 40
+        HORZGUIDE, 47
+        HORZGUIDE, 249
+    END
+
+    IDD_FTBROWSE, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 176
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 189
+    END
+
+    IDD_FTCANCELING, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 186
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 56
+    END
+
+    IDD_FTCONFIRM_DLG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 181
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 136
+    END
+
+    IDD_FTCREATEFOLDER, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 186
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 56
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_DOT_CURSOR          CURSOR  DISCARDABLE     "cursor1.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog Info
+//
+
+IDD_CONNECTION_DLG DLGINIT
+BEGIN
+    IDC_SERVER_EDIT, 0x403, 16, 0
+0x796d, 0x616d, 0x6863, 0x6e69, 0x2e65, 0x726f, 0x3a67, 0x0031, 
+    0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAY MENU DISCARDABLE 
+BEGIN
+    POPUP "Tray Menu"
+    BEGIN
+        MENUITEM "&New Connection...",          ID_NEW_CONNECTION
+        MENUITEM SEPARATOR
+        MENUITEM "Default &Options...",         ID_OPTIONS
+        MENUITEM SEPARATOR
+        MENUITEM "&Close Daemon",               ID_CLOSE
+        MENUITEM "&About...",                   ID_ABOUT
+    END
+END
+
+IDR_FTMENU MENU DISCARDABLE 
+BEGIN
+    POPUP "File Transfer"
+    BEGIN
+        MENUITEM "Copy Files and Folders",      IDM_FTCOPY
+        MENUITEM SEPARATOR
+        MENUITEM "Create a Folder",             IDM_FTCREATEFOLDER
+        MENUITEM "Rename File or Folder",       IDM_FTRENAME
+        MENUITEM "Delete Files and Folders",    IDM_FTDELETE
+        MENUITEM SEPARATOR
+        MENUITEM "Cancel File Transfer",        IDM_FTCANCEL
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 24
+//
+
+IDR_MANIFEST            24      DISCARDABLE     "vncviewer.exe.manifest"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP              BITMAP  DISCARDABLE     "vncviewer.bmp"
+IDB_TOOLBAR             BITMAP  DISCARDABLE     "toolbar.bmp"
+#endif    // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+