]> source.dussan.org Git - tigervnc.git/commitdiff
Migrating to new directory structure adopted from the RealVNC's source tree. More...
authorConstantin Kaplinsky <const@tightvnc.com>
Thu, 25 May 2006 05:12:25 +0000 (05:12 +0000)
committerConstantin Kaplinsky <const@tightvnc.com>
Thu, 25 May 2006 05:12:25 +0000 (05:12 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@591 3789f03b-4d11-0410-bbf8-ca57d06f2519

228 files changed:
win/README.txt [new file with mode: 0644]
win/README_BINARY.txt [new file with mode: 0644]
win/logmessages/logmessages.dsp [new file with mode: 0644]
win/logmessages/messages.h [new file with mode: 0644]
win/logmessages/messages.mc [new file with mode: 0644]
win/logmessages/messages.rc [new file with mode: 0644]
win/rfb_win32/AboutDialog.cxx [new file with mode: 0644]
win/rfb_win32/AboutDialog.h [new file with mode: 0644]
win/rfb_win32/BitmapInfo.h [new file with mode: 0644]
win/rfb_win32/CKeyboard.cxx [new file with mode: 0644]
win/rfb_win32/CKeyboard.h [new file with mode: 0644]
win/rfb_win32/CPointer.cxx [new file with mode: 0644]
win/rfb_win32/CPointer.h [new file with mode: 0644]
win/rfb_win32/CleanDesktop.cxx [new file with mode: 0644]
win/rfb_win32/CleanDesktop.h [new file with mode: 0644]
win/rfb_win32/Clipboard.cxx [new file with mode: 0644]
win/rfb_win32/Clipboard.h [new file with mode: 0644]
win/rfb_win32/CompatibleBitmap.h [new file with mode: 0644]
win/rfb_win32/ComputerName.h [new file with mode: 0644]
win/rfb_win32/CurrentUser.cxx [new file with mode: 0644]
win/rfb_win32/CurrentUser.h [new file with mode: 0644]
win/rfb_win32/DIBSectionBuffer.cxx [new file with mode: 0644]
win/rfb_win32/DIBSectionBuffer.h [new file with mode: 0644]
win/rfb_win32/DeviceContext.cxx [new file with mode: 0644]
win/rfb_win32/DeviceContext.h [new file with mode: 0644]
win/rfb_win32/DeviceFrameBuffer.cxx [new file with mode: 0644]
win/rfb_win32/DeviceFrameBuffer.h [new file with mode: 0644]
win/rfb_win32/Dialog.cxx [new file with mode: 0644]
win/rfb_win32/Dialog.h [new file with mode: 0644]
win/rfb_win32/DynamicFn.cxx [new file with mode: 0644]
win/rfb_win32/DynamicFn.h [new file with mode: 0644]
win/rfb_win32/EventManager.cxx [new file with mode: 0644]
win/rfb_win32/EventManager.h [new file with mode: 0644]
win/rfb_win32/FolderManager.cxx [new file with mode: 0644]
win/rfb_win32/FolderManager.h [new file with mode: 0644]
win/rfb_win32/Handle.h [new file with mode: 0644]
win/rfb_win32/IconInfo.h [new file with mode: 0644]
win/rfb_win32/IntervalTimer.h [new file with mode: 0644]
win/rfb_win32/LaunchProcess.cxx [new file with mode: 0644]
win/rfb_win32/LaunchProcess.h [new file with mode: 0644]
win/rfb_win32/ListViewControl.cxx [new file with mode: 0644]
win/rfb_win32/ListViewControl.h [new file with mode: 0644]
win/rfb_win32/LocalMem.h [new file with mode: 0644]
win/rfb_win32/LogicalPalette.h [new file with mode: 0644]
win/rfb_win32/LowLevelKeyEvents.cxx [new file with mode: 0644]
win/rfb_win32/LowLevelKeyEvents.h [new file with mode: 0644]
win/rfb_win32/ModuleFileName.h [new file with mode: 0644]
win/rfb_win32/MonitorInfo.cxx [new file with mode: 0644]
win/rfb_win32/MonitorInfo.h [new file with mode: 0644]
win/rfb_win32/MsgBox.h [new file with mode: 0644]
win/rfb_win32/MsgWindow.cxx [new file with mode: 0644]
win/rfb_win32/MsgWindow.h [new file with mode: 0644]
win/rfb_win32/OSVersion.cxx [new file with mode: 0644]
win/rfb_win32/OSVersion.h [new file with mode: 0644]
win/rfb_win32/ProgressControl.cxx [new file with mode: 0644]
win/rfb_win32/ProgressControl.h [new file with mode: 0644]
win/rfb_win32/RegConfig.cxx [new file with mode: 0644]
win/rfb_win32/RegConfig.h [new file with mode: 0644]
win/rfb_win32/Registry.cxx [new file with mode: 0644]
win/rfb_win32/Registry.h [new file with mode: 0644]
win/rfb_win32/SDisplay.cxx [new file with mode: 0644]
win/rfb_win32/SDisplay.h [new file with mode: 0644]
win/rfb_win32/SDisplayCoreDriver.h [new file with mode: 0644]
win/rfb_win32/SDisplayCorePolling.cxx [new file with mode: 0644]
win/rfb_win32/SDisplayCorePolling.h [new file with mode: 0644]
win/rfb_win32/SDisplayCoreWMHooks.cxx [new file with mode: 0644]
win/rfb_win32/SDisplayCoreWMHooks.h [new file with mode: 0644]
win/rfb_win32/SFileTransferManagerWin32.cxx [new file with mode: 0644]
win/rfb_win32/SFileTransferManagerWin32.h [new file with mode: 0644]
win/rfb_win32/SFileTransferWin32.cxx [new file with mode: 0644]
win/rfb_win32/SFileTransferWin32.h [new file with mode: 0644]
win/rfb_win32/SInput.cxx [new file with mode: 0644]
win/rfb_win32/SInput.h [new file with mode: 0644]
win/rfb_win32/ScaledDIBSectionBuffer.cxx [new file with mode: 0644]
win/rfb_win32/ScaledDIBSectionBuffer.h [new file with mode: 0644]
win/rfb_win32/Security.cxx [new file with mode: 0644]
win/rfb_win32/Security.h [new file with mode: 0644]
win/rfb_win32/Service.cxx [new file with mode: 0644]
win/rfb_win32/Service.h [new file with mode: 0644]
win/rfb_win32/SocketManager.cxx [new file with mode: 0644]
win/rfb_win32/SocketManager.h [new file with mode: 0644]
win/rfb_win32/TCharArray.cxx [new file with mode: 0644]
win/rfb_win32/TCharArray.h [new file with mode: 0644]
win/rfb_win32/Threading.cxx [new file with mode: 0644]
win/rfb_win32/Threading.h [new file with mode: 0644]
win/rfb_win32/ToolBar.cxx [new file with mode: 0644]
win/rfb_win32/ToolBar.h [new file with mode: 0644]
win/rfb_win32/TrayIcon.h [new file with mode: 0644]
win/rfb_win32/TsSessions.cxx [new file with mode: 0644]
win/rfb_win32/TsSessions.h [new file with mode: 0644]
win/rfb_win32/WMCursor.cxx [new file with mode: 0644]
win/rfb_win32/WMCursor.h [new file with mode: 0644]
win/rfb_win32/WMHooks.cxx [new file with mode: 0644]
win/rfb_win32/WMHooks.h [new file with mode: 0644]
win/rfb_win32/WMNotifier.cxx [new file with mode: 0644]
win/rfb_win32/WMNotifier.h [new file with mode: 0644]
win/rfb_win32/WMPoller.cxx [new file with mode: 0644]
win/rfb_win32/WMPoller.h [new file with mode: 0644]
win/rfb_win32/WMShatter.cxx [new file with mode: 0644]
win/rfb_win32/WMShatter.h [new file with mode: 0644]
win/rfb_win32/WMWindowCopyRect.cxx [new file with mode: 0644]
win/rfb_win32/WMWindowCopyRect.h [new file with mode: 0644]
win/rfb_win32/Win32Util.cxx [new file with mode: 0644]
win/rfb_win32/Win32Util.h [new file with mode: 0644]
win/rfb_win32/keymap.h [new file with mode: 0644]
win/rfb_win32/rfb_win32.dsp [new file with mode: 0644]
win/rfbplayer/ChoosePixelFormatDialog.h [new file with mode: 0644]
win/rfbplayer/EditPixelFormatDialog.h [new file with mode: 0644]
win/rfbplayer/FbsInputStream.cxx [new file with mode: 0644]
win/rfbplayer/FbsInputStream.h [new file with mode: 0644]
win/rfbplayer/GotoPosDialog.h [new file with mode: 0644]
win/rfbplayer/InfoDialog.h [new file with mode: 0644]
win/rfbplayer/OptionsDialog.h [new file with mode: 0644]
win/rfbplayer/PixelFormatList.cxx [new file with mode: 0644]
win/rfbplayer/PixelFormatList.h [new file with mode: 0644]
win/rfbplayer/PlayerOptions.cxx [new file with mode: 0644]
win/rfbplayer/PlayerOptions.h [new file with mode: 0644]
win/rfbplayer/PlayerToolBar.cxx [new file with mode: 0644]
win/rfbplayer/PlayerToolBar.h [new file with mode: 0644]
win/rfbplayer/RfbProto.cxx [new file with mode: 0644]
win/rfbplayer/RfbProto.h [new file with mode: 0644]
win/rfbplayer/SessionInfoDialog.h [new file with mode: 0644]
win/rfbplayer/UserPixelFormatsDialog.h [new file with mode: 0644]
win/rfbplayer/buildTime.cxx [new file with mode: 0644]
win/rfbplayer/resource.h [new file with mode: 0644]
win/rfbplayer/rfbSessionReader.h [new file with mode: 0644]
win/rfbplayer/rfbplayer.cxx [new file with mode: 0644]
win/rfbplayer/rfbplayer.dsp [new file with mode: 0644]
win/rfbplayer/rfbplayer.h [new file with mode: 0644]
win/rfbplayer/rfbplayer.ico [new file with mode: 0644]
win/rfbplayer/rfbplayer.rc [new file with mode: 0644]
win/rfbplayer/toolbar.bmp [new file with mode: 0644]
win/vnc.dsw [new file with mode: 0644]
win/vncconfig/Authentication.h [new file with mode: 0644]
win/vncconfig/Connections.h [new file with mode: 0644]
win/vncconfig/Desktop.h [new file with mode: 0644]
win/vncconfig/Hooking.h [new file with mode: 0644]
win/vncconfig/Inputs.h [new file with mode: 0644]
win/vncconfig/Legacy.cxx [new file with mode: 0644]
win/vncconfig/Legacy.h [new file with mode: 0644]
win/vncconfig/PasswordDialog.cxx [new file with mode: 0644]
win/vncconfig/PasswordDialog.h [new file with mode: 0644]
win/vncconfig/Sharing.h [new file with mode: 0644]
win/vncconfig/resource.h [new file with mode: 0644]
win/vncconfig/vncconfig.cxx [new file with mode: 0644]
win/vncconfig/vncconfig.dsp [new file with mode: 0644]
win/vncconfig/vncconfig.exe.manifest [new file with mode: 0644]
win/vncconfig/vncconfig.ico [new file with mode: 0644]
win/vncconfig/vncconfig.rc [new file with mode: 0644]
win/vncviewer/CConn.cxx [new file with mode: 0644]
win/vncviewer/CConn.h [new file with mode: 0644]
win/vncviewer/CConnOptions.cxx [new file with mode: 0644]
win/vncviewer/CConnOptions.h [new file with mode: 0644]
win/vncviewer/CConnThread.cxx [new file with mode: 0644]
win/vncviewer/CConnThread.h [new file with mode: 0644]
win/vncviewer/ConnectingDialog.cxx [new file with mode: 0644]
win/vncviewer/ConnectingDialog.h [new file with mode: 0644]
win/vncviewer/ConnectionDialog.cxx [new file with mode: 0644]
win/vncviewer/ConnectionDialog.h [new file with mode: 0644]
win/vncviewer/DesktopWindow.cxx [new file with mode: 0644]
win/vncviewer/DesktopWindow.h [new file with mode: 0644]
win/vncviewer/FTBrowseDlg.cxx [new file with mode: 0644]
win/vncviewer/FTBrowseDlg.h [new file with mode: 0644]
win/vncviewer/FTDialog.cxx [new file with mode: 0644]
win/vncviewer/FTDialog.h [new file with mode: 0644]
win/vncviewer/FTListView.cxx [new file with mode: 0644]
win/vncviewer/FTListView.h [new file with mode: 0644]
win/vncviewer/FTProgress.cxx [new file with mode: 0644]
win/vncviewer/FTProgress.h [new file with mode: 0644]
win/vncviewer/FileTransfer.cxx [new file with mode: 0644]
win/vncviewer/FileTransfer.h [new file with mode: 0644]
win/vncviewer/InfoDialog.cxx [new file with mode: 0644]
win/vncviewer/InfoDialog.h [new file with mode: 0644]
win/vncviewer/ListenServer.h [new file with mode: 0644]
win/vncviewer/ListenTrayIcon.h [new file with mode: 0644]
win/vncviewer/MRU.h [new file with mode: 0644]
win/vncviewer/OptionsDialog.cxx [new file with mode: 0644]
win/vncviewer/OptionsDialog.h [new file with mode: 0644]
win/vncviewer/UserPasswdDialog.cxx [new file with mode: 0644]
win/vncviewer/UserPasswdDialog.h [new file with mode: 0644]
win/vncviewer/ViewerToolBar.cxx [new file with mode: 0644]
win/vncviewer/ViewerToolBar.h [new file with mode: 0644]
win/vncviewer/buildTime.cxx [new file with mode: 0644]
win/vncviewer/cursor1.cur [new file with mode: 0644]
win/vncviewer/ftdir.ico [new file with mode: 0644]
win/vncviewer/ftfile.ico [new file with mode: 0644]
win/vncviewer/ftreload.ico [new file with mode: 0644]
win/vncviewer/ftup.ico [new file with mode: 0644]
win/vncviewer/resource.h [new file with mode: 0644]
win/vncviewer/toolbar.bmp [new file with mode: 0644]
win/vncviewer/vncviewer.bmp [new file with mode: 0644]
win/vncviewer/vncviewer.cxx [new file with mode: 0644]
win/vncviewer/vncviewer.dsp [new file with mode: 0644]
win/vncviewer/vncviewer.exe.manifest [new file with mode: 0644]
win/vncviewer/vncviewer.ico [new file with mode: 0644]
win/vncviewer/vncviewer.rc [new file with mode: 0644]
win/winvnc/AddNewClientDialog.h [new file with mode: 0644]
win/winvnc/ControlPanel.cxx [new file with mode: 0644]
win/winvnc/ControlPanel.h [new file with mode: 0644]
win/winvnc/JavaViewer.cxx [new file with mode: 0644]
win/winvnc/JavaViewer.h [new file with mode: 0644]
win/winvnc/ManagedListener.cxx [new file with mode: 0644]
win/winvnc/ManagedListener.h [new file with mode: 0644]
win/winvnc/QueryConnectDialog.cxx [new file with mode: 0644]
win/winvnc/QueryConnectDialog.h [new file with mode: 0644]
win/winvnc/STrayIcon.cxx [new file with mode: 0644]
win/winvnc/STrayIcon.h [new file with mode: 0644]
win/winvnc/VNCServerService.cxx [new file with mode: 0644]
win/winvnc/VNCServerService.h [new file with mode: 0644]
win/winvnc/VNCServerWin32.cxx [new file with mode: 0644]
win/winvnc/VNCServerWin32.h [new file with mode: 0644]
win/winvnc/buildTime.cxx [new file with mode: 0644]
win/winvnc/connecte.ico [new file with mode: 0644]
win/winvnc/connected.ico [new file with mode: 0644]
win/winvnc/icon_dis.ico [new file with mode: 0644]
win/winvnc/resource.h [new file with mode: 0644]
win/winvnc/winvnc.bmp [new file with mode: 0644]
win/winvnc/winvnc.cxx [new file with mode: 0644]
win/winvnc/winvnc.dsp [new file with mode: 0644]
win/winvnc/winvnc.ico [new file with mode: 0644]
win/winvnc/winvnc.rc [new file with mode: 0644]
win/winvnc/winvnc4.exe.manifest [new file with mode: 0644]
win/wm_hooks/resource.h [new file with mode: 0644]
win/wm_hooks/wm_hooks.cxx [new file with mode: 0644]
win/wm_hooks/wm_hooks.def [new file with mode: 0644]
win/wm_hooks/wm_hooks.dsp [new file with mode: 0644]
win/wm_hooks/wm_hooks.h [new file with mode: 0644]
win/wm_hooks/wm_hooks.rc [new file with mode: 0644]

diff --git a/win/README.txt b/win/README.txt
new file mode 100644 (file)
index 0000000..a834b21
--- /dev/null
@@ -0,0 +1,128 @@
+
+TightVNC Source Distribution for Windows platforms
+==================================================
+
+Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
+Copyright (C) 2000-2004 Constantin Kaplinsky.
+Copyright (C) 2004 Peter Astrand, Cendio AB
+
+This software is distributed under the GNU General Public Licence as
+published by the Free Software Foundation.  See the file LICENCE.TXT
+for the conditions under which this software is made available.
+TightVNC also contains code from other sources.  See the
+Acknowledgements section below, and the individual files for details
+of the conditions under which they are made available.
+
+The source tree contains a number of directories, and is most easily
+built by loading the VNC workspace file (vnc.dsw) into Microsoft
+Visual Studio 6/7.  This will preserve the required dependencies
+between the sub-projects.
+
+There are three main executable projects:
+
+       vncviewer - The VNC Viewer for Win32.
+
+       winvnc - The VNC Server for Win32 (command-line operation
+                only).
+
+       vncconfig - The configuration applet and GUI front-end for VNC
+                   Server.
+
+These projects are designed to be built using Microsoft Visual C++
+6.0, and should also compile with Microsoft Visual Studio .NET
+(version 7).  Other compilers have not been tested but the code base
+is extremely portable.
+
+
+ACKNOWLEDGEMENTS
+================
+
+This distribution contains zlib software by Jean-loup Gailly and Mark Adler.
+This is:
+
+    Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler.
+
+       This software is provided 'as-is', without any express or implied
+       warranty.  In no event will the authors be held liable for any damages
+       arising from the use of this software.
+
+       Permission is granted to anyone to use this software for any purpose,
+       including commercial applications, and to alter it and redistribute it
+       freely, subject to the following restrictions:
+
+       1. The origin of this software must not be misrepresented; you must not
+          claim that you wrote the original software. If you use this software
+          in a product, an acknowledgment in the product documentation would be
+       appreciated but is not required.
+       2. Altered source versions must be plainly marked as such, and must not be
+       misrepresented as being the original software.
+       3. This notice may not be removed or altered from any source distribution.
+
+       Jean-loup Gailly        Mark Adler
+       jloup@gzip.org          madler@alumni.caltech.edu
+
+
+       The data format used by the zlib library is described by RFCs (Request for
+       Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+       (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+
+
+This distribution contains public domain DES software by Richard Outerbridge.
+This is:
+
+       Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+       (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+
+
+This distribution contains Java DES software by Dave Zimmerman
+<dzimm@widget.com> and Jef Poskanzer <jef@acme.com>.  This is:
+
+    Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+
+    Permission to use, copy, modify, and distribute this software and its
+    documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee
+    is hereby granted, provided that this copyright notice is kept intact.
+    
+    WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
+    SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
+    NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+    PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE
+    LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
+    MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+    
+    THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+    CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+    PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+    NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+    SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+    SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+    PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  WIDGET
+    WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF
+    FITNESS FOR HIGH RISK ACTIVITIES.
+
+    Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights
+    reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+    BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    Visit the ACME Labs Java page for up-to-date versions of this and other
+    fine Java utilities: http://www.acme.com/java/
diff --git a/win/README_BINARY.txt b/win/README_BINARY.txt
new file mode 100644 (file)
index 0000000..4c77e02
--- /dev/null
@@ -0,0 +1,126 @@
+
+TightVNC Binary Distribution for Windows platforms
+==================================================
+
+Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
+Copyright (C) 2000-2004 Constantin Kaplinsky.
+Copyright (C) 2004-2005 Peter Astrand, Cendio AB
+
+This software is distributed under the GNU General Public Licence as
+published by the Free Software Foundation.  See the file LICENCE.TXT
+for the conditions under which this software is made available.
+TightVNC also contains code from other sources.  See the
+Acknowledgements section below, and the individual files for details
+of the conditions under which they are made available.
+
+The installer package contains two VNC components:
+
+       VNC Viewer - this is the VNC Viewer, or client, program for
+                    Win32.
+                       [Win9x, WinME, NT4, Win2000, WinXP,
+                        Windows 2003 Server]
+
+       VNC Server - this is the VNC Server for Win32. It allows a
+                    Windows desktop to be accessed remotely using a
+                    VNC Viewer.
+                       [Win9x, WinME, NT4, Win2000, WinXP(*),
+                        Windows 2003 Server]
+
+(*)  May not work if the in-built Fast User Switching or Remote
+     Administration features are in use.
+
+Both components were built using Microsoft Visual C++ 6.0, and are
+designed to operate upon the Win32 platforms listed above.
+
+ACKNOWLEDGEMENTS
+================
+
+This distribution contains zlib software by Jean-loup Gailly and Mark Adler.
+This is:
+
+    Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler.
+
+       This software is provided 'as-is', without any express or implied
+       warranty.  In no event will the authors be held liable for any damages
+       arising from the use of this software.
+
+       Permission is granted to anyone to use this software for any purpose,
+       including commercial applications, and to alter it and redistribute it
+       freely, subject to the following restrictions:
+
+       1. The origin of this software must not be misrepresented; you must not
+          claim that you wrote the original software. If you use this software
+          in a product, an acknowledgment in the product documentation would be
+       appreciated but is not required.
+       2. Altered source versions must be plainly marked as such, and must not be
+       misrepresented as being the original software.
+       3. This notice may not be removed or altered from any source distribution.
+
+       Jean-loup Gailly        Mark Adler
+       jloup@gzip.org          madler@alumni.caltech.edu
+
+
+       The data format used by the zlib library is described by RFCs (Request for
+       Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+       (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+
+
+This distribution contains public domain DES software by Richard Outerbridge.
+This is:
+
+       Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+       (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+
+
+This distribution contains Java DES software by Dave Zimmerman
+<dzimm@widget.com> and Jef Poskanzer <jef@acme.com>.  This is:
+
+    Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+
+    Permission to use, copy, modify, and distribute this software and its
+    documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee
+    is hereby granted, provided that this copyright notice is kept intact.
+    
+    WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
+    SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
+    NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+    PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE
+    LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
+    MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+    
+    THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+    CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+    PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+    NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+    SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+    SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+    PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  WIDGET
+    WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF
+    FITNESS FOR HIGH RISK ACTIVITIES.
+
+    Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights
+    reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+    BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    Visit the ACME Labs Java page for up-to-date versions of this and other
+    fine Java utilities: http://www.acme.com/java/
diff --git a/win/logmessages/logmessages.dsp b/win/logmessages/logmessages.dsp
new file mode 100644 (file)
index 0000000..06ed8c4
--- /dev/null
@@ -0,0 +1,202 @@
+# Microsoft Developer Studio Project File - Name="logmessages" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=logmessages - Win32 Debug Unicode\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "logmessages.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "logmessages.mak" CFG="logmessages - Win32 Debug Unicode"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "logmessages - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "logmessages - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "logmessages - Win32 Debug Unicode" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "logmessages - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release"\r
+# PROP Intermediate_Dir "..\Release\logmessages"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /D "WIN32" /D "_MBCS" /YX /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
+# ADD LINK32 /nologo /dll /machine:I386 /out:"messages.mc"\r
+# Begin Custom Build\r
+InputPath=.\messages.mc\r
+SOURCE="$(InputPath)"\r
+\r
+BuildCmds= \\r
+       mc messages.mc \\r
+       rc -r -fo messages.res messages.rc \\r
+       link -dll -noentry -out:..\Release\logmessages.dll messages.res \\r
+       \r
+\r
+"messages.res" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"messages.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"messages.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"..\Release\logmessages.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "logmessages - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "../Debug"\r
+# PROP Intermediate_Dir "..\Debug\logmessages"\r
+# PROP Ignore_Export_Lib 1\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /out:"messages.mc" /pdbtype:sept\r
+# Begin Custom Build\r
+InputPath=.\messages.mc\r
+SOURCE="$(InputPath)"\r
+\r
+BuildCmds= \\r
+       mc messages.mc \\r
+       rc -r -fo messages.res messages.rc \\r
+       link -dll -noentry -out:..\Debug\logmessages.dll messages.res \\r
+       \r
+\r
+"messages.res" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"messages.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"messages.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"..\Debug\logmessages.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "logmessages - Win32 Debug Unicode"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "logmessages___Win32_Debug_Unicode"\r
+# PROP BASE Intermediate_Dir "logmessages___Win32_Debug_Unicode"\r
+# PROP BASE Ignore_Export_Lib 1\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug_Unicode"\r
+# PROP Intermediate_Dir "..\Debug_Unicode\logmessages"\r
+# PROP Ignore_Export_Lib 1\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_WINDOWS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /out:"messages.mc" /pdbtype:sept\r
+# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /out:"messages.mc" /pdbtype:sept\r
+# Begin Custom Build\r
+InputPath=.\messages.mc\r
+SOURCE="$(InputPath)"\r
+\r
+BuildCmds= \\r
+       mc messages.mc \\r
+       rc -r -fo messages.res messages.rc \\r
+       link -dll -noentry -out:..\Debug_Unicode\logmessages.dll messages.res \\r
+       \r
+\r
+"messages.res" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"messages.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"messages.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+\r
+"..\Debug_Unicode\logmessages.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+   $(BuildCmds)\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "logmessages - Win32 Release"\r
+# Name "logmessages - Win32 Debug"\r
+# Name "logmessages - Win32 Debug Unicode"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=.\messages.mc\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/win/logmessages/messages.h b/win/logmessages/messages.h
new file mode 100644 (file)
index 0000000..bfb8c56
--- /dev/null
@@ -0,0 +1,47 @@
+//
+//  Values are 32 bit values layed out as follows:
+//
+//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+//  +---+-+-+-----------------------+-------------------------------+
+//  |Sev|C|R|     Facility          |               Code            |
+//  +---+-+-+-----------------------+-------------------------------+
+//
+//  where
+//
+//      Sev - is the severity code
+//
+//          00 - Success
+//          01 - Informational
+//          10 - Warning
+//          11 - Error
+//
+//      C - is the Customer code flag
+//
+//      R - is a reserved bit
+//
+//      Facility - is the facility code
+//
+//      Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+//
+// Define the severity codes
+//
+
+
+//
+// MessageId: VNC4LogMessage
+//
+// MessageText:
+//
+//  %1: %2
+//  
+//  
+//
+#define VNC4LogMessage                   0x00000001L
+
diff --git a/win/logmessages/messages.mc b/win/logmessages/messages.mc
new file mode 100644 (file)
index 0000000..0bc8329
--- /dev/null
@@ -0,0 +1,7 @@
+MessageId=0x1
+Severity=Success
+SymbolicName=VNC4LogMessage
+Language=English
+%1: %2
+
+
diff --git a/win/logmessages/messages.rc b/win/logmessages/messages.rc
new file mode 100644 (file)
index 0000000..0885a89
--- /dev/null
@@ -0,0 +1,2 @@
+LANGUAGE 0x9,0x1
+1 11 MSG00001.bin
diff --git a/win/rfb_win32/AboutDialog.cxx b/win/rfb_win32/AboutDialog.cxx
new file mode 100644 (file)
index 0000000..030be1b
--- /dev/null
@@ -0,0 +1,49 @@
+/* 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 <rfb_win32/AboutDialog.h>
+#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("AboutDialog");
+
+AboutDialog AboutDialog::instance;
+
+
+AboutDialog::AboutDialog() : Dialog(GetModuleHandle(0)) {
+}
+
+bool AboutDialog::showDialog() {
+  return Dialog::showDialog(MAKEINTRESOURCE(DialogId));
+}
+
+void AboutDialog::initDialog() {
+  // Set the build time field
+  SetWindowText(GetDlgItem(handle, BuildTime), TStr(buildTime));
+
+  // Get our executable's version info
+  FileVersionInfo verInfo;
+
+  SetWindowText(GetDlgItem(handle, Version), verInfo.getVerString(_T("ProductVersion")));
+  SetWindowText(GetDlgItem(handle, Copyright), verInfo.getVerString(_T("LegalCopyright")));
+  SetWindowText(GetDlgItem(handle, Description), verInfo.getVerString(_T("ProductName")));
+}
diff --git a/win/rfb_win32/AboutDialog.h b/win/rfb_win32/AboutDialog.h
new file mode 100644 (file)
index 0000000..0dd9d49
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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.
+ */
+
+// -=- AboutDialog.h
+
+#ifndef __RFB_WIN32_ABOUT_DIALOG_H__
+#define __RFB_WIN32_ABOUT_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb/util.h>
+
+extern const char* buildTime;
+
+namespace rfb {
+
+  namespace win32 {
+
+    class AboutDialog : Dialog {
+    public:
+      AboutDialog();
+      virtual bool showDialog();
+      virtual void initDialog();
+
+      static AboutDialog instance;
+
+      typedef WORD LabelId;
+      static const LabelId DialogId;    // Resource ID of the About dialog
+      static const LabelId BuildTime;   // Resource ID of the BuildTime label in the dialog
+      static const LabelId Version;     // etc...
+      static const LabelId Copyright;
+      static const LabelId Description;
+    protected:
+      WORD dialogId;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/rfb_win32/BitmapInfo.h b/win/rfb_win32/BitmapInfo.h
new file mode 100644 (file)
index 0000000..6a6f0d2
--- /dev/null
@@ -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.
+ */
+
+#ifndef __RFB_WIN32_BITMAP_INFO_H__
+#define __RFB_WIN32_BITMAP_INFO_H__
+
+#include <windows.h>
+#include <rdr/types.h>
+
+namespace rfb {
+  namespace win32 {
+
+    struct BitmapInfo {
+      BITMAPINFOHEADER bmiHeader;
+      union {
+        struct {
+          DWORD red;
+          DWORD green;
+          DWORD blue;
+        } mask;
+        RGBQUAD color[256];
+      };
+    };
+
+    inline void initMaxAndShift(DWORD mask, int* max, int* shift) {
+      for ((*shift) = 0; (mask & 1) == 0; (*shift)++) mask >>= 1;
+        (*max) = (rdr::U16)mask;
+    }
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/CKeyboard.cxx b/win/rfb_win32/CKeyboard.cxx
new file mode 100644 (file)
index 0000000..28aceab
--- /dev/null
@@ -0,0 +1,258 @@
+/* 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 <map>
+
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define XK_CURRENCY
+#include <rfb/keysymdef.h>
+
+#include <rfb_win32/CKeyboard.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/OSVersion.h>
+#include "keymap.h"
+
+using namespace rfb;
+
+static LogWriter vlog("CKeyboard");
+
+
+// Client-side RFB keyboard event sythesis
+
+class CKeymapper {
+
+public:
+  CKeymapper()
+  {
+    for (int i = 0; i < sizeof(keymap) / sizeof(keymap_t); i++) {
+      int extendedVkey = keymap[i].vk + (keymap[i].extended ? 256 : 0);
+      if (keysymMap.find(extendedVkey) == keysymMap.end()) {
+        keysymMap[extendedVkey] = keymap[i].keysym;
+      }
+    }
+  }
+
+  // lookup() tries to find a match for vkey with the extended flag.  We check
+  // first for an exact match including the extended flag, then try without the
+  // extended flag.
+  rdr::U32 lookup(int extendedVkey) {
+    if (keysymMap.find(extendedVkey) != keysymMap.end())
+      return keysymMap[extendedVkey];
+    if (keysymMap.find(extendedVkey ^ 256) != keysymMap.end())
+      return keysymMap[extendedVkey ^ 256];
+    return 0;
+  }
+
+private:
+  std::map<int,rdr::U32> keysymMap;
+} ckeymapper;
+
+
+class ModifierKeyReleaser {
+public:
+  ModifierKeyReleaser(InputHandler* writer_, int vkCode, bool extended)
+    : writer(writer_), extendedVkey(vkCode + (extended ? 256 : 0)),
+      keysym(0)
+  {}
+  void release(std::map<int,rdr::U32>* downKeysym) {
+    if (downKeysym->find(extendedVkey) != downKeysym->end()) {
+      keysym = (*downKeysym)[extendedVkey];
+      vlog.debug("fake release extendedVkey 0x%x, keysym 0x%x",
+                 extendedVkey, keysym);
+      writer->keyEvent(keysym, false);
+    }
+  }
+  ~ModifierKeyReleaser() {
+    if (keysym) {
+      vlog.debug("fake press extendedVkey 0x%x, keysym 0x%x",
+                 extendedVkey, keysym);
+      writer->keyEvent(keysym, true);
+    }
+  }
+  InputHandler* writer;
+  int extendedVkey;
+  rdr::U32 keysym;
+};
+
+// IS_PRINTABLE_LATIN1 tests if a character is either a printable latin1
+// character, or 128, which is the Euro symbol on Windows.
+#define IS_PRINTABLE_LATIN1(c) (((c) >= 32 && (c) <= 126) || (c) == 128 || \
+                                ((c) >= 160 && (c) <= 255))
+
+void win32::CKeyboard::keyEvent(InputHandler* writer, rdr::U8 vkey,
+                                rdr::U32 flags, bool down)
+{
+  bool extended = (flags & 0x1000000);
+  int extendedVkey = vkey + (extended ? 256 : 0);
+
+  // If it's a release, just release whichever keysym corresponded to the same
+  // key being pressed, regardless of how it would be interpreted in the
+  // current keyboard state.
+  if (!down) {
+    releaseKey(writer, extendedVkey);
+    return;
+  }
+
+  // We should always pass every down event to ToAscii() otherwise it can get
+  // out of sync.
+
+  // XXX should we pass CapsLock, ScrollLock or NumLock to ToAscii - they
+  // actually alter the lock state on the keyboard?
+
+  BYTE keystate[256];
+  GetKeyboardState(keystate);
+  rdr::U8 chars[2];
+
+  int nchars = ToAscii(vkey, 0, keystate, (WORD*)&chars, 0);
+
+  // See if it's in the Windows VK code -> X keysym map.  We do this before
+  // looking at the result of ToAscii so that e.g. we recognise that it's
+  // XK_KP_Add rather than '+'.
+
+  rdr::U32 keysym = ckeymapper.lookup(extendedVkey);
+  if (keysym) {
+    vlog.debug("mapped key: extendedVkey 0x%x", extendedVkey);
+    pressKey(writer, extendedVkey, keysym);
+    return;
+  }
+
+  if (nchars < 0) {
+    // Dead key - the next call to ToAscii() will give us either the accented
+    // character or two characters.
+    vlog.debug("ToAscii dead key (1): extendedVkey 0x%x", extendedVkey);
+    return;
+  }
+
+  if (nchars > 0 && IS_PRINTABLE_LATIN1(chars[0])) {
+    // Got a printable latin1 character.  We must release Control and Alt
+    // (AltGr) if they were both pressed, so that the latin1 character is seen
+    // without them by the VNC server.
+    ModifierKeyReleaser lctrl(writer, VK_CONTROL, 0);
+    ModifierKeyReleaser rctrl(writer, VK_CONTROL, 1);
+    ModifierKeyReleaser lalt(writer, VK_MENU, 0);
+    ModifierKeyReleaser ralt(writer, VK_MENU, 1);
+
+    if ((keystate[VK_CONTROL] & 0x80) && (keystate[VK_MENU] & 0x80)) {
+      lctrl.release(&downKeysym);
+      rctrl.release(&downKeysym);
+      lalt.release(&downKeysym);
+      ralt.release(&downKeysym);
+    }
+
+    for (int i = 0; i < nchars; i++) {
+      vlog.debug("ToAscii key (1): extendedVkey 0x%x", extendedVkey);
+      if (chars[i] == 128) { // special hack for euro!
+        pressKey(writer, extendedVkey, XK_EuroSign);
+      } else {
+        pressKey(writer, extendedVkey, chars[i]);
+      }
+    }
+    return;
+  }
+
+  // Either no chars were generated, or something outside the printable
+  // character range.  Try ToAscii() without the Control and Alt keys down to
+  // see if that yields an ordinary character.
+
+  keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0;
+  keystate[VK_MENU] = keystate[VK_LMENU] = keystate[VK_RMENU] = 0;
+
+  nchars = ToAscii(vkey, 0, keystate, (WORD*)&chars, 0);
+
+  if (nchars < 0) {
+    // So it would be a dead key if neither control nor alt were pressed.
+    // However, we know that at least one of control and alt must be pressed.
+    // We can't leave it at this stage otherwise the next call to ToAscii()
+    // with a valid character will get wrongly interpreted in the context of
+    // this bogus dead key.  Working on the assumption that a dead key followed
+    // by space usually returns the dead character itself, try calling ToAscii
+    // with VK_SPACE.
+    vlog.debug("ToAscii dead key (2): extendedVkey 0x%x", extendedVkey);
+    nchars = ToAscii(VK_SPACE, 0, keystate, (WORD*)&chars, 0);
+    if (nchars < 0) {
+      vlog.debug("ToAscii dead key (3): extendedVkey 0x%x - giving up!",
+                 extendedVkey);
+      return;
+    }
+  }
+
+  if (nchars > 0 && IS_PRINTABLE_LATIN1(chars[0])) {
+    for (int i = 0; i < nchars; i++) {
+      vlog.debug("ToAscii key (2) (no ctrl/alt): extendedVkey 0x%x",
+                 extendedVkey);
+      if (chars[i] == 128) { // special hack for euro!
+        pressKey(writer, extendedVkey, XK_EuroSign);
+      } else {
+        pressKey(writer, extendedVkey, chars[i]);
+      }
+    }
+    return;
+  }
+
+  vlog.debug("no chars regardless of control and alt: extendedVkey 0x%x",
+             extendedVkey);
+}
+
+// releaseAllKeys() - write key release events to the server for all keys
+// that are currently regarded as being down.
+void win32::CKeyboard::releaseAllKeys(InputHandler* writer) {
+  std::map<int,rdr::U32>::iterator i, next_i;
+  for (i=downKeysym.begin(); i!=downKeysym.end(); i=next_i) {
+    next_i = i; next_i++;
+    writer->keyEvent((*i).second, false);
+    downKeysym.erase(i);
+  }
+}
+
+// releaseKey() - write a key up event to the server, but only if we've
+// actually sent a key down event for the given key.  The key up event always
+// contains the same keysym we used in the key down event, regardless of what
+// it would look up as using the current keyboard state.
+void win32::CKeyboard::releaseKey(InputHandler* writer, int extendedVkey)
+{
+  if (downKeysym.find(extendedVkey) != downKeysym.end()) {
+    vlog.debug("release extendedVkey 0x%x, keysym 0x%x",
+               extendedVkey, downKeysym[extendedVkey]);
+    writer->keyEvent(downKeysym[extendedVkey], false);
+    downKeysym.erase(extendedVkey);
+  }
+}
+
+// pressKey() - write a key down event to the server, and record which keysym
+// was sent as corresponding to the given extendedVkey.  The only tricky bit is
+// that if we are trying to press an extendedVkey which is already marked as
+// down but with a different keysym, then we need to release the old keysym
+// first.  This can happen in two cases: (a) when a single key press results in
+// more than one character, and (b) when shift is released while another key is
+// autorepeating.
+void win32::CKeyboard::pressKey(InputHandler* writer, int extendedVkey,
+                                rdr::U32 keysym)
+{
+  if (downKeysym.find(extendedVkey) != downKeysym.end()) {
+    if (downKeysym[extendedVkey] != keysym) {
+      vlog.debug("release extendedVkey 0x%x, keysym 0x%x",
+                 extendedVkey, downKeysym[extendedVkey]);
+      writer->keyEvent(downKeysym[extendedVkey], false);
+    }
+  }
+  vlog.debug("press   extendedVkey 0x%x, keysym 0x%x",
+             extendedVkey, keysym);
+  writer->keyEvent(keysym, true);
+  downKeysym[extendedVkey] = keysym;
+}
diff --git a/win/rfb_win32/CKeyboard.h b/win/rfb_win32/CKeyboard.h
new file mode 100644 (file)
index 0000000..666ebce
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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.
+ */
+
+// -=- CKeyboard.h
+//
+// Client-side keyboard handling for Win32
+
+#ifndef __RFB_WIN32_CKEYBOARD_H__
+#define __RFB_WIN32_CKEYBOARD_H__
+
+#include <rfb/InputHandler.h>
+#include <map>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CKeyboard {
+    public:
+      void keyEvent(InputHandler* writer, rdr::U8 vkey, rdr::U32 flags,
+                    bool down);
+      void releaseAllKeys(InputHandler* writer);
+      const std::map<int,rdr::U32>& pressedKeys() const {return downKeysym;};
+      bool keyPressed(int k) const {return downKeysym.find(k)!=downKeysym.end();}
+    private:
+      void win32::CKeyboard::releaseKey(InputHandler* writer, int extendedVkey);
+      void win32::CKeyboard::pressKey(InputHandler* writer, int extendedVkey,
+                                      rdr::U32 keysym);
+      std::map<int,rdr::U32> downKeysym;
+    };
+
+  }; // win32
+
+}; // rfb
+
+#endif // __RFB_WIN32_CKEYBOARD_H__
diff --git a/win/rfb_win32/CPointer.cxx b/win/rfb_win32/CPointer.cxx
new file mode 100644 (file)
index 0000000..3d0d934
--- /dev/null
@@ -0,0 +1,186 @@
+/* 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 <rfb/LogWriter.h>
+#include <rfb_win32/CPointer.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CPointer");
+
+
+CPointer::CPointer() : currButtonMask(0), intervalQueued(false), threeEmulating(false) {
+}
+
+CPointer::~CPointer() {
+  intervalTimer.stop();
+  threeTimer.stop();
+}
+
+
+void CPointer::pointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
+  //
+  // - Duplicate Event Filtering
+  //
+
+  bool maskChanged = buttonMask != currButtonMask;
+  bool posChanged = !pos.equals(currPos);
+  if (!(posChanged || maskChanged))
+    return;
+
+  // Pass on the event to the event-interval handler
+  threePointerEvent(writer, pos, buttonMask);
+
+  // Save the position and mask
+  currPos = pos;
+  currButtonMask = buttonMask;
+}
+
+
+inline abs(int x) {return x>0 ? x : 0;}
+
+int emulate3Mask(int buttonMask) {
+  // - Release left & right and press middle
+  vlog.debug("emulate3: active");
+  buttonMask &= ~5;
+  buttonMask |= 2;
+  return buttonMask;
+}
+
+void CPointer::threePointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
+  //
+  // - 3-Button Mouse Emulation
+  //
+
+  if (emulate3) {
+
+    bool leftChanged = (buttonMask & 1) != (currButtonMask & 1);
+    bool rightChanged = (buttonMask & 4) != (currButtonMask & 4);
+
+    if (leftChanged || rightChanged) {
+      // - One of left or right have changed
+
+      if ((buttonMask & 5) == 1 || (buttonMask & 5) == 4) {
+        // - One is up, one is down.  Start a timer, so that if it
+        //   expires then we know we should actually send this event
+        vlog.debug("emulate3: start timer");
+        threeTimer.start(100);
+        threePos = pos;
+        threeMask = buttonMask;
+        return;
+
+      } else if (threeTimer.isActive()) {
+        // - Both are up or both are down, and we were timing for an emulation event
+        //   Stop the timer and flush the stored event
+        vlog.debug("emulate3: stop timer (state)");
+        threeTimer.stop();
+        if (threeEmulating == ((buttonMask & 5) == 5))
+          intervalPointerEvent(writer, threePos, threeMask);
+        else
+          threeEmulating = ((buttonMask & 5) == 5);
+      }
+
+    } else {
+    
+      if (threeTimer.isActive()) {
+        // - We are timing for an emulation event
+
+        if (abs(threePos.x - pos.x) <= 4 || abs(threePos.y - pos.y) <= 4) {
+          //   If the mouse has moved too far since the button-change event then flush
+          vlog.debug("emulate3: stop timer (moved)");
+          threeTimer.stop();
+          intervalPointerEvent(writer, threePos, threeMask);
+
+        } else {
+          //   Otherwise, we ignore the new event
+          return;
+        }
+      }
+
+    }
+
+    // - If neither left nor right are down, stop emulating
+    if ((buttonMask & 5) == 0)
+      threeEmulating = false;
+
+    // - If emulating, release left & right and press middle
+    if (threeEmulating)
+      buttonMask = emulate3Mask(buttonMask);
+
+  }
+
+  // - Let the event pass through to the next stage of processing
+  intervalPointerEvent(writer, pos, buttonMask);
+}
+
+void CPointer::intervalPointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
+  //
+  // - Pointer Event Interval
+  //
+  vlog.write(101, "ptrEvent: %d,%d (%lx)", pos.x, pos.y, buttonMask);
+
+  // Send the event immediately if we haven't sent one for a while
+  bool sendNow = !intervalTimer.isActive();
+
+  if (intervalMask != buttonMask) {
+    // If the buttons have changed then flush queued events and send now
+    sendNow = true;
+    if (intervalQueued)
+      writer->pointerEvent(intervalPos, intervalMask);
+    intervalQueued = false;
+  }
+
+  if (!sendNow) {
+    // If we're not sending now then just queue the event
+    intervalQueued = true;
+    intervalPos = pos;
+    intervalMask = buttonMask;
+  } else {
+    // Start the interval timer if required, and send the event
+    intervalQueued = false;
+    intervalMask = buttonMask;
+    if (pointerEventInterval)
+      intervalTimer.start(pointerEventInterval);
+    writer->pointerEvent(pos, buttonMask);
+  }
+}
+
+void CPointer::handleTimer(InputHandler* writer, int timerId) {
+  if (timerId == intervalTimer.getId()) {
+    // Pointer interval has expired - send any queued events
+    if (intervalQueued) {
+      writer->pointerEvent(intervalPos, intervalMask);
+      intervalQueued = false;
+    } else {
+      intervalTimer.stop();
+    }
+
+  } else if (timerId = threeTimer.getId()) {
+    // 3-Button emulation timer has expired - send what we've got
+    vlog.debug("emulate3: timeout");
+    threeTimer.stop();
+
+    // If emulating, release left & right and press middle
+    if (threeEmulating)
+      threeMask = emulate3Mask(threeMask);
+
+    intervalPointerEvent(writer, threePos, threeMask);
+  }
+}
diff --git a/win/rfb_win32/CPointer.h b/win/rfb_win32/CPointer.h
new file mode 100644 (file)
index 0000000..b591601
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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.
+ */
+
+// -=- CPointer.h
+//
+// Client-side pointer event handling for Win32
+
+#ifndef __RFB_WIN32_CPOINTER_H__
+#define __RFB_WIN32_CPOINTER_H__
+
+#include <rdr/Exception.h>
+#include <rfb/Configuration.h>
+#include <rfb/InputHandler.h>
+#include <rfb/Rect.h>
+#include <rfb_win32/IntervalTimer.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CPointer {
+    public:
+      CPointer();
+      ~CPointer();
+
+      void pointerEvent(InputHandler* writer, const Point& pos, int buttonMask);
+      void handleTimer(InputHandler* writer, int timerId);
+
+      void setHWND(HWND w) {intervalTimer.setHWND(w); threeTimer.setHWND(w);}
+      void setIntervalTimerId(int id) {intervalTimer.setId(id);}
+      void set3ButtonTimerId(int id) {threeTimer.setId(id);}
+
+      void enableEmulate3(bool enable) {emulate3 = enable;}
+      void enableInterval(int millis) {pointerEventInterval = millis;}
+    private:
+      Point currPos;
+      int currButtonMask;
+
+      bool emulate3;
+      int pointerEventInterval;
+
+      void intervalPointerEvent(InputHandler* writer, const Point& pos, int buttonMask);
+      IntervalTimer intervalTimer;
+      bool intervalQueued;
+      Point intervalPos;
+      int intervalMask;
+
+      void threePointerEvent(InputHandler* writer, const Point& pos, int buttonMask);
+      IntervalTimer threeTimer;
+      Point threePos;
+      int threeMask;
+      bool threeEmulating;
+    };
+
+  }; // win32
+
+}; // rfb
+
+#endif // __RFB_WIN32_CPOINTER_H__
diff --git a/win/rfb_win32/CleanDesktop.cxx b/win/rfb_win32/CleanDesktop.cxx
new file mode 100644 (file)
index 0000000..39cca11
--- /dev/null
@@ -0,0 +1,321 @@
+/* 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.
+ */
+
+// -=- CleanDesktop.cxx
+
+#include <windows.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <rfb_win32/CleanDesktop.h>
+#include <rfb_win32/CurrentUser.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb/LogWriter.h>
+#include <rdr/Exception.h>
+#include <set>
+
+#ifdef SPI_GETUIEFFECTS
+#define RFB_HAVE_SPI_UIEFFECTS
+#else
+#pragma message("  NOTE: Not building Get/Set UI Effects support.")
+#endif
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("CleanDesktop");
+
+
+struct ActiveDesktop {
+  ActiveDesktop() : handle(0) {
+    // - Contact Active Desktop
+    HRESULT result = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
+                                      IID_IActiveDesktop, (PVOID*)&handle);
+    if (result != S_OK)
+      throw rdr::SystemException("failed to contact Active Desktop", result);
+  }
+  ~ActiveDesktop() {
+    if (handle)
+      handle->Release();
+  }
+
+  // enableItem
+  //   enables or disables the Nth Active Desktop item
+  bool enableItem(int i, bool enable_) {
+    COMPONENT item;
+    memset(&item, 0, sizeof(item));
+    item.dwSize = sizeof(item);
+
+    HRESULT hr = handle->GetDesktopItem(i, &item, 0);
+    if (hr != S_OK) {
+      vlog.error("unable to GetDesktopItem %d: %ld", i, hr);
+      return false;
+    }
+    item.fChecked = enable_;
+    vlog.debug("%sbling %d: \"%s\"", enable_ ? "ena" : "disa", i, (const char*)CStr(item.wszFriendlyName));
+
+    hr = handle->ModifyDesktopItem(&item, COMP_ELEM_CHECKED);
+    return hr == S_OK;
+  }
+  
+  // enable
+  //   Attempts to enable/disable Active Desktop, returns true if the setting changed,
+  //   false otherwise.
+  //   If Active Desktop *can* be enabled/disabled then that is done.
+  //   If Active Desktop is always on (XP/2K3) then instead the individual items are
+  //   disabled, and true is returned to indicate that they need to be restored later.
+  bool enable(bool enable_) {
+    bool modifyComponents = false;
+
+    vlog.debug("ActiveDesktop::enable");
+
+    // - Firstly, try to disable Active Desktop entirely
+    HRESULT hr;
+    COMPONENTSOPT adOptions;
+    memset(&adOptions, 0, sizeof(adOptions));
+    adOptions.dwSize = sizeof(adOptions);
+
+    // Attempt to actually disable/enable AD
+    hr = handle->GetDesktopItemOptions(&adOptions, 0);
+    if (hr == S_OK) {
+      // If Active Desktop is already in the desired state then return false (no change)
+      // NB: If AD is enabled AND restoreItems is set then we regard it as disabled...
+      if (((adOptions.fActiveDesktop==0) && restoreItems.empty()) == (enable_==false))
+        return false;
+      adOptions.fActiveDesktop = enable_;
+      hr = handle->SetDesktopItemOptions(&adOptions, 0);
+    }
+    // Apply the change, then test whether it actually took effect
+    if (hr == S_OK)
+      hr = handle->ApplyChanges(AD_APPLY_REFRESH);
+    if (hr == S_OK)
+      hr = handle->GetDesktopItemOptions(&adOptions, 0);
+    if (hr == S_OK)
+      modifyComponents = (adOptions.fActiveDesktop==0) != (enable_==false);
+    if (hr != S_OK) {
+      vlog.error("failed to get/set Active Desktop options: %ld", hr);
+      return false;
+    }
+
+    if (enable_) {
+      // - We are re-enabling Active Desktop.  If there are components in restoreItems
+      //   then restore them!
+      std::set<int>::const_iterator i;
+      for (i=restoreItems.begin(); i!=restoreItems.end(); i++) {
+        enableItem(*i, true);
+      }
+      restoreItems.clear();
+    } else if (modifyComponents) {
+      // - Disable all currently enabled items, and add the disabled ones to restoreItems
+      int itemCount = 0;
+      hr = handle->GetDesktopItemCount(&itemCount, 0);
+      if (hr != S_OK) {
+        vlog.error("failed to get desktop item count: %ld", hr);
+        return false;
+      }
+      for (unsigned int i=0; i<itemCount; i++) {
+        if (enableItem(i, false))
+          restoreItems.insert(i);
+      }
+    }
+
+    // - Apply whatever changes we have made, but DON'T save them!
+    hr = handle->ApplyChanges(AD_APPLY_REFRESH);
+    return hr == S_OK;
+  }
+  IActiveDesktop* handle;
+  std::set<int> restoreItems;
+};
+
+
+DWORD SysParamsInfo(UINT action, UINT param, PVOID ptr, UINT ini) {
+  DWORD r = ERROR_SUCCESS;
+  if (!SystemParametersInfo(action, param, ptr, ini)) {
+    r = GetLastError();
+    vlog.info("SPI error: %d", r);
+  }
+  return r;
+}
+
+
+CleanDesktop::CleanDesktop() : restoreActiveDesktop(false), restoreWallpaper(false),
+                               restorePattern(false), restoreEffects(false) {
+  CoInitialize(0);
+}
+
+CleanDesktop::~CleanDesktop() {
+  enableEffects();
+  enablePattern();
+  enableWallpaper();
+  CoUninitialize();
+}
+
+void CleanDesktop::disableWallpaper() {
+  try {
+    ImpersonateCurrentUser icu;
+
+    vlog.debug("disable desktop wallpaper/Active Desktop");
+
+    // -=- First attempt to remove the wallpaper using Active Desktop
+    try {
+      ActiveDesktop ad;
+      if (ad.enable(false))
+        restoreActiveDesktop = true;
+    } catch (rdr::Exception& e) {
+      vlog.error(e.str());
+    }
+
+    // -=- Switch of normal wallpaper and notify apps
+    SysParamsInfo(SPI_SETDESKWALLPAPER, 0, "", SPIF_SENDCHANGE);
+    restoreWallpaper = true;
+
+  } catch (rdr::Exception& e) {
+    vlog.info(e.str());
+  }
+}
+
+void CleanDesktop::enableWallpaper() {
+  try {
+    ImpersonateCurrentUser icu;
+
+    if (restoreActiveDesktop) {
+      vlog.debug("restore Active Desktop");
+
+      // -=- First attempt to re-enable Active Desktop
+      try {
+        ActiveDesktop ad;
+        ad.enable(true);
+        restoreActiveDesktop = false;
+      } catch (rdr::Exception& e) {
+        vlog.error(e.str());
+      }
+    }
+
+    if (restoreWallpaper) {
+      vlog.debug("restore desktop wallpaper");
+
+      // -=- Then restore the standard wallpaper if required
+           SysParamsInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
+      restoreWallpaper = false;
+    }
+
+  } catch (rdr::Exception& e) {
+    vlog.info(e.str());
+  }
+}
+
+
+void CleanDesktop::disablePattern() {
+  try {
+    ImpersonateCurrentUser icu;
+
+    vlog.debug("disable desktop pattern");
+    SysParamsInfo(SPI_SETDESKPATTERN, 0, "", SPIF_SENDCHANGE);
+    restorePattern = true;
+
+  } catch (rdr::Exception& e) {
+    vlog.info(e.str());
+  }
+}
+
+void CleanDesktop::enablePattern() {
+  try {
+    if (restorePattern) {
+      ImpersonateCurrentUser icu;
+
+      vlog.debug("restoring pattern...");
+
+      TCharArray pattern;
+      if (osVersion.isPlatformWindows) {
+        RegKey cfgKey;
+        cfgKey.openKey(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"));
+        pattern.buf = cfgKey.getString(_T("Pattern"));
+      }
+      SysParamsInfo(SPI_SETDESKPATTERN, 0, pattern.buf, SPIF_SENDCHANGE);
+      restorePattern = false;
+    }
+
+  } catch (rdr::Exception& e) {
+    vlog.info(e.str());
+  }
+}
+
+
+void CleanDesktop::disableEffects() {
+  try {
+    ImpersonateCurrentUser icu;
+
+    vlog.debug("disable desktop effects");
+
+    SysParamsInfo(SPI_SETFONTSMOOTHING, FALSE, 0, SPIF_SENDCHANGE);
+#ifdef RFB_HAVE_SPI_UIEFFECTS
+    if (SysParamsInfo(SPI_GETUIEFFECTS, 0, &uiEffects, 0) == ERROR_CALL_NOT_IMPLEMENTED) {
+      SysParamsInfo(SPI_GETCOMBOBOXANIMATION, 0, &comboBoxAnim, 0);
+      SysParamsInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradientCaptions, 0);
+      SysParamsInfo(SPI_GETHOTTRACKING, 0, &hotTracking, 0);
+      SysParamsInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &listBoxSmoothScroll, 0);
+      SysParamsInfo(SPI_GETMENUANIMATION, 0, &menuAnim, 0);
+      SysParamsInfo(SPI_SETCOMBOBOXANIMATION, 0, FALSE, SPIF_SENDCHANGE);
+      SysParamsInfo(SPI_SETGRADIENTCAPTIONS, 0, FALSE, SPIF_SENDCHANGE);
+      SysParamsInfo(SPI_SETHOTTRACKING, 0, FALSE, SPIF_SENDCHANGE);
+      SysParamsInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, FALSE, SPIF_SENDCHANGE);
+      SysParamsInfo(SPI_SETMENUANIMATION, 0, FALSE, SPIF_SENDCHANGE);
+    } else {
+      SysParamsInfo(SPI_SETUIEFFECTS, 0, FALSE, SPIF_SENDCHANGE);
+
+      // We *always* restore UI effects overall, since there is no Windows GUI to do it
+      uiEffects = TRUE;
+    }
+#else
+    vlog.debug("  not supported");
+#endif
+    restoreEffects = true;
+
+  } catch (rdr::Exception& e) {
+    vlog.info(e.str());
+  }
+}
+
+void CleanDesktop::enableEffects() {
+  try {
+    if (restoreEffects) {
+      ImpersonateCurrentUser icu;
+
+      vlog.debug("restore desktop effects");
+
+      RegKey desktopCfg;
+      desktopCfg.openKey(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"));
+      SysParamsInfo(SPI_SETFONTSMOOTHING, desktopCfg.getInt(_T("FontSmoothing"), 0) != 0, 0, SPIF_SENDCHANGE);
+#ifdef RFB_HAVE_SPI_UIEFFECTS
+      if (SysParamsInfo(SPI_SETUIEFFECTS, 0, (void*)uiEffects, SPIF_SENDCHANGE) == ERROR_CALL_NOT_IMPLEMENTED) {
+        SysParamsInfo(SPI_SETCOMBOBOXANIMATION, 0, (void*)comboBoxAnim, SPIF_SENDCHANGE);
+        SysParamsInfo(SPI_SETGRADIENTCAPTIONS, 0, (void*)gradientCaptions, SPIF_SENDCHANGE);
+        SysParamsInfo(SPI_SETHOTTRACKING, 0, (void*)hotTracking, SPIF_SENDCHANGE);
+        SysParamsInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, (void*)listBoxSmoothScroll, SPIF_SENDCHANGE);
+        SysParamsInfo(SPI_SETMENUANIMATION, 0, (void*)menuAnim, SPIF_SENDCHANGE);
+      }
+      restoreEffects = false;
+#else
+      vlog.info("  not supported");
+#endif
+    }
+
+  } catch (rdr::Exception& e) {
+    vlog.info(e.str());
+  }
+}
diff --git a/win/rfb_win32/CleanDesktop.h b/win/rfb_win32/CleanDesktop.h
new file mode 100644 (file)
index 0000000..22e246f
--- /dev/null
@@ -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.
+ */
+
+// -=- CleanDesktop.h
+
+#ifndef __RFB_WIN32_CLEANDESKTOP_H__
+#define __RFB_WIN32_CLEANDESKTOP_H__
+
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CleanDesktop {
+    public:
+      CleanDesktop();
+      ~CleanDesktop();
+
+      void disableWallpaper();
+      void enableWallpaper();
+
+      void disablePattern();
+      void enablePattern();
+
+      void disableEffects();
+      void enableEffects();
+
+    private:
+      bool restoreActiveDesktop;
+      bool restoreWallpaper;
+      bool restorePattern;
+      bool restoreEffects;
+      BOOL uiEffects;
+      BOOL comboBoxAnim, gradientCaptions, hotTracking, listBoxSmoothScroll, menuAnim;
+    };
+
+  }; // win32
+
+}; // rfb
+
+#endif // __RFB_WIN32_CLEANDESKTOP_H__
diff --git a/win/rfb_win32/Clipboard.cxx b/win/rfb_win32/Clipboard.cxx
new file mode 100644 (file)
index 0000000..a4c43f0
--- /dev/null
@@ -0,0 +1,200 @@
+/* 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.
+ */
+
+// -=- Clipboard.cxx
+
+#include <rfb_win32/Clipboard.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb/util.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Clipboard");
+
+
+//
+// -=- CR/LF handlers
+//
+
+char*
+dos2unix(const char* text) {
+  int len = strlen(text)+1;
+  char* unix = new char[strlen(text)+1];
+  int i, j=0;
+  for (i=0; i<len; i++) {
+    if (text[i] != '\x0d')
+      unix[j++] = text[i];
+  }
+  return unix;
+}
+
+char*
+unix2dos(const char* text) {
+  int len = strlen(text)+1;
+  char* dos = new char[strlen(text)*2+1];
+  int i, j=0;
+  for (i=0; i<len; i++) {
+    if (text[i] == '\x0a')
+      dos[j++] = '\x0d';
+    dos[j++] = text[i];
+  }
+  return dos;
+}
+
+
+//
+// -=- ISO-8859-1 (Latin 1) filter (in-place)
+//
+
+void
+removeNonISOLatin1Chars(char* text) {
+  int len = strlen(text);
+  int i=0, j=0;
+  for (; i<len; i++) {
+    if (((text[i] >= 1) && (text[i] <= 127)) ||
+        ((text[i] >= 160) && (text[i] <= 255)))
+      text[j++] = text[i];
+  }
+  text[j] = 0;
+}
+
+//
+// -=- Clipboard object
+//
+
+Clipboard::Clipboard()
+  : MsgWindow(_T("Clipboard")), notifier(0), next_window(0) {
+  next_window = SetClipboardViewer(getHandle());
+  vlog.debug("registered clipboard handler");
+}
+
+Clipboard::~Clipboard() {
+  vlog.debug("removing %x from chain (next is %x)", getHandle(), next_window);
+  ChangeClipboardChain(getHandle(), next_window);
+}
+
+LRESULT
+Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+
+  case WM_CHANGECBCHAIN:
+    vlog.debug("change clipboard chain (%x, %x)", wParam, lParam);
+    if ((HWND) wParam == next_window)
+      next_window = (HWND) lParam;
+    else if (next_window != 0)
+      SendMessage(next_window, msg, wParam, lParam);
+    else
+      vlog.error("bad clipboard chain change!");
+    break;
+
+  case WM_DRAWCLIPBOARD:
+    {
+      HWND owner = GetClipboardOwner();
+      if (owner == getHandle()) {
+        vlog.debug("local clipboard changed by me");
+      } else {
+        vlog.debug("local clipboard changed by %x", owner);
+
+                         // Open the clipboard
+                         if (OpenClipboard(getHandle())) {
+                                 // Get the clipboard data
+                                 HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
+                                 if (cliphandle) {
+                                         char* clipdata = (char*) GlobalLock(cliphandle);
+
+            // Notify clients
+            if (notifier) {
+              if (!clipdata) {
+                notifier->notifyClipboardChanged(0, 0);
+              } else {
+                CharArray unix_text;
+                unix_text.buf = dos2unix(clipdata);
+                removeNonISOLatin1Chars(unix_text.buf);
+                notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf));
+              }
+            } else {
+              vlog.debug("no clipboard notifier registered");
+            }
+
+                                         // Release the buffer and close the clipboard
+                                         GlobalUnlock(cliphandle);
+                                 }
+
+                                 CloseClipboard();
+        }
+                       }
+    }
+    if (next_window)
+                 SendMessage(next_window, msg, wParam, lParam);
+    return 0;
+
+  };
+  return MsgWindow::processMessage(msg, wParam, lParam);
+};
+
+void
+Clipboard::setClipText(const char* text) {
+  HANDLE clip_handle = 0;
+
+  try {
+
+    // - Firstly, we must open the clipboard
+    if (!OpenClipboard(getHandle()))
+      throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());
+
+    // - Pre-process the supplied clipboard text into DOS format
+    CharArray dos_text;
+    dos_text.buf = unix2dos(text);
+    removeNonISOLatin1Chars(dos_text.buf);
+    int dos_text_len = strlen(dos_text.buf);
+
+    // - Allocate global memory for the data
+    clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, dos_text_len+1);
+
+    char* data = (char*) GlobalLock(clip_handle);
+    memcpy(data, dos_text.buf, dos_text_len+1);
+    data[dos_text_len] = 0;
+    GlobalUnlock(clip_handle);
+
+    // - Next, we must clear out any existing data
+    if (!EmptyClipboard())
+      throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());
+
+    // - Set the new clipboard data
+    if (!SetClipboardData(CF_TEXT, clip_handle))
+      throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
+    clip_handle = 0;
+
+    vlog.debug("set clipboard");
+  } catch (rdr::Exception& e) {
+    vlog.debug(e.str());
+  }
+
+  // - Close the clipboard
+  if (!CloseClipboard())
+    vlog.debug("unable to close Win32 clipboard: %u", GetLastError());
+  else
+    vlog.debug("closed clipboard");
+  if (clip_handle) {
+    vlog.debug("freeing clipboard handle");
+    GlobalFree(clip_handle);
+  }
+}
diff --git a/win/rfb_win32/Clipboard.h b/win/rfb_win32/Clipboard.h
new file mode 100644 (file)
index 0000000..b79768f
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+// -=- Clipboard.h
+//
+// The Clipboard is used to set the system clipboard, and to get callbacks
+// when the system clipboard has changed.
+
+#ifndef __RFB_WIN32_CLIPBOARD_H__
+#define __RFB_WIN32_CLIPBOARD_H__
+
+#include <rfb/SDesktop.h>
+#include <rfb/Threading.h>
+#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/DeviceFrameBuffer.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class Clipboard : MsgWindow {
+    public:
+
+      // -=- Abstract base class for callback recipients
+      class Notifier {
+      public:
+        virtual void notifyClipboardChanged(const char* text, int len) = 0;
+      };
+
+      Clipboard();
+      ~Clipboard();
+
+      // - Set the notifier to use
+      void setNotifier(Notifier* cbn) {notifier = cbn;}
+
+      // - Set the clipboard contents
+      void setClipText(const char* text);
+
+    protected:
+      // - Internal MsgWindow callback
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      Notifier* notifier;
+      HWND next_window;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_CLIPBOARD_H__
diff --git a/win/rfb_win32/CompatibleBitmap.h b/win/rfb_win32/CompatibleBitmap.h
new file mode 100644 (file)
index 0000000..4beed8d
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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 __RFB_WIN32_COMPAT_BITMAP_H__
+#define __RFB_WIN32_COMPAT_BITMAP_H__
+
+#include <windows.h>
+#include <rdr/Exception.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class CompatibleBitmap {
+    public:
+      CompatibleBitmap(HDC hdc, int width, int height) {
+        hbmp = CreateCompatibleBitmap(hdc, width, height);
+        if (!hbmp)
+          throw rdr::SystemException("CreateCompatibleBitmap() failed", GetLastError());
+      }
+      virtual ~CompatibleBitmap() {
+        if (hbmp) DeleteObject(hbmp);
+      }
+      operator HBITMAP() const {return hbmp;}
+    protected:
+      HBITMAP hbmp;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/ComputerName.h b/win/rfb_win32/ComputerName.h
new file mode 100644 (file)
index 0000000..110caa5
--- /dev/null
@@ -0,0 +1,40 @@
+/* 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 __RFB_WIN32_COMPUTERNAME_H__
+#define __RFB_WIN32_COMPUTERNAME_H__
+
+#include <windows.h>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+  namespace win32 {
+
+    // Get the computer name
+    struct ComputerName : TCharArray {
+      ComputerName() : TCharArray(MAX_COMPUTERNAME_LENGTH+1) {
+        ULONG namelength = MAX_COMPUTERNAME_LENGTH+1;
+        if (!GetComputerName(buf, &namelength))
+          _tcscpy(buf, _T(""));
+      }
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/CurrentUser.cxx b/win/rfb_win32/CurrentUser.cxx
new file mode 100644 (file)
index 0000000..7562d29
--- /dev/null
@@ -0,0 +1,152 @@
+/* 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.
+ */
+
+// -=- Currentuser.cxx
+
+#include <stdlib.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/CurrentUser.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb_win32/Service.h>
+#include <rfb_win32/OSVersion.h>
+#include <lmcons.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CurrentUser");
+
+
+const TCHAR* shellIconClass = _T("Shell_TrayWnd");
+
+BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam) {
+  TCHAR className[16];
+  if (GetClassName(hwnd, className, sizeof(className)) &&
+      (_tcscmp(className, shellIconClass) == 0)) {
+    vlog.debug("located tray icon window (%s)", (const char*)CStr(className));
+    DWORD processId = 0;
+    GetWindowThreadProcessId(hwnd, &processId);
+    if (!processId)
+      return TRUE;
+    Handle process = OpenProcess(MAXIMUM_ALLOWED, FALSE, processId);
+    if (!process.h)
+      return TRUE;
+    if (!OpenProcessToken(process, MAXIMUM_ALLOWED, (HANDLE*)lParam))
+      return TRUE;
+    vlog.debug("obtained user token");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+BOOL CALLBACK enumDesktops(LPTSTR lpszDesktop, LPARAM lParam) {
+  HDESK desktop = OpenDesktop(lpszDesktop, 0, FALSE, DESKTOP_ENUMERATE);
+  vlog.debug("opening \"%s\"", lpszDesktop);
+  if (!desktop) {
+    vlog.info("desktop \"%s\" inaccessible", (const char*)CStr(lpszDesktop));
+    return TRUE;
+  }
+  BOOL result = EnumDesktopWindows(desktop, enumWindows, lParam);
+  if (!CloseDesktop(desktop))
+    vlog.info("unable to close desktop: %ld", GetLastError());
+  return result;
+}
+
+
+CurrentUserToken::CurrentUserToken() : isSafe_(false) {
+  if (isServiceProcess()) {
+    // If the platform is Windows 95/98/Me then we must fake the token's presence
+    if (osVersion.isPlatformWindows) {
+      try {
+        UserName un;
+        h = INVALID_HANDLE_VALUE;
+      } catch (rdr::SystemException& e) {
+        if (e.err != ERROR_NOT_LOGGED_ON)
+          throw;
+        if (FindWindow(shellIconClass, 0))
+          h = INVALID_HANDLE_VALUE;
+      }
+      isSafe_ = (h != 0);
+      return;
+    }
+
+    // Try to get the user token using the Terminal Services APIs
+    //   NB: This will only work under XP/2003 and later
+    typedef BOOL (WINAPI *WTSQueryUserToken_proto)(ULONG, PHANDLE);
+    DynamicFn<WTSQueryUserToken_proto> _WTSQueryUserToken(_T("wtsapi32.dll"), "WTSQueryUserToken");
+    if (_WTSQueryUserToken.isValid()) {
+      (*_WTSQueryUserToken)(-1, &h);
+      isSafe_ = true;
+      return;
+    }
+
+    // Try to find the Shell Tray Icon window and take its token
+    //   NB: This will only work under NT/2K (and later, but they're dealt with above)
+    //   NB: If the shell is not running then this will return an Unsafe Null token.
+    EnumDesktops(GetProcessWindowStation(), enumDesktops, (LONG)&h);
+    isSafe_ = (h != 0);
+  } else {
+    // Try to open the security token for the User-Mode process
+    if (!OpenProcessToken(GetCurrentProcess(), GENERIC_ALL, &h)) {
+      DWORD err = GetLastError();
+      if (err != ERROR_CALL_NOT_IMPLEMENTED)
+        throw rdr::SystemException("OpenProcessToken failed", err);
+      // Under Windows 95/98/Me, we fake the handle value...
+      h = INVALID_HANDLE_VALUE;
+    }
+    isSafe_ = true;
+  }
+}
+
+
+ImpersonateCurrentUser::ImpersonateCurrentUser() {
+  RegCloseKey(HKEY_CURRENT_USER);
+  if (!isServiceProcess())
+    return;
+  if (!token.canImpersonate())
+    throw rdr::Exception("Cannot impersonate unsafe or null token");
+  if (!ImpersonateLoggedOnUser(token)) {
+    DWORD err = GetLastError();
+    if (err != ERROR_CALL_NOT_IMPLEMENTED)
+      throw rdr::SystemException("Failed to impersonate user", GetLastError());
+  }
+}
+
+ImpersonateCurrentUser::~ImpersonateCurrentUser() {
+  if (!RevertToSelf()) {
+    DWORD err = GetLastError();
+    if (err != ERROR_CALL_NOT_IMPLEMENTED)
+      exit(err);
+  }
+  RegCloseKey(HKEY_CURRENT_USER);
+}
+
+
+UserName::UserName() : TCharArray(UNLEN+1) {
+  DWORD len = UNLEN+1;
+  if (!GetUserName(buf, &len))
+    throw rdr::SystemException("GetUserName failed", GetLastError());
+}
+
+
+UserSID::UserSID() {
+  CurrentUserToken token;
+  if (!token.canImpersonate())
+    return;
+  setSID(Sid::FromToken(token.h));
+}
diff --git a/win/rfb_win32/CurrentUser.h b/win/rfb_win32/CurrentUser.h
new file mode 100644 (file)
index 0000000..794f27c
--- /dev/null
@@ -0,0 +1,100 @@
+/* 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.
+ */
+
+// CurrentUser.h
+
+// Helper class providing the session's logged on username, if
+// a user is logged on.  Also allows processes running under
+// XP/2K3 etc to masquerade as the logged on user for security
+// purposes
+
+#ifndef __RFB_WIN32_CURRENT_USER_H__
+#define __RFB_WIN32_CURRENT_USER_H__
+
+#include <rfb_win32/Handle.h>
+#include <rfb_win32/Security.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    // CurrentUserToken
+    //   CurrentUserToken is a Handle containing the security token
+    //   for the currently logged-on user, or null if no user is
+    //   logged on.
+    //
+    //   Under Windows 95/98/Me, which don't support security tokens,
+    //   the token will be INVALID_HANDLE_VALUE if a user is logged on.
+    //
+    //   Under Windows NT/2K, it may be the case that the token is
+    //   null even when a user *is* logged on, because we use some hacks
+    //   to detect the user's token and sometimes they fail.  On these
+    //   platforms, isSafe() will return False if the token is null.
+    //
+    //   Under Windows XP, etc, isSafe() will always be True, and the token
+    //   will always be set to the currently logged on user's token.
+    //
+    //   canImpersonate() tests whether there is a user token that is safe
+    //   to impersonate.
+    //
+    //   noUserLoggedOn() tests whether there is *definitely* no user logged on.
+
+    struct CurrentUserToken : public Handle {
+      CurrentUserToken();
+      bool isSafe() const { return isSafe_; };
+      bool canImpersonate() const { return h && isSafe(); }
+      bool noUserLoggedOn() const { return !h && isSafe(); }
+    private:
+      bool isSafe_;
+    };
+
+    // ImpersonateCurrentUser
+    //   Throws an exception on failure.
+    //   Succeeds (trivially) if process is not running as service.
+    //   Fails if CurrentUserToken is not valid.
+    //   Fails if platform is NT AND cannot impersonate token.
+    //   Succeeds otherwise.
+
+    struct ImpersonateCurrentUser {
+      ImpersonateCurrentUser();
+      ~ImpersonateCurrentUser();
+      CurrentUserToken token;
+    };
+
+    // UserName
+    //   Returns the name of the user the thread is currently running as.
+    //   Raises a SystemException in case of error.
+    //   NB: Raises a SystemException with err == ERROR_NOT_LOGGED_ON if
+    //       running under Windows 9x/95/Me and no user is logged on.
+
+    struct UserName : public TCharArray {
+      UserName();
+    };
+
+    // UserSID
+    //   Returns the SID of the currently logged-on user (i.e. the session user)
+
+    struct UserSID : public Sid {
+      UserSID();
+    };
+
+  }
+
+}
+
+#endif
diff --git a/win/rfb_win32/DIBSectionBuffer.cxx b/win/rfb_win32/DIBSectionBuffer.cxx
new file mode 100644 (file)
index 0000000..18ce3ea
--- /dev/null
@@ -0,0 +1,222 @@
+/* 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 <rfb_win32/DIBSectionBuffer.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/BitmapInfo.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("DIBSectionBuffer");
+
+
+DIBSectionBuffer::DIBSectionBuffer(HWND window_)
+  : bitmap(0), device(0), window(window_) {
+  memset(&format, 0, sizeof(format));
+  memset(palette, 0, sizeof(palette));
+}
+
+DIBSectionBuffer::DIBSectionBuffer(HDC device_)
+  : bitmap(0), window(0), device(device_) {
+  memset(&format, 0, sizeof(format));
+  memset(palette, 0, sizeof(palette));
+}
+
+DIBSectionBuffer::~DIBSectionBuffer() {
+  if (bitmap)
+    DeleteObject(bitmap);
+}
+
+
+void DIBSectionBuffer::setPF(const PixelFormat& pf) {
+  if (memcmp(&getPF(), &pf, sizeof(pf)) == 0) {
+    vlog.debug("pixel format unchanged by setPF()");
+    return;
+  }
+  format = pf;
+  recreateBuffer();
+  if ((pf.bpp <= 8) && pf.trueColour) {
+    vlog.info("creating %d-bit TrueColour palette", pf.depth);
+    for (int i=0; i < (1<<(pf.depth)); i++) {
+      palette[i].b = ((((i >> pf.blueShift) & pf.blueMax) * 65535) + pf.blueMax/2) / pf.blueMax;
+      palette[i].g = ((((i >> pf.greenShift) & pf.greenMax) * 65535) + pf.greenMax/2) / pf.greenMax;
+      palette[i].r = ((((i >> pf.redShift) & pf.redMax) * 65535) + pf.redMax/2) / pf.redMax;
+    }
+    refreshPalette();
+  }
+}
+
+void DIBSectionBuffer::setSize(int w, int h) {
+  if (width_ == w && height_ == h) {
+    vlog.debug("size unchanged by setSize()");
+    return;
+  }
+  width_ = w;
+  height_ = h;
+  recreateBuffer();
+}
+
+
+// * copyPaletteToDIB MUST NEVER be called on a truecolour DIB! *
+
+void copyPaletteToDIB(Colour palette[256], HDC wndDC, HBITMAP dib) {
+  BitmapDC dibDC(wndDC, dib);
+  RGBQUAD rgb[256];
+  for (unsigned int i=0;i<256;i++) {
+    rgb[i].rgbRed = palette[i].r >> 8;
+    rgb[i].rgbGreen = palette[i].g >> 8;
+    rgb[i].rgbBlue = palette[i].b >> 8;
+  }
+  if (!SetDIBColorTable(dibDC, 0, 256, (RGBQUAD*) rgb))
+    throw rdr::SystemException("unable to SetDIBColorTable", GetLastError());
+}
+
+inline void initMaxAndShift(DWORD mask, int* max, int* shift) {
+  for ((*shift) = 0; (mask & 1) == 0; (*shift)++) mask >>= 1;
+  (*max) = (rdr::U16)mask;
+}
+
+void DIBSectionBuffer::recreateBuffer() {
+  HBITMAP new_bitmap = 0;
+  rdr::U8* new_data = 0;
+
+  if (width_ && height_ && (format.depth != 0)) {
+    BitmapInfo bi;
+    memset(&bi, 0, sizeof(bi));
+    // *** wrong?
+    UINT iUsage = format.trueColour ? DIB_RGB_COLORS : DIB_PAL_COLORS;
+    // ***
+    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bi.bmiHeader.biBitCount = format.bpp;
+    bi.bmiHeader.biSizeImage = (format.bpp / 8) * width_ * height_;
+    bi.bmiHeader.biPlanes = 1;
+    bi.bmiHeader.biWidth = width_;
+    bi.bmiHeader.biHeight = -height_;
+    bi.bmiHeader.biCompression = (format.bpp > 8) ? BI_BITFIELDS : BI_RGB;
+    bi.mask.red = format.redMax << format.redShift;
+    bi.mask.green = format.greenMax << format.greenShift;
+    bi.mask.blue = format.blueMax << format.blueShift;
+
+    // Create a DIBSection to draw into
+    if (device)
+      new_bitmap = ::CreateDIBSection(device, (BITMAPINFO*)&bi.bmiHeader, iUsage,
+                                      (void**)&new_data, NULL, 0);
+    else
+      new_bitmap = ::CreateDIBSection(WindowDC(window), (BITMAPINFO*)&bi.bmiHeader, iUsage,
+                                      (void**)&new_data, NULL, 0);
+
+    if (!new_bitmap) {
+      int err = GetLastError();
+      throw rdr::SystemException("unable to create DIB section", err);
+    }
+
+    vlog.debug("recreateBuffer()");
+  } else {
+    vlog.debug("one of area or format not set");
+  }
+
+  if (new_bitmap && bitmap) {
+    vlog.debug("preserving bitmap contents");
+
+    // Copy the contents across
+    if (device) {
+      if (format.bpp <= 8)
+        copyPaletteToDIB(palette, device, new_bitmap);
+      BitmapDC src_dev(device, bitmap);
+      BitmapDC dest_dev(device, new_bitmap);
+      BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY);
+    } else {
+      WindowDC wndDC(window);
+      if (format.bpp <= 8)
+        copyPaletteToDIB(palette, wndDC, new_bitmap);
+      BitmapDC src_dev(wndDC, bitmap);
+      BitmapDC dest_dev(wndDC, new_bitmap);
+      BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY);
+    }
+  }
+  
+  if (bitmap) {
+    // Delete the old bitmap
+    DeleteObject(bitmap);
+    bitmap = 0;
+    data = 0;
+  }
+
+  if (new_bitmap) {
+    // Set up the new bitmap
+    bitmap = new_bitmap;
+    data = new_data;
+
+    // Determine the *actual* DIBSection format
+    DIBSECTION ds;
+    if (!GetObject(bitmap, sizeof(ds), &ds))
+      throw rdr::SystemException("GetObject", GetLastError());
+
+    // Correct the "stride" of the DIB
+    // *** This code DWORD aligns each row - is that right???
+    stride = width_;
+    int bytesPerRow = stride * format.bpp/8;
+    if (bytesPerRow % 4) {
+      bytesPerRow += 4 - (bytesPerRow % 4);
+      stride = (bytesPerRow * 8) / format.bpp;
+      vlog.info("adjusting DIB stride: %d to %d", width_, stride);
+    }
+
+    // Calculate the PixelFormat for the DIB
+    format.bigEndian = 0;
+    format.bpp = format.depth = ds.dsBm.bmBitsPixel;
+    format.trueColour = format.trueColour || format.bpp > 8;
+    if (format.bpp > 8) {
+
+      // Get the truecolour format used by the DIBSection
+      initMaxAndShift(ds.dsBitfields[0], &format.redMax, &format.redShift);
+      initMaxAndShift(ds.dsBitfields[1], &format.greenMax, &format.greenShift);
+      initMaxAndShift(ds.dsBitfields[2], &format.blueMax, &format.blueShift);
+
+      // Calculate the effective depth
+      format.depth = 0;
+      Pixel bits = ds.dsBitfields[0] | ds.dsBitfields[1] | ds.dsBitfields[2];
+      while (bits) {
+        format.depth++;
+        bits = bits >> 1;
+      }
+      if (format.depth > format.bpp)
+        throw Exception("Bad DIBSection format (depth exceeds bpp)");
+    } else {
+      // Set the DIBSection's palette
+      refreshPalette();
+    }
+
+  }
+}
+
+void DIBSectionBuffer::refreshPalette() {
+  if (format.bpp > 8) {
+    vlog.error("refresh palette called for truecolor DIB");
+    return;
+  }
+  vlog.debug("refreshing palette");
+  if (device)
+    copyPaletteToDIB(palette, device, bitmap);
+  else
+    copyPaletteToDIB(palette, WindowDC(window), bitmap);
+}
+
+
diff --git a/win/rfb_win32/DIBSectionBuffer.h b/win/rfb_win32/DIBSectionBuffer.h
new file mode 100644 (file)
index 0000000..ad1a310
--- /dev/null
@@ -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.
+ */
+
+// -=- DIBSectionBuffer.h
+
+// A DIBSectionBuffer acts much like a standard PixelBuffer, but is associated
+// with a particular window on-screen and can be drawn into that window if
+// required, using the standard Win32 drawing operations.
+
+#ifndef __RFB_WIN32_DIB_SECTION_BUFFER_H__
+#define __RFB_WIN32_DIB_SECTION_BUFFER_H__
+
+#include <windows.h>
+#include <rfb/PixelBuffer.h>
+#include <rfb/Region.h>
+#include <rfb/ColourMap.h>
+#include <rfb/Exception.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    //
+    // -=- DIBSectionBuffer
+    //
+
+    class DIBSectionBuffer : public FullFramePixelBuffer, ColourMap {
+    public:
+      DIBSectionBuffer(HWND window);
+      DIBSectionBuffer(HDC device);
+      virtual ~DIBSectionBuffer();
+
+      virtual void setPF(const PixelFormat &pf);
+      virtual void setSize(int w, int h);
+
+      virtual int getStride() const {return stride;}
+
+      virtual ColourMap* getColourMap() const {return (ColourMap*)this;}
+
+      // - ColourMap interface
+      virtual void lookup(int index, int* r, int *g, int* b) {
+        *r = palette[index].r;
+        *g = palette[index].g;
+        *b = palette[index].b;
+      }
+  
+      // Custom colourmap interface
+      void setColour(int index, int r, int g, int b) {
+        palette[index].r = r;
+        palette[index].g = g;
+        palette[index].b = b;
+      }
+      void refreshPalette();
+
+      // *** virtual void copyRect(const Rect &dest, const Point &move_by_delta);
+    public:
+      HBITMAP bitmap;
+    protected:
+      void recreateBuffer();
+      Colour palette[256];
+      int stride;
+      HWND window;
+      HDC device;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_DIB_SECTION_BUFFER_H__
diff --git a/win/rfb_win32/DeviceContext.cxx b/win/rfb_win32/DeviceContext.cxx
new file mode 100644 (file)
index 0000000..4f70a1b
--- /dev/null
@@ -0,0 +1,188 @@
+/* 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 <rfb_win32/DeviceContext.h>
+#include <rfb_win32/CompatibleBitmap.h>
+#include <rfb_win32/BitmapInfo.h>
+#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace win32;
+
+
+static LogWriter vlog("DeviceContext");
+
+PixelFormat DeviceContext::getPF() const {
+  return getPF(dc);
+}
+
+PixelFormat DeviceContext::getPF(HDC dc) {
+  PixelFormat format;
+  CompatibleBitmap bitmap(dc, 1, 1);
+
+  // -=- Get the bitmap format information
+  BitmapInfo bi;
+  memset(&bi, 0, sizeof(bi));
+  bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+  bi.bmiHeader.biBitCount = 0;
+  if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
+    throw rdr::SystemException("unable to determine device pixel format", GetLastError());
+  }
+  if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
+    throw rdr::SystemException("unable to determine pixel shifts/palette", GetLastError());
+  }
+
+  // Set the initial format information
+  format.trueColour = bi.bmiHeader.biBitCount > 8;
+  format.bigEndian = 0;
+  format.bpp = bi.bmiHeader.biBitCount;
+
+  if (format.trueColour) {
+    DWORD rMask=0, gMask=0, bMask=0;
+
+    // Which true colour format is the DIB section using?
+    switch (bi.bmiHeader.biCompression) {
+    case BI_RGB:
+      // Default RGB layout
+      switch (bi.bmiHeader.biBitCount) {
+      case 16:
+        // RGB 555 - High Colour
+        vlog.info("16-bit High Colour");
+        rMask = 0x7c00;
+        bMask = 0x001f;
+        gMask = 0x03e0;
+        break;
+      case 24:
+      case 32:
+        // RGB 888 - True Colour
+        vlog.info("24/32-bit High Colour");
+        rMask = 0xff0000;
+        gMask = 0x00ff00;
+        bMask = 0x0000ff;
+        break;
+      default:
+        vlog.error("bits per pixel %u not supported", bi.bmiHeader.biBitCount);
+        throw rdr::Exception("unknown bits per pixel specified");
+      };
+      break;
+    case BI_BITFIELDS:
+      // Custom RGB layout
+      rMask = bi.mask.red;
+      gMask = bi.mask.green;
+      bMask = bi.mask.blue;
+      vlog.info("%lu-bit BitFields: (%lx, %lx, %lx)",
+                 bi.bmiHeader.biBitCount, rMask, gMask, bMask);
+      break;
+    };
+
+    // Convert the data we just retrieved
+    initMaxAndShift(rMask, &format.redMax, &format.redShift);
+    initMaxAndShift(gMask, &format.greenMax, &format.greenShift);
+    initMaxAndShift(bMask, &format.blueMax, &format.blueShift);
+
+    // Calculate the depth from the colour shifts
+    format.depth = 0;
+    Pixel bits = rMask | gMask | bMask;
+    while (bits) {
+      format.depth++;
+      bits = bits >> 1;
+    }
+
+    // Check that the depth & bpp are valid
+    if (format.depth > format.bpp) {
+      vlog.error("depth exceeds bits per pixel!");
+      format.bpp = format.depth;
+    }
+
+    // Correct the bits-per-pixel to something we're happy with
+    if (format.bpp <= 16)
+      format.bpp = 16;
+    else if (format.bpp <= 32)
+      format.bpp = 32;
+  } else {
+    // Palettised format - depth reflects number of colours,
+    // but bits-per-pixel is ALWAYS 8
+    format.depth = format.bpp;
+    if (format.bpp < 8)
+      format.bpp = 8;
+    vlog.info("%d-colour palettised", 1<<format.depth);
+  }
+
+  return format;
+}
+
+Rect DeviceContext::getClipBox() const {
+  return getClipBox(dc);
+}
+
+Rect DeviceContext::getClipBox(HDC dc) {
+  // Get the display dimensions
+  RECT cr;
+  if (!GetClipBox(dc, &cr))
+    throw rdr::SystemException("GetClipBox", GetLastError());
+  return Rect(cr.left, cr.top, cr.right, cr.bottom);
+}
+
+
+DeviceDC::DeviceDC(const TCHAR* deviceName) {
+  dc = ::CreateDC(_T("DISPLAY"), deviceName, NULL, NULL);
+  if (!dc)
+    throw rdr::SystemException("failed to create DeviceDC", GetLastError());
+}
+
+DeviceDC::~DeviceDC() {
+  if (dc)
+    DeleteDC(dc);
+}
+
+
+WindowDC::WindowDC(HWND wnd) : hwnd(wnd) {
+  dc = GetDC(wnd);
+  if (!dc)
+    throw rdr::SystemException("GetDC failed", GetLastError());
+}
+
+WindowDC::~WindowDC() {
+  if (dc)
+    ReleaseDC(hwnd, dc);
+}
+
+
+CompatibleDC::CompatibleDC(HDC existing) {
+  dc = CreateCompatibleDC(existing);
+  if (!dc)
+    throw rdr::SystemException("CreateCompatibleDC failed", GetLastError());
+}
+
+CompatibleDC::~CompatibleDC() {
+  if (dc)
+    DeleteDC(dc);
+}
+
+
+BitmapDC::BitmapDC(HDC hdc, HBITMAP hbitmap) : CompatibleDC(hdc){
+  oldBitmap = (HBITMAP)SelectObject(dc, hbitmap);
+  if (!oldBitmap)
+    throw rdr::SystemException("SelectObject to CompatibleDC failed",
+    GetLastError());
+}
+
+BitmapDC::~BitmapDC() {
+  SelectObject(dc, oldBitmap);
+}
diff --git a/win/rfb_win32/DeviceContext.h b/win/rfb_win32/DeviceContext.h
new file mode 100644 (file)
index 0000000..9d91cec
--- /dev/null
@@ -0,0 +1,86 @@
+/* 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.
+ */
+
+// DeviceContext base class, wrapping Windows HDC, plus some
+// helper classes tailored to particular types of DC, such as
+// window and device DCs.
+
+#ifndef __RFB_WIN32_DEVICECONTEXT_H__
+#define __RFB_WIN32_DEVICECONTEXT_H__
+
+#include <windows.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/Rect.h>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    // Base class, providing methods to get the bounding (clip) box,
+    // and the pixel format, and access to the HDC itself.
+    class DeviceContext {
+    public:
+      DeviceContext() : dc(0) {}
+      virtual ~DeviceContext() {}
+      operator HDC() const {return dc;}
+      PixelFormat getPF() const;
+      static PixelFormat getPF(HDC dc);
+      Rect getClipBox() const;
+      static Rect getClipBox(HDC dc);
+    protected:
+      HDC dc;
+    };
+
+    // -=- DeviceContext that opens a specific display device
+    class DeviceDC : public DeviceContext {
+    public:
+      DeviceDC(const TCHAR* deviceName);
+      ~DeviceDC();
+    };
+
+    // Get a DC for a particular window's client area.
+    class WindowDC : public DeviceContext {
+    public:
+      WindowDC(HWND wnd);
+      virtual ~WindowDC();
+    protected:
+      HWND hwnd;
+    };
+
+    // Create a new DC, compatible with an existing one.
+    class CompatibleDC : public DeviceContext {
+    public:
+      CompatibleDC(HDC existing);
+      virtual ~CompatibleDC();
+    };
+
+    // Create a new DC, compatible with an existing one, and
+    // select the specified bitmap into it.
+    class BitmapDC : public CompatibleDC {
+    public:
+      BitmapDC(HDC hdc, HBITMAP hbitmap);
+      ~BitmapDC();
+    protected:
+      HBITMAP oldBitmap;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/DeviceFrameBuffer.cxx b/win/rfb_win32/DeviceFrameBuffer.cxx
new file mode 100644 (file)
index 0000000..8da894e
--- /dev/null
@@ -0,0 +1,289 @@
+/* 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.
+ */
+
+// -=- DeviceFrameBuffer.cxx
+//
+// The DeviceFrameBuffer class encapsulates the pixel data of the system
+// display.
+
+#include <vector>
+#include <rfb_win32/DeviceFrameBuffer.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb_win32/IconInfo.h>
+#include <rfb/VNCServer.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("DeviceFrameBuffer");
+
+BoolParameter DeviceFrameBuffer::useCaptureBlt("UseCaptureBlt",
+  "Use a slower capture method that ensures that alpha blended windows appear correctly",
+  true);
+
+
+// -=- DeviceFrameBuffer class
+
+DeviceFrameBuffer::DeviceFrameBuffer(HDC deviceContext, const Rect& wRect)
+  : DIBSectionBuffer(deviceContext), device(deviceContext), cursorBm(deviceContext),
+    ignoreGrabErrors(false)
+{
+
+  // -=- Firstly, let's check that the device has suitable capabilities
+
+  int capabilities = GetDeviceCaps(device, RASTERCAPS);
+  if (!(capabilities & RC_BITBLT)) {
+    throw Exception("device does not support BitBlt");
+  }
+  if (!(capabilities & RC_DI_BITMAP)) {
+    throw Exception("device does not support GetDIBits");
+  }
+  /*
+  if (GetDeviceCaps(device, PLANES) != 1) {
+    throw Exception("device does not support planar displays");
+  }
+  */
+
+  // -=- Get the display dimensions and pixel format
+
+  // Get the display dimensions
+  deviceCoords = DeviceContext::getClipBox(device);
+  if (!wRect.is_empty())
+    deviceCoords = wRect.translate(deviceCoords.tl);
+  int w = deviceCoords.width();
+  int h = deviceCoords.height();
+
+  // We can't handle uneven widths :(
+  if (w % 2) w--;
+
+  // Configure the underlying DIB to match the device
+  DIBSectionBuffer::setPF(DeviceContext::getPF(device));
+  DIBSectionBuffer::setSize(w, h);
+
+  // Configure the cursor buffer
+  cursorBm.setPF(format);
+
+  // Set up a palette if required
+  if (!format.trueColour)
+    updateColourMap();
+}
+
+DeviceFrameBuffer::~DeviceFrameBuffer() {
+}
+
+
+void
+DeviceFrameBuffer::setPF(const PixelFormat &pf) {
+  throw Exception("setPF not supported");
+}
+
+void
+DeviceFrameBuffer::setSize(int w, int h) {
+  throw Exception("setSize not supported");
+}
+
+
+#ifndef CAPTUREBLT
+#define CAPTUREBLT 0x40000000
+#endif
+
+void
+DeviceFrameBuffer::grabRect(const Rect &rect) {
+  BitmapDC tmpDC(device, bitmap);
+
+  // Map the rectangle coords from VNC Desktop-relative to device relative - usually (0,0)
+  Point src = desktopToDevice(rect.tl);
+
+  // Note: Microsoft's documentation lies directly about CAPTUREBLT and claims it works on 98/ME
+  //       If you try CAPTUREBLT on 98 then you get blank output...
+  if (!::BitBlt(tmpDC, rect.tl.x, rect.tl.y, rect.width(), rect.height(), device, src.x, src.y,
+    (osVersion.isPlatformNT && useCaptureBlt) ? (CAPTUREBLT | SRCCOPY) : SRCCOPY)) {
+    if (ignoreGrabErrors)
+      vlog.error("BitBlt failed:%ld", GetLastError());
+    else
+      throw rdr::SystemException("BitBlt failed", GetLastError());
+  }
+}
+
+void
+DeviceFrameBuffer::grabRegion(const Region &rgn) {
+  std::vector<Rect> rects;
+  std::vector<Rect>::const_iterator i;
+  rgn.get_rects(&rects);
+  for(i=rects.begin(); i!=rects.end(); i++) {
+    grabRect(*i);
+  }
+  ::GdiFlush();
+}
+
+
+void copyDevicePaletteToDIB(HDC dc, DIBSectionBuffer* dib) {
+  // - Fetch the system palette for the framebuffer
+  PALETTEENTRY syspalette[256];
+  UINT entries = ::GetSystemPaletteEntries(dc, 0, 256, syspalette);
+
+  if (entries == 0) {
+    vlog.info("resorting to standard 16 color palette");
+    for (unsigned int i=0;i<256;i++) {
+      int v = (i%16) >= 8 ? 127 : 255;
+      syspalette[i].peRed = i & 1 ? v : 0;
+      syspalette[i].peGreen = i & 2 ? v : 0;
+      syspalette[i].peBlue = i & 4 ? v : 0;
+    }
+  } else {
+    vlog.info("framebuffer has %u palette entries", entries);
+  }
+
+  // - Update the bitmap's stored copy of the palette
+  for (unsigned int i=0;i<256;i++) {
+    int r, g, b;
+    r = (syspalette[i].peRed << 8) + 0x80;
+    g = (syspalette[i].peGreen << 8) + 0x80;
+    b = (syspalette[i].peBlue << 8) + 0x80;
+    dib->setColour(i, r, g, b);
+  }
+
+  // - Update the DIB section to use the palette
+  dib->refreshPalette();
+}
+
+
+void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
+{
+  // - If hCursor is null then there is no cursor - clear the old one
+
+  if (hCursor == 0) {
+    server->setCursor(0, 0, Point(), 0, 0);
+    return;
+  }
+
+  try {
+
+    // - Get the size and other details about the cursor.
+
+    IconInfo iconInfo((HICON)hCursor);
+
+    BITMAP maskInfo;
+    if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), &maskInfo))
+      throw rdr::SystemException("GetObject() failed", GetLastError());
+    if (maskInfo.bmPlanes != 1)
+      throw rdr::Exception("unsupported multi-plane cursor");
+    if (maskInfo.bmBitsPixel != 1)
+      throw rdr::Exception("unsupported cursor mask format");
+
+    // - Create the cursor pixel buffer and mask storage
+    //   NB: The cursor pixel buffer is NOT used here.  Instead, we
+    //   pass the cursorBm.data pointer directly, to save overhead.
+
+    cursor.setSize(maskInfo.bmWidth, maskInfo.bmHeight);
+    cursor.setPF(format);
+    cursor.hotspot = Point(iconInfo.xHotspot, iconInfo.yHotspot);
+
+    // - Get the AND and XOR masks.  There is only an XOR mask if this is not a
+    // colour cursor.
+
+    if (!iconInfo.hbmColor)
+      cursor.setSize(cursor.width(), cursor.height() / 2);
+    rdr::U8Array mask(maskInfo.bmWidthBytes * maskInfo.bmHeight);
+    rdr::U8* xorMask = mask.buf + cursor.height() * maskInfo.bmWidthBytes;
+
+    if (!GetBitmapBits(iconInfo.hbmMask,
+                       maskInfo.bmWidthBytes * maskInfo.bmHeight, mask.buf))
+      throw rdr::SystemException("GetBitmapBits failed", GetLastError());
+
+    // Configure the cursor bitmap
+    cursorBm.setSize(cursor.width(), cursor.height());
+
+    // Copy the palette into it if required
+    if (format.bpp <= 8)
+      copyDevicePaletteToDIB(device, &cursorBm);
+
+    // Draw the cursor into the bitmap
+    BitmapDC dc(device, cursorBm.bitmap);
+    if (!DrawIconEx(dc, 0, 0, hCursor, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT))
+      throw rdr::SystemException("unable to render cursor", GetLastError());
+
+    // Replace any XORed pixels with xorColour, because RFB doesn't support
+    // XORing of cursors.  XORing is used for the I-beam cursor, which is most
+    // often used over a white background, but also sometimes over a black
+    // background.  We set the XOR'd pixels to black, then draw a white outline
+    // around the whole cursor.
+
+    // *** should we replace any pixels not set in mask to zero, to ensure
+    // that irrelevant data doesn't screw compression?
+
+    bool doOutline = false;
+    if (!iconInfo.hbmColor) {
+      Pixel xorColour = format.pixelFromRGB(0, 0, 0, cursorBm.getColourMap());
+      for (int y = 0; y < cursor.height(); y++) {
+        bool first = true;
+        for (int x = 0; x < cursor.width(); x++) {
+          int byte = y * maskInfo.bmWidthBytes + x / 8;
+          int bit = 7 - x % 8;
+          if ((mask.buf[byte] & (1 << bit)) && (xorMask[byte] & (1 << bit)))
+          {
+            mask.buf[byte] &= ~(1 << bit);
+
+            switch (format.bpp) {
+            case 8:
+              ((rdr::U8*)cursorBm.data)[y * cursor.width() + x] = xorColour;  break;
+            case 16:
+              ((rdr::U16*)cursorBm.data)[y * cursor.width() + x] = xorColour; break;
+            case 32:
+              ((rdr::U32*)cursorBm.data)[y * cursor.width() + x] = xorColour; break;
+            }
+
+            doOutline = true;
+          }
+        }
+      }
+    }
+
+    // Finally invert the AND mask so it's suitable for RFB and pack it into
+    // the minimum number of bytes per row.
+
+    int maskBytesPerRow = (cursor.width() + 7) / 8;
+
+    for (int j = 0; j < cursor.height(); j++) {
+      for (int i = 0; i < maskBytesPerRow; i++)
+        cursor.mask.buf[j * maskBytesPerRow + i]
+          = ~mask.buf[j * maskInfo.bmWidthBytes + i];
+    }
+
+    if (doOutline) {
+      vlog.debug("drawing cursor outline!");
+      memcpy(cursor.data, cursorBm.data, cursor.dataLen());
+      cursor.drawOutline(format.pixelFromRGB(0xffff, 0xffff, 0xffff, cursorBm.getColourMap()));
+      memcpy(cursorBm.data, cursor.data, cursor.dataLen());
+    }
+
+    server->setCursor(cursor.width(), cursor.height(), cursor.hotspot,
+                      cursorBm.data, cursor.mask.buf);
+  } catch (rdr::Exception& e) {
+    vlog.error(e.str());
+  }
+}
+
+
+void
+DeviceFrameBuffer::updateColourMap() {
+  if (!format.trueColour)
+    copyDevicePaletteToDIB(device, this);
+}
diff --git a/win/rfb_win32/DeviceFrameBuffer.h b/win/rfb_win32/DeviceFrameBuffer.h
new file mode 100644 (file)
index 0000000..7718c33
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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.
+ */
+
+// -=- DeviceFrameBuffer.h
+//
+// The DeviceFrameBuffer class encapsulates the pixel data of a supplied
+// Device Context Handle (HDC)
+
+// *** THIS INTERFACE NEEDS TIDYING TO SEPARATE COORDINATE SYSTEMS BETTER ***
+
+#ifndef __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
+#define __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
+
+#include <windows.h>
+#include <rfb_win32/DIBSectionBuffer.h>
+#include <rfb/Cursor.h>
+#include <rfb/Region.h>
+#include <rfb/Exception.h>
+#include <rfb/Configuration.h>
+
+namespace rfb {
+
+  class VNCServer;
+
+  namespace win32 {
+
+    // -=- DeviceFrameBuffer interface
+
+    // DeviceFrameBuffer is passed an HDC referring to a window or to
+    // the entire display.  It may also be passed a rectangle specifying
+    // the Device-relative coordinates of the actual rectangle to treat
+    // as the desktop.
+
+    // Coordinate systems start getting really annoying here.  There are
+    // three different "origins" to which coordinates might be relative:
+    //
+    // Desktop - VNC coordinates, top-left always (0,0)
+    // Device - DC coordinates.  Top-left *usually (0,0) but could be other.
+    // Window - coordinates relative to the specified sub-rectangle within
+    //          the supplied DC.
+    // Screen - Coordinates relative to the entire Windows virtual screen.
+    //          The virtual screen includes all monitors that are part of
+    //          the Windows desktop.
+
+    // The data member is made to point to an internal mirror of the
+    // current display data.  Individual rectangles or regions of the
+    // buffer can be brought up to date by calling the grab functions.
+
+    class DeviceFrameBuffer : public DIBSectionBuffer {
+    public:
+      DeviceFrameBuffer(HDC deviceContext, const Rect& area_=Rect());
+      virtual ~DeviceFrameBuffer();
+
+      // - FrameBuffer overrides
+
+      virtual void grabRect(const Rect &rect);
+      virtual void grabRegion(const Region &region);
+
+      // - DIBSectionBuffer overrides
+      
+      virtual void setPF(const PixelFormat& pf);
+      virtual void setSize(int w, int h);
+      
+      // - DeviceFrameBuffer specific methods
+
+      void setCursor(HCURSOR c, VNCServer* server);
+      void updateColourMap();
+
+      // Set whether grabRect should ignore errors or throw exceptions
+      // Only set this if you are sure you'll capture the errors some other way!
+      void setIgnoreGrabErrors(bool ie) {ignoreGrabErrors=ie;}
+      
+      static BoolParameter useCaptureBlt;
+
+    protected:
+      // Translate supplied Desktop coordinates into Device-relative coordinates
+      // This translation may have been affected at start-time by the supplied sub-rect.
+      Point desktopToDevice(const Point p) const {return p.translate(deviceCoords.tl);}
+
+      HDC device;
+      DIBSectionBuffer cursorBm;
+      Cursor cursor;
+      Rect deviceCoords;
+      bool ignoreGrabErrors;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
diff --git a/win/rfb_win32/Dialog.cxx b/win/rfb_win32/Dialog.cxx
new file mode 100644 (file)
index 0000000..398334f
--- /dev/null
@@ -0,0 +1,391 @@
+/* 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.
+ */
+
+// -=- Dialog.cxx
+
+// Base-class for any Dialog classes we might require
+
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/LogWriter.h>
+#include <rdr/Exception.h>
+#include <rfb_win32/Win32Util.h>
+
+#ifdef _DIALOG_CAPTURE
+#ifdef PropSheet_IndexToId
+#include <rfb_win32/DeviceFrameBuffer.h>
+#include <extra/LoadBMP.cxx>
+#else
+#undef _DIALOG_CAPTURE
+#pragma message("  NOTE: Not building Dialog Capture support.")
+#endif
+#endif
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter dlog("Dialog");
+static LogWriter plog("PropSheet");
+
+
+Dialog::Dialog(HINSTANCE inst_)
+: inst(inst_), alreadyShowing(false), handle(0)
+{
+}
+
+Dialog::~Dialog()
+{
+}
+
+
+bool Dialog::showDialog(const TCHAR* resource, HWND owner)
+{
+  if (alreadyShowing) return false;
+  handle = 0;
+  alreadyShowing = true;
+  INT_PTR result = DialogBoxParam(inst, resource, owner,
+                                  staticDialogProc, (LPARAM)this);
+  if (result<0)
+    throw rdr::SystemException("DialogBoxParam failed", GetLastError());
+  alreadyShowing = false;
+  return (result == 1);
+}
+
+
+bool Dialog::isItemChecked(int id) {
+  return SendMessage(GetDlgItem(handle, id), BM_GETCHECK, 0, 0) == BST_CHECKED;
+}
+int Dialog::getItemInt(int id) {
+  BOOL trans;
+  int result = GetDlgItemInt(handle, id, &trans, TRUE);
+  if (!trans)
+    throw rdr::Exception("unable to read dialog Int");
+  return result;
+}
+TCHAR* Dialog::getItemString(int id) {
+  TCharArray tmp(256);
+  if (!GetDlgItemText(handle, id, tmp.buf, 256))
+    tmp.buf[0] = 0;
+  return tmp.takeBuf();
+}
+
+void Dialog::setItemChecked(int id, bool state) {
+  dlog.debug("bool[%d]=%d", id, (int)state);
+  SendMessage(GetDlgItem(handle, id), BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0);
+}
+void Dialog::setItemInt(int id, int value) {
+  dlog.debug("int[%d]=%d", id, value);
+  SetDlgItemInt(handle, id, value, TRUE);
+}
+void Dialog::setItemString(int id, const TCHAR* s) {
+  dlog.debug("string[%d]=%s", id, (const char*)CStr(s));
+  SetDlgItemText(handle, id, s);
+}
+
+
+void Dialog::enableItem(int id, bool state) {
+  dlog.debug("enable[%d]=%d", id, (int)state);
+  EnableWindow(GetDlgItem(handle, id), state);
+}
+
+
+
+
+BOOL CALLBACK Dialog::staticDialogProc(HWND hwnd, UINT msg,
+                                      WPARAM wParam, LPARAM lParam)
+{
+  if (msg == WM_INITDIALOG)
+    SetWindowLong(hwnd, GWL_USERDATA, (LONG)lParam);
+
+  LONG self = GetWindowLong(hwnd, GWL_USERDATA);
+  if (!self) return FALSE;
+
+  return ((Dialog*)self)->dialogProc(hwnd, msg, wParam, lParam);
+}
+
+BOOL Dialog::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg) {
+
+  case WM_INITDIALOG:
+    handle = hwnd;
+    initDialog();
+    return TRUE;
+
+  case WM_COMMAND:
+    switch (LOWORD(wParam)) {
+    case IDOK:
+      if (onOk()) {
+        EndDialog(hwnd, 1);
+        return TRUE;
+      }
+      return FALSE;
+    case IDCANCEL:
+      EndDialog(hwnd, 0);
+      return TRUE;
+    default:
+      return onCommand(LOWORD(wParam), HIWORD(wParam));
+    };
+
+  case WM_HELP:
+    return onHelp(((HELPINFO*)lParam)->iCtrlId);
+
+  }
+
+  return FALSE;
+}
+
+
+PropSheetPage::PropSheetPage(HINSTANCE inst, const TCHAR* id) : Dialog(inst), propSheet(0) {
+  page.dwSize = sizeof(page);
+  page.dwFlags = 0; // PSP_USECALLBACK;
+  page.hInstance = inst;
+  page.pszTemplate = id;
+  page.pfnDlgProc = staticPageProc;
+  page.lParam = (LPARAM)this;
+  page.pfnCallback = 0; // staticPageProc;
+}
+
+PropSheetPage::~PropSheetPage() {
+}
+
+
+BOOL CALLBACK PropSheetPage::staticPageProc(HWND hwnd, UINT msg,
+                                      WPARAM wParam, LPARAM lParam)
+{
+  if (msg == WM_INITDIALOG)
+    SetWindowLong(hwnd, GWL_USERDATA, ((PROPSHEETPAGE*)lParam)->lParam);
+
+  LONG self = GetWindowLong(hwnd, GWL_USERDATA);
+  if (!self) return FALSE;
+
+  return ((PropSheetPage*)self)->dialogProc(hwnd, msg, wParam, lParam);
+}
+
+BOOL PropSheetPage::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg) {
+
+  case WM_INITDIALOG:
+    handle = hwnd;
+    initDialog();
+    return TRUE;
+
+  case WM_NOTIFY:
+    switch (((NMHDR*)lParam)->code) {
+    case PSN_APPLY:
+      onOk();
+      return FALSE;
+    };
+    return FALSE;
+
+  case WM_COMMAND:
+    return onCommand(LOWORD(wParam), HIWORD(wParam));
+
+  case WM_HELP:
+    return onHelp(((HELPINFO*)lParam)->iCtrlId);
+
+  }
+
+  return FALSE;
+}
+
+
+PropSheet::PropSheet(HINSTANCE inst_, const TCHAR* title_, std::list<PropSheetPage*> pages_, HICON icon_)
+: title(tstrDup(title_)), inst(inst_), pages(pages_), alreadyShowing(0), handle(0), icon(icon_) {
+}
+
+PropSheet::~PropSheet() {
+}
+
+
+// For some reason, DLGTEMPLATEEX isn't defined in the Windows headers - go figure...
+struct DLGTEMPLATEEX {
+  WORD dlgVer;
+  WORD signature;
+  DWORD helpID;
+  DWORD exStyle;
+  DWORD style;
+  WORD cDlgItems;
+  short x;
+  short y;
+  short cx;
+  short cy;
+};
+
+static int CALLBACK removeCtxtHelp(HWND hwnd, UINT message, LPARAM lParam) {
+  if (message == PSCB_PRECREATE) {
+    // Remove the context-help style, to remove the titlebar ? button
+    // *** Nasty hack to cope with new & old dialog template formats...
+    if (((DLGTEMPLATEEX*)lParam)->signature == 0xffff)
+      ((DLGTEMPLATEEX*)lParam)->style &= ~DS_CONTEXTHELP;
+    else
+      ((LPDLGTEMPLATE)lParam)->style &= ~DS_CONTEXTHELP;
+  }
+  return TRUE;
+}
+
+
+bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, bool capture) {
+  if (alreadyShowing) return false;
+  alreadyShowing = true;
+  int count = pages.size();
+
+  HPROPSHEETPAGE* hpages = new HPROPSHEETPAGE[count];
+  try {
+    // Create the PropertSheet page GDI objects.
+    std::list<PropSheetPage*>::iterator pspi;
+    int i = 0;
+    for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
+      hpages[i] = CreatePropertySheetPage(&((*pspi)->page));
+      (*pspi)->setPropSheet(this);
+      i++;
+    }
+    // Initialise and create the PropertySheet itself
+    PROPSHEETHEADER header;
+    header.dwSize = PROPSHEETHEADER_V1_SIZE;
+    header.dwFlags = PSH_MODELESS | (showApply ? 0 : PSH_NOAPPLYNOW) | (showCtxtHelp ? 0 : PSH_USECALLBACK);
+    header.pfnCallback = removeCtxtHelp;
+    header.hwndParent = owner;
+    header.hInstance = inst;
+    header.pszCaption = title.buf;
+    header.nPages = count;
+    header.nStartPage = 0;
+    header.phpage = hpages;
+    if (icon) {
+      header.hIcon = icon;
+      header.dwFlags |= PSH_USEHICON;
+    }
+
+    handle = (HWND)PropertySheet(&header);
+    if ((handle == 0) || (handle == (HWND)-1))
+      throw rdr::SystemException("PropertySheet failed", GetLastError());
+    centerWindow(handle, owner);
+    plog.info("created %lx", handle);
+
+#ifdef _DIALOG_CAPTURE
+    if (capture) {
+      plog.info("capturing \"%s\"", (const char*)CStr(title.buf));
+      char* tmpdir = getenv("TEMP");
+      HDC dc = GetWindowDC(handle);
+      DeviceFrameBuffer fb(dc);
+      int i=0;
+      while (true) {
+        int id = PropSheet_IndexToId(handle, i);
+        if (!id) break;
+        PropSheet_SetCurSelByID(handle, id);
+        MSG msg;
+        while (PeekMessage(&msg, handle, 0, 0, PM_REMOVE)) {
+          if (!PropSheet_IsDialogMessage(handle, &msg))
+            DispatchMessage(&msg);
+        }
+        fb.grabRect(fb.getRect());
+        TCHAR title[128];
+        if (!GetWindowText(PropSheet_GetCurrentPageHwnd(handle), title, sizeof(title)))
+          _stprintf(title, _T("capture%d"), i);
+        CharArray pageTitle(strDup(title));
+        for (int j=0; j<strlen(pageTitle.buf); j++) {
+          if (pageTitle.buf[j] == '/' || pageTitle.buf[j] == '\\' || pageTitle.buf[j] == ':')
+            pageTitle.buf[j] = '-';
+        }
+        char filename[256];
+        sprintf(filename, "%s\\%s.bmp", tmpdir, pageTitle.buf);
+        vlog.debug("writing to %s", filename);
+        saveBMP(filename, &fb);
+        i++;
+      }
+      ReleaseDC(handle, dc);
+    } else {
+#endif
+      try {
+        if (owner)
+          EnableWindow(owner, FALSE);
+        // Run the PropertySheet
+        MSG msg;
+        while (GetMessage(&msg, 0, 0, 0)) {
+          if (!PropSheet_IsDialogMessage(handle, &msg))
+            DispatchMessage(&msg);
+          if (!PropSheet_GetCurrentPageHwnd(handle))
+            break;
+        }
+        if (owner)
+          EnableWindow(owner, TRUE);
+      } catch (...) {
+        if (owner)
+          EnableWindow(owner, TRUE);
+        throw;
+      }
+#ifdef _DIALOG_CAPTURE
+    }
+#endif
+
+    plog.info("finished %lx", handle);
+
+    DestroyWindow(handle);
+    handle = 0;
+    alreadyShowing = false;
+
+    // Clear up the pages' GDI objects
+    for (pspi=pages.begin(); pspi!=pages.end(); pspi++)
+      (*pspi)->setPropSheet(0);
+    delete [] hpages; hpages = 0;
+
+    return true;
+  } catch (rdr::Exception) {
+    alreadyShowing = false;
+
+    std::list<PropSheetPage*>::iterator pspi;
+    for (pspi=pages.begin(); pspi!=pages.end(); pspi++)
+      (*pspi)->setPropSheet(0);
+    delete [] hpages; hpages = 0;
+
+    throw;
+  }
+}
+
+void PropSheet::reInitPages() {
+  plog.debug("reInitPages %lx", handle);
+  std::list<PropSheetPage*>::iterator pspi;
+  for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
+    if ((*pspi)->handle)
+      (*pspi)->initDialog();
+  }
+}
+
+bool PropSheet::commitPages() {
+  plog.debug("commitPages %lx", handle);
+  bool result = true;
+  std::list<PropSheetPage*>::iterator pspi;
+  for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
+    if ((*pspi)->handle)
+      result = result && (*pspi)->onOk();
+  }
+  return result;
+}
+
+
+void PropSheetPage::setChanged(bool changed) {
+  if (propSheet) {
+    plog.debug("setChanged[%lx(%lx)]=%d", handle, propSheet->handle, (int)changed);
+    if (changed)
+      PropSheet_Changed(propSheet->handle, handle);
+    else
+      PropSheet_UnChanged(propSheet->handle, handle);
+  }
+}
diff --git a/win/rfb_win32/Dialog.h b/win/rfb_win32/Dialog.h
new file mode 100644 (file)
index 0000000..9784ba4
--- /dev/null
@@ -0,0 +1,158 @@
+/* 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.
+ */
+
+// -=- RegConfig.h
+
+// Class which monitors the registry and reads in the registry settings
+// whenever they change, or are added or removed.
+
+#ifndef __RFB_WIN32_DIALOG_H__
+#define __RFB_WIN32_DIALOG_H__
+
+#include <windows.h>
+#include <prsht.h>
+#include <list>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    // Dialog - A simple Win32 Dialog box.  A derived class of Dialog overrides the
+    // initDialog(), command() and ok() methods to take appropriate action.  A
+    // simple dialog box can be displayed by creating a Dialog object and calling
+    // show().
+
+    class Dialog {
+    public:
+
+      Dialog(HINSTANCE inst);
+      virtual ~Dialog();
+
+      // showDialog() displays the dialog box.  It returns when it has been dismissed,
+      // returning true if "OK" was pressed, false otherwise.  The resource
+      // argument identifies the dialog resource (often a MAKEINTRESOURCE macro
+      // expansion), and owner is an optional window handle - the corresponding
+      // window is disabled while the dialog box is displayed.
+
+      bool showDialog(const TCHAR* resource, HWND owner=0);
+
+      // initDialog() is called upon receipt of the WM_INITDIALOG message.
+
+      virtual void initDialog() {}
+
+      // onCommand() is called upon receipt of a WM_COMMAND message item other than IDOK
+      // or IDCANCEL.  It should return true if the command has been handled.
+
+      virtual bool onCommand(int item, int cmd) { return false; }
+
+      // onHelp() is called upon receipt of a WM_MENU message.  This indicates that
+      // context-specific help should be displayed, for a dialog control, for example.
+      // It should return true if the command has been handled.
+
+      virtual bool onHelp(int item) { return false; }
+
+      // onOk() is called when the OK button is pressed.  The hwnd argument is the
+      // dialog box's window handle.
+
+      virtual bool onOk() { return true; }
+
+      // Read the states of items
+      bool isItemChecked(int id);
+      int getItemInt(int id);
+      TCHAR* getItemString(int id); // Recipient owns string storage
+      
+      // Set the states of items
+      void setItemChecked(int id, bool state);
+      void setItemInt(int id, int value);
+      void setItemString(int id, const TCHAR* s);
+
+      // enableItem is used to grey out an item, making it inaccessible, or to
+      // re-enable it.
+      void enableItem(int id, bool state);
+
+    protected:
+      static BOOL CALLBACK staticDialogProc(HWND hwnd, UINT msg,
+                             WPARAM wParam, LPARAM lParam);
+      virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+      HINSTANCE inst;
+      HWND handle;
+      bool alreadyShowing;
+    };
+
+    // PropertySheetPage 
+    // Class used to define property pages within a PropertySheet.
+    // Each page is associated with a particular dialog resource, indicated by
+    // the "id" parameter supplied to the constructor.
+
+    class PropSheetPage;
+
+    class PropSheet {
+    public:
+      PropSheet(HINSTANCE inst, const TCHAR* title, std::list<PropSheetPage*> pages, HICON icon=0);
+      virtual ~PropSheet();
+
+      // Display the PropertySheet
+      bool showPropSheet(HWND owner, bool showApply = false, bool showCtxtHelp = false, bool capture=false);
+      
+      // Calls initDialog again for each page that has already had it called.
+      // Note: If a page hasn't been seen yet, it won't have been called.
+      // Note: This must only be called while the property sheet is visible.
+      void reInitPages();
+
+      // Calls onOk for each page that has had initDialog called, and returns
+      // false if any one of them returns false, or true otherwise.  ALL the
+      // onOk() methods will be called, even if one of them fails.
+      // Note: If a page hasn't been seen yet, it won't have been called.
+      // Note: This must only be called while the property sheet is visible.
+      bool commitPages();
+
+      friend class PropSheetPage;
+
+    protected:
+      HWND owner;
+      HICON icon;
+      std::list<PropSheetPage*> pages;
+      HINSTANCE inst;
+      TCharArray title;
+      HWND handle;
+      bool alreadyShowing;
+    };
+
+    class PropSheetPage : public Dialog {
+    public:
+      PropSheetPage(HINSTANCE inst, const TCHAR* id);
+      virtual ~PropSheetPage();
+
+      void setChanged(bool changed);
+
+      friend class PropSheet;
+
+    protected:
+      void setPropSheet(PropSheet* ps) {propSheet = ps;};
+      static BOOL CALLBACK staticPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+      virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+      PROPSHEETPAGE page;
+      PropSheet* propSheet;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_DIALOG_H__
diff --git a/win/rfb_win32/DynamicFn.cxx b/win/rfb_win32/DynamicFn.cxx
new file mode 100644 (file)
index 0000000..e933f24
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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 <rfb_win32/DynamicFn.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("DynamicFn");
+
+
+DynamicFnBase::DynamicFnBase(const TCHAR* dllName, const char* fnName) : dllHandle(0), fnPtr(0) {
+  dllHandle = LoadLibrary(dllName);
+  if (!dllHandle) {
+    vlog.info("DLL %s not found (%d)", (const char*)CStr(dllName), GetLastError());
+    return;
+  }
+  fnPtr = GetProcAddress(dllHandle, fnName);
+  if (!fnPtr)
+    vlog.info("proc %s not found in %s (%d)", fnName, (const char*)CStr(dllName), GetLastError());
+}
+
+DynamicFnBase::~DynamicFnBase() {
+  if (dllHandle)
+    FreeLibrary(dllHandle);
+}
+
+
diff --git a/win/rfb_win32/DynamicFn.h b/win/rfb_win32/DynamicFn.h
new file mode 100644 (file)
index 0000000..57fdbec
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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.
+ */
+
+// Helper class managing dynamic linkage to DLL functions.
+
+#ifndef __RFB_WIN32_DYNAMICFN_H__
+#define __RFB_WIN32_DYNAMICFN_H__
+
+#include <windows.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class DynamicFnBase {
+    public:
+      DynamicFnBase(const TCHAR* dllName, const char* fnName);
+      ~DynamicFnBase();
+      bool isValid() const {return fnPtr != 0;}
+    protected:
+      void* fnPtr;
+      HMODULE dllHandle;
+    private:
+      DynamicFnBase(const DynamicFnBase&);
+      DynamicFnBase operator=(const DynamicFnBase&);
+    };
+
+    template<class T> class DynamicFn : public DynamicFnBase {
+    public:
+      DynamicFn(const TCHAR* dllName, const char* fnName) : DynamicFnBase(dllName, fnName) {}
+      T operator *() const {return (T)fnPtr;};
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/EventManager.cxx b/win/rfb_win32/EventManager.cxx
new file mode 100644 (file)
index 0000000..0f9993b
--- /dev/null
@@ -0,0 +1,103 @@
+/* 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 <rfb_win32/EventManager.h>
+#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("EventManager");
+
+
+EventManager::EventManager() : eventCount(0) {
+}
+
+EventManager::~EventManager() {
+}
+
+
+bool EventManager::addEvent(HANDLE event, EventHandler* ecb) {
+  if (eventCount >= MAXIMUM_WAIT_OBJECTS-1)
+    return false;
+  events[eventCount] = event;
+  handlers[eventCount] = ecb;
+  eventCount++;
+  return true;
+}
+
+void EventManager::removeEvent(HANDLE event) {
+  for (int i=0; i<eventCount; i++) {
+    if (events[i] == event) {
+      for (int j=i; j<eventCount-1; j++) {
+        events[j] = events[j+1];
+        handlers[j] = handlers[j+1];
+      }
+      eventCount--;
+      return;
+    }
+  }
+  throw rdr::Exception("Event not registered");
+}
+
+
+int EventManager::checkTimeouts() {
+  return 0;
+}
+
+BOOL EventManager::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
+  while (true) {
+    // - Process any pending timeouts
+    DWORD timeout = checkTimeouts();
+    if (timeout == 0)
+      timeout = INFINITE;
+
+    // - Events take precedence over messages
+    DWORD result;
+    if (eventCount) {
+      // - Check whether any events are set
+      result = WaitForMultipleObjects(eventCount, events, FALSE, 0);
+      if (result == WAIT_TIMEOUT) {
+        // - No events are set, so check for messages
+        if (PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE)) 
+          return msg->message != WM_QUIT;
+
+        // - Block waiting for an event to be set, or a message
+        result = MsgWaitForMultipleObjects(eventCount, events, FALSE, timeout,
+                                           QS_ALLINPUT);
+        if (result == WAIT_OBJECT_0 + eventCount) {
+          // - Return the message, if any
+          if (PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE)) 
+            return msg->message != WM_QUIT;
+          continue;
+        }
+      }
+    } else
+      return GetMessage(msg, hwnd, minMsg, maxMsg);
+
+    if ((result >= WAIT_OBJECT_0) && (result < (WAIT_OBJECT_0 + eventCount))) {
+      // - An event was set - call the handler
+      int index = result - WAIT_OBJECT_0;
+      handlers[index]->processEvent(events[index]);
+    } else if (result == WAIT_FAILED) {
+      // - An error has occurred, so return the error status code
+      return -1;
+    }
+  }
+}
diff --git a/win/rfb_win32/EventManager.h b/win/rfb_win32/EventManager.h
new file mode 100644 (file)
index 0000000..bb66e34
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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.
+ */
+
+// -=- EventManager.h
+
+// Win32 event manager.  Caller supplies event & handler pairs and
+// then uses getMessage() in place of ::GetMessage() in the main
+// loop.  EventManager calls the event handler whenever the event
+// is set.
+// Ownership of events remains with the caller.
+// It is the responsibility of handlers to reset events.
+
+#ifndef __RFB_WIN32_EVENT_MGR_H__
+#define __RFB_WIN32_EVENT_MGR_H__
+
+#include <rfb_win32/Win32Util.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class EventHandler {
+    public:
+      virtual ~EventHandler() {}
+      virtual void processEvent(HANDLE event) = 0;
+    };
+
+    class EventManager {
+    public:
+      EventManager();
+      virtual ~EventManager();
+
+      // Add a Win32 event & handler for it
+      //   NB: The handler must call ResetEvent on the event.
+      //   NB: The caller retains ownership of the event.
+      virtual bool addEvent(HANDLE event, EventHandler* ecb);
+
+      // Remove a Win32 event
+      virtual void removeEvent(HANDLE event);
+
+      // getMessage
+      //   Waits for a message to become available on the thread's message queue,
+      //   and returns it.  If any registered events become set while waiting then
+      //   their handlers are called before returning.
+      //   Returns zero if the message is WM_QUIT, -1 in case of error, >0 otherwise.
+      virtual BOOL getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg);
+
+    protected:
+      // checkTimeouts
+      //   Derived classes should override this to perform any extra processing,
+      //   returning the maximum number of milliseconds after which the callback
+      //   should be called again.
+      virtual int checkTimeouts();
+
+      HANDLE events[MAXIMUM_WAIT_OBJECTS];
+      EventHandler* handlers[MAXIMUM_WAIT_OBJECTS-1];
+      int eventCount;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/FolderManager.cxx b/win/rfb_win32/FolderManager.cxx
new file mode 100644 (file)
index 0000000..a2fa08d
--- /dev/null
@@ -0,0 +1,279 @@
+/* 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/
+ *
+ */
+
+// -=- FolderManager.cxx
+
+#include <rfb_win32/FolderManager.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FolderManager::FolderManager()
+{
+
+}
+
+FolderManager::~FolderManager()
+{
+
+}
+      
+bool 
+FolderManager::createDir(char *pFullPath)
+{
+  if (CreateDirectory(pFullPath, NULL) == 0) return false;
+
+  return true;
+}
+
+bool
+FolderManager::renameIt(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);
+
+  return renameIt(fullOldName, fullNewName);
+}
+
+bool 
+FolderManager::renameIt(char *pOldName, char *pNewName)
+{
+  if (MoveFile(pOldName, pNewName)) return true;
+
+  return false;
+}
+
+bool 
+FolderManager::deleteIt(char *pFullPath)
+{
+  FileInfo fileInfo;
+
+  FILEINFO FIStruct;
+  if (!getInfo(pFullPath, &FIStruct)) return false;
+
+  fileInfo.add(&FIStruct);
+
+  return deleteIt(&fileInfo);
+}
+
+bool
+FolderManager::deleteIt(char *pPrefix, FileInfo *pFI)
+{
+  char buf[FT_FILENAME_SIZE];
+  for (unsigned int i = 0; i < pFI->getNumEntries(); i++) {
+    sprintf(buf, "%s\\%s", pPrefix, pFI->getNameAt(i));
+    pFI->setNameAt(i,buf);
+  }
+  return deleteIt(pFI);
+}
+
+bool
+FolderManager::deleteIt(FileInfo *pFI)
+{
+  unsigned int num = pFI->getNumEntries();
+  unsigned int last = num - 1;
+
+  while (num > 0) {
+    if (pFI->getFlagsAt(last) & FT_ATTR_DIR) {
+      if (RemoveDirectory(pFI->getNameAt(last)) == 0) {
+        if (GetLastError() == ERROR_DIR_NOT_EMPTY) {
+          if (!getFolderInfoWithPrefix(pFI->getNameAt(last), pFI)) {
+            pFI->free();
+            return false;
+          }
+        }
+      } else {
+        pFI->deleteAt(last);
+      }
+    } else {
+      if (DeleteFile(pFI->getNameAt(last)) == 0) {
+        pFI->free();
+        return false;
+      } else {
+        pFI->deleteAt(last);
+      }
+    }
+    num = pFI->getNumEntries();
+    last = num - 1;
+  }
+
+  return true;
+}
+
+bool 
+FolderManager::getFolderInfoWithPrefix(char *pPrefix, FileInfo *pFileInfo)
+{
+  char prefix[FT_FILENAME_SIZE];
+  strcpy(prefix, pPrefix);
+
+  FileInfo tmpFileInfo;
+  if (!getDirInfo(prefix, &tmpFileInfo, 0)) {
+    tmpFileInfo.free();
+    return false;
+  } else {
+    char buf[FT_FILENAME_SIZE];
+    for (unsigned int i = 0; i < tmpFileInfo.getNumEntries(); i++) {
+      sprintf(buf, "%s\\%s", prefix, tmpFileInfo.getNameAt(i));
+      pFileInfo->add(buf, tmpFileInfo.getSizeAt(i), tmpFileInfo.getDataAt(i), tmpFileInfo.getFlagsAt(i));
+    }
+  }
+  tmpFileInfo.free();
+  return true;
+}
+    
+bool 
+FolderManager::getDirInfo(char *pPath, FileInfo *pFileInfo, unsigned int dirOnly)
+{
+  if (strlen(pPath) == 0) return getDrivesInfo(pFileInfo);
+  
+  char path[FT_FILENAME_SIZE];
+  sprintf(path, "%s\\*", pPath);
+  
+  WIN32_FIND_DATA FindFileData;
+  SetErrorMode(SEM_FAILCRITICALERRORS);
+  HANDLE handle = FindFirstFile(path, &FindFileData);
+  DWORD lastError = GetLastError();
+  SetErrorMode(0);
+  
+  if (handle != INVALID_HANDLE_VALUE) {
+    do {
+      if (strcmp(FindFileData.cFileName, ".") != 0 &&
+        strcmp(FindFileData.cFileName, "..") != 0) {
+        unsigned int lastWriteTime = getTime70(FindFileData.ftLastWriteTime);
+        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {      
+          pFileInfo->add(FindFileData.cFileName, 0, lastWriteTime, FT_ATTR_DIR);
+        } else {
+          if (!dirOnly)
+            pFileInfo->add(FindFileData.cFileName, FindFileData.nFileSizeLow, lastWriteTime, FT_ATTR_FILE);
+        }
+      }
+      
+    } while (FindNextFile(handle, &FindFileData));
+  } else {
+    return false;
+  }
+  FindClose(handle);
+  return true;
+}
+
+bool 
+FolderManager::getDrivesInfo(FileInfo *pFileInfo)
+{
+  TCHAR szDrivesList[256];
+  if (GetLogicalDriveStrings(255, szDrivesList) == 0)
+    return false;
+  
+  int i = 0;
+  while (szDrivesList[i] != '\0') {
+    char *drive = strdup(&szDrivesList[i]);
+    char *backslash = strrchr(drive, '\\');
+    if (backslash != NULL)
+      *backslash = '\0';
+    pFileInfo->add(drive, 0, 0, FT_ATTR_DIR);
+    free(drive);
+    i += strcspn(&szDrivesList[i], "\0") + 1;
+  }
+  return true;
+}
+
+bool
+FolderManager::getInfo(char *pFullPath, FILEINFO *pFIStruct)
+{
+  WIN32_FIND_DATA FindFileData;
+  SetErrorMode(SEM_FAILCRITICALERRORS);
+  HANDLE hFile = FindFirstFile(pFullPath, &FindFileData);
+  DWORD lastError = GetLastError();
+  SetErrorMode(0);
+  if (hFile != INVALID_HANDLE_VALUE) {
+    FindClose(hFile);
+    strcpy(pFIStruct->name, pFullPath);
+    pFIStruct->info.data = getTime70(FindFileData.ftLastWriteTime);
+    if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {    
+      pFIStruct->info.size = 0;
+      pFIStruct->info.flags = FT_ATTR_DIR;
+      return true;
+    } else {
+      pFIStruct->info.size = FindFileData.nFileSizeLow;
+      pFIStruct->info.flags = FT_ATTR_FILE;
+      return true;
+    }
+  }
+  return false;
+}
+
+unsigned int 
+FolderManager::getTime70(FILETIME ftime)
+{
+  LARGE_INTEGER uli;
+  uli.LowPart = ftime.dwLowDateTime;
+  uli.HighPart = ftime.dwHighDateTime;
+  uli.QuadPart = (uli.QuadPart - 116444736000000000) / 10000000;
+  return uli.LowPart;
+}
+
+void 
+FolderManager::getFiletime(unsigned int time70, FILETIME *pftime)
+{
+  LONGLONG ll = Int32x32To64(time70, 10000000) + 116444736000000000;
+  pftime->dwLowDateTime = (DWORD) ll;
+  pftime->dwHighDateTime = (DWORD) (ll >> 32);
+}
+
+bool
+FolderManager::getDirSize(char *pFullPath, DWORD64 *dirSize)
+{
+  char fullPath[FT_FILENAME_SIZE];
+  FileInfo fi;
+  fi.add(pFullPath, 0, 0, FT_ATTR_DIR);
+  DWORD64 dirFileSize64 = 0;
+  do {
+    sprintf(fullPath, "%s\\*", fi.getNameAt(0));
+    WIN32_FIND_DATA FindFileData;
+    SetErrorMode(SEM_FAILCRITICALERRORS);
+    HANDLE hFile = FindFirstFile(fullPath, &FindFileData);
+    SetErrorMode(0);
+    
+    if (hFile != INVALID_HANDLE_VALUE) {
+      do {
+        if (strcmp(FindFileData.cFileName, ".") != 0 &&
+          strcmp(FindFileData.cFileName, "..") != 0) {
+          char buff[MAX_PATH];
+          if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {    
+            sprintf(buff, "%s\\%s", fi.getNameAt(0), FindFileData.cFileName);
+            fi.add(buff, 0, 0, FT_ATTR_DIR);
+          } else {
+            dirFileSize64 += FindFileData.nFileSizeLow;
+          }
+        }
+      } while (FindNextFile(hFile, &FindFileData));
+      FindClose(hFile);
+    }
+    fi.deleteAt(0);
+  } while (fi.getNumEntries() > 0);
+  
+  *dirSize = dirFileSize64;
+  return true;
+}
\ No newline at end of file
diff --git a/win/rfb_win32/FolderManager.h b/win/rfb_win32/FolderManager.h
new file mode 100644 (file)
index 0000000..24923dd
--- /dev/null
@@ -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/
+ *
+ */
+
+// -=- FolderManager.h
+
+#ifndef __RFB_WIN32_FOLDERMANAGER_H__
+#define __RFB_WIN32_FOLDERMANAGER_H__
+
+#include <windows.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb/DirManager.h>
+
+namespace rfb {
+  namespace win32{
+    class FolderManager : public DirManager {
+    public:
+      FolderManager();
+      ~FolderManager();
+      
+      bool createDir(char *pFullPath);
+
+      bool renameIt(char *pOldName, char *pNewName);
+      bool renameIt(char *pPath, char *pOldName, char *pNewName);
+      
+      bool deleteIt(char *pPrefix, FileInfo *pFI);
+      bool deleteIt(char *pFullPath);
+      bool deleteIt(FileInfo *pFI);
+
+      bool getInfo(char *pFullPath, FILEINFO *pFIStruct);
+      
+      bool getDirInfo(char *pPath, FileInfo *pFileInfo, unsigned int dirOnly);
+      bool getDrivesInfo(FileInfo *pFI);
+
+      unsigned int getTime70(FILETIME ftime);
+      void getFiletime(unsigned int time70, FILETIME *pftime);
+
+      bool getDirSize(char *pFullPath, DWORD64 *dirSize);
+
+    private:
+      bool getFolderInfoWithPrefix(char *pPrefix, FileInfo *pFileInfo);
+    };
+  }
+}
+
+#endif // __RFB_WIN32_FOLDERMANAGER_H__
\ No newline at end of file
diff --git a/win/rfb_win32/Handle.h b/win/rfb_win32/Handle.h
new file mode 100644 (file)
index 0000000..d3baa58
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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.
+ */
+
+// Wrapper for Win32 HANDLEs that can/must be CloseHandle()d.
+
+#ifndef __RFB_WIN32_HANDLE_H__
+#define __RFB_WIN32_HANDLE_H__
+
+#include <windows.h>
+
+namespace rfb {
+  namespace win32 {
+
+
+    class Handle {
+    public:
+      Handle(HANDLE h_=0) : h(h_) {}
+      ~Handle() {
+        if (h) CloseHandle(h);
+      }
+      operator HANDLE() {return h;}
+      HANDLE h;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/IconInfo.h b/win/rfb_win32/IconInfo.h
new file mode 100644 (file)
index 0000000..cb33a42
--- /dev/null
@@ -0,0 +1,44 @@
+/* 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 __RFB_WIN32_ICONINFO_H__
+#define __RFB_WIN32_ICONINFO_H__
+
+#include <windows.h>
+#include <rdr/Exception.h>
+
+namespace rfb {
+  namespace win32 {
+
+    struct IconInfo : public ICONINFO {
+      IconInfo(HICON icon) {
+        if (!GetIconInfo(icon, this))
+          throw rdr::SystemException("GetIconInfo() failed", GetLastError());
+      }
+      ~IconInfo() {
+        if (hbmColor)
+          DeleteObject(hbmColor);
+        if (hbmMask)
+          DeleteObject(hbmMask);
+      }
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/IntervalTimer.h b/win/rfb_win32/IntervalTimer.h
new file mode 100644 (file)
index 0000000..ddfae49
--- /dev/null
@@ -0,0 +1,70 @@
+/* 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.
+ */
+
+// -=- IntervalTimer.h
+//
+// Simple wrapper for standard Win32 timers
+
+#ifndef __RFB_WIN32_INTERVAL_TIMER_H__
+#define __RFB_WIN32_INTERVAL_TIMER_H__
+
+namespace rfb {
+
+  namespace win32 {
+
+    struct IntervalTimer {
+      IntervalTimer(HWND hwnd_, int id_)
+        : active(false), hwnd(hwnd_), id(id_) {
+      }
+      IntervalTimer() : active(false), hwnd(0), id(0) {
+      }
+      ~IntervalTimer() {
+        stop();
+      }
+
+      void start(int interval_) {
+        if (!active || interval_ != interval) {
+          interval = interval_;
+          if (!SetTimer(hwnd, id, interval, 0))
+            throw rdr::SystemException("SetTimer", GetLastError());
+          active = true;
+        }
+      }
+      void stop() {
+        if (active)
+          KillTimer(hwnd, id);
+        active = false;
+      }
+
+      void setHWND(HWND hwnd_) {hwnd=hwnd_;}
+      void setId(int id_) {id = id_;}
+      int getId() const {return id;}
+      bool isActive() const {return active;}
+
+    private:
+      HWND hwnd;
+      int id;
+      bool active;
+      int interval;
+    };
+
+  }; // win32
+
+}; // rfb
+
+#endif // __RFB_WIN32_INTERVAL_TIMER_H__
diff --git a/win/rfb_win32/LaunchProcess.cxx b/win/rfb_win32/LaunchProcess.cxx
new file mode 100644 (file)
index 0000000..56a712e
--- /dev/null
@@ -0,0 +1,103 @@
+/* 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.
+ */
+
+// -=- LaunchProcess.cxx
+
+#include <rfb_win32/LaunchProcess.h>
+#include <rfb_win32/ModuleFileName.h>
+#include <rfb_win32/Win32Util.h>
+#include <rdr/Exception.h>
+#include <stdio.h>
+
+using namespace rfb;
+using namespace win32;
+
+
+LaunchProcess::LaunchProcess(const TCHAR* exeName_, const TCHAR* params_)
+: exeName(tstrDup(exeName_)), params(tstrDup(params_)) {
+  memset(&procInfo, 0, sizeof(procInfo));
+}
+
+LaunchProcess::~LaunchProcess() {
+  await();
+}
+
+
+void LaunchProcess::start(HANDLE userToken, bool createConsole) {
+  if (procInfo.hProcess && (WaitForSingleObject(procInfo.hProcess, 0) != WAIT_OBJECT_0))
+    return;
+  await();
+  returnCode = STILL_ACTIVE;
+
+  // - Create storage for the process startup information
+  STARTUPINFO sinfo;
+  memset(&sinfo, 0, sizeof(sinfo));
+  sinfo.cb = sizeof(sinfo);
+
+  // - Concoct a suitable command-line
+  TCharArray exePath;
+  if (!tstrContains(exeName.buf, _T('\\'))) {
+    ModuleFileName filename;
+    TCharArray path; splitPath(filename.buf, &path.buf, 0);
+    exePath.buf = new TCHAR[_tcslen(path.buf) + _tcslen(exeName.buf) + 2];
+    _stprintf(exePath.buf, _T("%s\\%s"), path.buf, exeName.buf);
+  } else {
+    exePath.buf = tstrDup(exeName.buf);
+  }
+
+  // - Start the process
+  // Note: We specify the exe's precise path in the ApplicationName parameter,
+  //       AND include the name as the first part of the CommandLine parameter,
+  //       because CreateProcess doesn't make ApplicationName argv[0] in C programs.
+  TCharArray cmdLine(_tcslen(exeName.buf) + 3 + _tcslen(params.buf) + 1);
+  _stprintf(cmdLine.buf, _T("\"%s\" %s"), exeName.buf, params.buf);
+  DWORD flags = createConsole ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW;
+  BOOL success;
+  if (userToken != INVALID_HANDLE_VALUE)
+    success = CreateProcessAsUser(userToken, exePath.buf, cmdLine.buf, 0, 0, FALSE, flags, 0, 0, &sinfo, &procInfo);
+  else
+    success = CreateProcess(exePath.buf, cmdLine.buf, 0, 0, FALSE, flags, 0, 0, &sinfo, &procInfo);
+  if (!success)
+    throw rdr::SystemException("unable to launch process", GetLastError());
+
+  // Wait for it to finish initialising
+  WaitForInputIdle(procInfo.hProcess, 15000);
+}
+
+void LaunchProcess::detach()
+{
+  if (!procInfo.hProcess)
+    return;
+  CloseHandle(procInfo.hProcess);
+  CloseHandle(procInfo.hThread);
+  memset(&procInfo, 0, sizeof(procInfo));
+}
+
+bool LaunchProcess::await(DWORD timeoutMs) {
+  if (!procInfo.hProcess)
+    return true;
+  DWORD result = WaitForSingleObject(procInfo.hProcess, timeoutMs);
+  if (result == WAIT_OBJECT_0) {
+    GetExitCodeProcess(procInfo.hProcess, &returnCode);
+    detach();
+    return true;
+  } else if (result == WAIT_FAILED) {
+    throw rdr::SystemException("await() failed", GetLastError());
+  }
+  return false;
+}
diff --git a/win/rfb_win32/LaunchProcess.h b/win/rfb_win32/LaunchProcess.h
new file mode 100644 (file)
index 0000000..38521dc
--- /dev/null
@@ -0,0 +1,71 @@
+/* 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.
+ */
+
+// -=- LaunchProcess.h
+
+// Helper class to launch a names process from the same directory as
+// the current process executable resides in.
+
+#ifndef __RFB_WIN32_LAUNCHPROCESS_H__
+#define __RFB_WIN32_LAUNCHPROCESS_H__
+
+#include <windows.h>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class LaunchProcess {
+    public:
+      LaunchProcess(const TCHAR* exeName_, const TCHAR* params);
+      ~LaunchProcess();
+
+      // start() starts the specified process with the supplied
+      //   command-line.
+      //   If userToken is INVALID_HANDLE_VALUE then starts the process
+      //   as the current user, otherwise as the specified user.
+      //   If createConsole is true then CREATE_CONSOLE_WINDOW is passed
+      //   as an extra flag to the process creation call.
+      void start(HANDLE userToken, bool createConsole=false);
+
+      // Detatch from the child process. After detatching from a child
+      //   process, no other methods should be called on the object
+      //   that started it
+      void detach();
+
+      // Wait for the process to quit, up to the specified timeout, and
+      //   close the handles to it once it has quit.
+      //   If the process quits within the timeout then true is returned
+      //   and returnCode is set. If it has not quit then false is returned.
+      //   If an error occurs then an exception will be thrown.
+      bool await(DWORD timeoutMs=INFINITE);
+
+      PROCESS_INFORMATION procInfo;
+      DWORD returnCode;
+    protected:
+      TCharArray exeName;
+      TCharArray params;
+    };
+
+
+  };
+
+};
+
+#endif
diff --git a/win/rfb_win32/ListViewControl.cxx b/win/rfb_win32/ListViewControl.cxx
new file mode 100644 (file)
index 0000000..12e0400
--- /dev/null
@@ -0,0 +1,103 @@
+// ListViewControl.cxx: implementation of the ListViewControl class.
+//
+//////////////////////////////////////////////////////////////////////
+#include <tchar.h>
+#include "ListViewControl.h"
+#include "commctrl.h"
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+using namespace rfb;
+using namespace rfb::win32;
+
+ListViewControl::ListViewControl()
+{
+}
+
+bool ListViewControl::IsSelectedLVItem(DWORD idListView,
+                                      HWND hDlg, int numberItem)
+{      
+  return (ListView_GetItemState(GetDlgItem(hDlg, idListView),
+    numberItem, LVIS_SELECTED) == LVIS_SELECTED);
+}
+
+void ListViewControl::SelectLVItem(DWORD idListView, HWND hDlg, int numberItem)
+{
+  ListView_SetItemState(GetDlgItem(hDlg, idListView),
+    numberItem, LVIS_SELECTED, LVIS_SELECTED);
+}
+
+BOOL ListViewControl::InitLVColumns(DWORD idListView, HWND hDlg, int width, int columns,
+                                    TCHAR *title[], DWORD mask, DWORD LVStyle, DWORD format)
+{
+  ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, idListView), LVStyle);
+  TCHAR szText[256];      
+  LVCOLUMN lvc; 
+  int iCol;
+  
+  lvc.mask = mask; 
+  
+  for (iCol = 0; iCol < columns; iCol++) { 
+    lvc.iSubItem = iCol;
+    lvc.pszText = szText;      
+    lvc.cx = width;           
+    lvc.fmt = format;
+    
+    _tcscpy(szText, title[iCol]); 
+    if (ListView_InsertColumn(GetDlgItem(hDlg, idListView), iCol, &lvc) == -1) 
+      return FALSE; 
+  } 
+  return TRUE; 
+}
+
+BOOL ListViewControl::InsertLVItem(DWORD idListView, HWND hDlg, int number,  TCHAR * texts[],
+                                   int columns)
+{
+  int i;
+  LVITEM lvI;
+  lvI.mask = LVIF_TEXT| LVIF_STATE; 
+  lvI.state = 0; 
+  lvI.stateMask = 0; 
+  lvI.iItem = number; 
+  lvI.iSubItem = 0; 
+  lvI.pszText = texts[0];                                                                        
+  
+  if(ListView_InsertItem(GetDlgItem(hDlg, idListView), &lvI) == -1)
+    return NULL;
+  
+  for (i =1; i < columns; i++) {       
+    SetLVItemText(
+      idListView, hDlg, 
+      number, i, texts[i]);
+  }
+  return TRUE;
+}
+
+void ListViewControl::SetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
+                                    int namberColumn, TCHAR * text)
+{
+  ListView_SetItemText(
+    GetDlgItem(hDlg, idListView), 
+    numberItem, namberColumn, text);
+}
+
+void ListViewControl::GetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
+                                    int namberColumn, TCHAR * text)
+{
+        ListView_GetItemText(GetDlgItem(hDlg, idListView), numberItem,
+                                                       namberColumn, text, 256);
+}
+
+void ListViewControl::DeleteLVItem(DWORD idListView, HWND hDlg, int number)
+{
+  ListView_DeleteItem(GetDlgItem(hDlg, idListView), number);
+}
+
+void ListViewControl::DeleteAllLVItem(DWORD idListView, HWND hDlg)
+{
+  ListView_DeleteAllItems(GetDlgItem(hDlg, idListView));
+}
+
+ListViewControl::~ListViewControl()
+{
+}
diff --git a/win/rfb_win32/ListViewControl.h b/win/rfb_win32/ListViewControl.h
new file mode 100644 (file)
index 0000000..8a16373
--- /dev/null
@@ -0,0 +1,35 @@
+// ListViewControl.h: interface for the ListViewControl class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef AFX_LISTVIEWCONTROL_H__
+#define AFX_LISTVIEWCONTROL_H__
+
+#include <windows.h>
+#include "commctrl.h"
+
+namespace rfb {
+  
+  namespace win32 {
+    class ListViewControl  
+    {
+    public:
+      ListViewControl();
+      bool IsSelectedLVItem(DWORD idListView, HWND hDlg, int numberItem);
+      void SelectLVItem(DWORD idListView, HWND hDlg, int numberItem);
+      BOOL InitLVColumns(DWORD idListView, HWND hDlg, int width, int columns,
+        TCHAR * title[], DWORD mask, DWORD style, DWORD format);
+      BOOL InsertLVItem(DWORD idListView, HWND hDlg, int number,  TCHAR * texts[],
+        int columns);
+      void SetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
+        int namberColumn, TCHAR * text);
+      void GetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
+        int namberColumn, TCHAR * text);
+      void DeleteLVItem(DWORD idListView, HWND hDlg, int number);
+      void DeleteAllLVItem(DWORD idListView, HWND hDlg);
+      virtual ~ListViewControl();      
+    };
+  };
+};
+
+#endif;
\ No newline at end of file
diff --git a/win/rfb_win32/LocalMem.h b/win/rfb_win32/LocalMem.h
new file mode 100644 (file)
index 0000000..a99d324
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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 __RFB_WIN32_LOCALMEM_H__
+#define __RFB_WIN32_LOCALMEM_H__
+
+#include <windows.h>
+#include <rdr/Exception.h>
+
+namespace rfb {
+  namespace win32 {
+
+    // Allocate and/or manage LocalAlloc memory.
+    struct LocalMem {
+      LocalMem(int size) : ptr(LocalAlloc(LMEM_FIXED, size)) {
+        if (!ptr) throw rdr::SystemException("LocalAlloc", GetLastError());
+      }
+      LocalMem(void* p) : ptr(p) {}
+      ~LocalMem() {LocalFree(ptr);}
+      operator void*() {return ptr;}
+      void* takePtr() {
+        void* t = ptr; ptr = 0; return t;
+      }
+      void* ptr;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/LogicalPalette.h b/win/rfb_win32/LogicalPalette.h
new file mode 100644 (file)
index 0000000..204f108
--- /dev/null
@@ -0,0 +1,90 @@
+/* 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 __RFB_WIN32_LOGPALETTE_H__
+#define __RFB_WIN32_LOGPALETTE_H__
+
+#include <windows.h>
+#include <rdr/Exception.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class LogicalPalette {
+    public:
+      LogicalPalette() {
+        BYTE buf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
+        LOGPALETTE* logpal = (LOGPALETTE*)buf;
+        logpal->palVersion = 0x300;
+        logpal->palNumEntries = 256;
+        for (int i=0; i<256;i++) {
+          logpal->palPalEntry[i].peRed = 0;
+          logpal->palPalEntry[i].peGreen = 0;
+          logpal->palPalEntry[i].peBlue = 0;
+          logpal->palPalEntry[i].peFlags = 0;
+        }
+        palette = CreatePalette(logpal);
+        if (!palette)
+          throw rdr::SystemException("failed to CreatePalette", GetLastError());
+      }
+      ~LogicalPalette() {
+        if (palette && !DeleteObject(palette))
+          throw rdr::SystemException("del palette failed", GetLastError());
+      }
+      void setEntries(int start, int count, const Colour* cols) {
+        if (numEntries < count) {
+          ResizePalette(palette, start+count);
+          numEntries = start+count;
+        }
+        PALETTEENTRY* logpal = new PALETTEENTRY[count];
+        for (int i=0; i<count; i++) {
+          logpal[i].peRed = cols[i].r >> 8;
+          logpal[i].peGreen = cols[i].g >> 8;
+          logpal[i].peBlue = cols[i].b >> 8;
+          logpal[i].peFlags = 0;
+        }
+        UnrealizeObject(palette);
+        SetPaletteEntries(palette, start, count, logpal);
+        delete [] logpal;
+      }
+      HPALETTE getHandle() {return palette;}
+    protected:
+      HPALETTE palette;
+      int numEntries;
+    };
+
+    class PaletteSelector {
+    public:
+      PaletteSelector(HDC dc, HPALETTE pal) : device(dc), redrawRequired(false) {
+        oldPal = SelectPalette(dc, pal, FALSE);
+        redrawRequired = RealizePalette(dc) > 0;
+      }
+      ~PaletteSelector() {
+        if (oldPal) SelectPalette(device, oldPal, TRUE);
+      }
+      bool isRedrawRequired() {return redrawRequired;}
+    protected:
+      HPALETTE oldPal;
+      HDC device;
+      bool redrawRequired;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/LowLevelKeyEvents.cxx b/win/rfb_win32/LowLevelKeyEvents.cxx
new file mode 100644 (file)
index 0000000..322d1f4
--- /dev/null
@@ -0,0 +1,96 @@
+/* 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 <rfb_win32/LowLevelKeyEvents.h>
+#include <rfb/Threading.h>
+#include <rfb/LogWriter.h>
+#include <list>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("LowLevelKeyEvents");
+
+
+HHOOK hook = 0;
+std::list<HWND> windows;
+Mutex windowLock;
+
+
+static bool filterKeyEvent(int vkCode) {
+  switch (vkCode) {
+  case VK_LWIN:
+  case VK_RWIN:
+  case VK_SNAPSHOT:
+    return true;
+  case VK_TAB:
+    if (GetAsyncKeyState(VK_MENU) & 0x8000)
+      return true;
+  case VK_ESCAPE:
+    if (GetAsyncKeyState(VK_MENU) & 0x8000)
+      return true;
+    if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+      return true;
+  }
+  return false;
+}
+
+LRESULT CALLBACK LowLevelKeyEventProc(int nCode,
+                                      WPARAM wParam,
+                                      LPARAM lParam) {
+  if (nCode >= 0) {
+    Lock l(windowLock);
+    HWND foreground = GetForegroundWindow();
+    std::list<HWND>::iterator i;
+    for (i=windows.begin(); i!=windows.end(); i++) {
+      if (*i == foreground) {
+        UINT msgType = wParam;
+        KBDLLHOOKSTRUCT* msgInfo = (KBDLLHOOKSTRUCT*)lParam;
+        if (filterKeyEvent(msgInfo->vkCode)) {
+          vlog.debug("filtered event %lx(%lu) %lu", msgInfo->vkCode, msgInfo->vkCode, wParam);
+          PostMessage(*i, wParam, msgInfo->vkCode, (msgInfo->scanCode & 0xff) << 16);
+          return 1;
+        }
+      }
+    }
+  }
+  return CallNextHookEx(hook, nCode, wParam, lParam);
+}
+
+
+bool rfb::win32::enableLowLevelKeyEvents(HWND hwnd) {
+// ***  return false; // *** THIS CODE IS EXPERIMENTAL, SO DISABLED BY DEFAULT!
+  Lock l(windowLock);
+  if (windows.empty() && !hook)
+    hook = SetWindowsHookEx(WH_KEYBOARD_LL, &LowLevelKeyEventProc, GetModuleHandle(0), 0);
+  if (hook)
+    windows.push_back(hwnd);
+  vlog.debug("enable %p -> %s", hwnd, hook ? "success" : "failure");
+  return hook != 0;
+}
+
+void rfb::win32::disableLowLevelKeyEvents(HWND hwnd) {
+  vlog.debug("disable %p", hwnd);
+  Lock l(windowLock);
+  windows.remove(hwnd);
+  if (windows.empty() && hook) {
+    UnhookWindowsHookEx(hook);
+    hook = 0;
+  }
+}
diff --git a/win/rfb_win32/LowLevelKeyEvents.h b/win/rfb_win32/LowLevelKeyEvents.h
new file mode 100644 (file)
index 0000000..40d2ecf
--- /dev/null
@@ -0,0 +1,49 @@
+/* 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.
+ */
+
+// -=- LowLevelKeyEvents.h
+//
+// This interface allows keyboard events destined for a particular window
+// to be intercepted early in the keyboard message queue and posted directly
+// to the window.  This is used to avoid having the operating system process
+// keys such as VK_LWIN, VK_RWIN, etc.
+//
+
+#ifndef __RFB_WIN32_LOW_LEVEL_KEY_EVENTS_H__
+#define __RFB_WIN32_LOW_LEVEL_KEY_EVENTS_H__
+
+namespace rfb {
+
+  namespace win32 {
+
+    // enableLowLevelKeyEvents
+    //   Specifies that keyboard events destined for the specified window should
+    //   be posted directly to the window, rather than being passed via the normal
+    //   Windows keyboard message queue.
+    bool enableLowLevelKeyEvents(HWND hwnd);
+
+    // disableLowLevelKeyEvents
+    //   Causes the specified window to revert to the normal Windows keyboard
+    //   event processing mechanism.
+    void disableLowLevelKeyEvents(HWND hwnd);
+
+  };
+
+};
+
+#endif // __RFB_WIN32_LOW_LEVEL_KEY_EVENTS_H__
diff --git a/win/rfb_win32/ModuleFileName.h b/win/rfb_win32/ModuleFileName.h
new file mode 100644 (file)
index 0000000..2264e89
--- /dev/null
@@ -0,0 +1,40 @@
+/* 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 __RFB_WIN32_MODULE_FILENAME_H__
+#define __RFB_WIN32_MODULE_FILENAME_H__
+
+#include <windows.h>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+  namespace win32 {
+
+    struct ModuleFileName : public TCharArray {
+      ModuleFileName(HMODULE module=0) : TCharArray(MAX_PATH) {
+        if (!module)
+          module = GetModuleHandle(0);
+        if (!GetModuleFileName(module, buf, MAX_PATH))
+          buf[0] = 0;
+      }
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/MonitorInfo.cxx b/win/rfb_win32/MonitorInfo.cxx
new file mode 100644 (file)
index 0000000..03772e9
--- /dev/null
@@ -0,0 +1,205 @@
+/* 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 <rfb_win32/DynamicFn.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/Win32Util.h>
+#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("MonitorInfo");
+
+
+// If we are building in multi-monitor support (i.e. the headers support it)
+//   then do dynamic imports of the required system calls, and provide any
+//   other code that wouldn't otherwise compile.
+#ifdef RFB_HAVE_MONITORINFO
+#include <tchar.h>
+typedef HMONITOR (WINAPI *_MonitorFromWindow_proto)(HWND,DWORD);
+static rfb::win32::DynamicFn<_MonitorFromWindow_proto> _MonitorFromWindow(_T("user32.dll"), "MonitorFromWindow");
+typedef HMONITOR (WINAPI *_MonitorFromRect_proto)(LPCRECT,DWORD);
+static rfb::win32::DynamicFn<_MonitorFromRect_proto> _MonitorFromRect(_T("user32.dll"), "MonitorFromRect");
+typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
+static rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
+typedef BOOL (WINAPI *_EnumDisplayMonitors_proto)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
+static rfb::win32::DynamicFn<_EnumDisplayMonitors_proto> _EnumDisplayMonitors(_T("user32.dll"), "EnumDisplayMonitors");
+static void fillMonitorInfo(HMONITOR monitor, MonitorInfo* mi) {
+  vlog.debug("monitor=%lx", monitor);
+  if (!_GetMonitorInfo.isValid())
+    throw rdr::Exception("no GetMonitorInfo");
+  memset(mi, 0, sizeof(MONITORINFOEXA));
+  mi->cbSize = sizeof(MONITORINFOEXA);
+  if (!(*_GetMonitorInfo)(monitor, mi))
+    throw rdr::SystemException("failed to GetMonitorInfo", GetLastError());
+  vlog.debug("monitor is %d,%d-%d,%d", mi->rcMonitor.left, mi->rcMonitor.top, mi->rcMonitor.right, mi->rcMonitor.bottom);
+  vlog.debug("work area is %d,%d-%d,%d", mi->rcWork.left, mi->rcWork.top, mi->rcWork.right, mi->rcWork.bottom);
+  vlog.debug("device is \"%s\"", mi->szDevice);
+}
+#else
+#pragma message("  NOTE: Not building Multi-Monitor support.")
+#endif
+
+
+MonitorInfo::MonitorInfo(HWND window) {
+  cbSize = sizeof(MonitorInfo);
+  szDevice[0] = 0;
+
+#ifdef RFB_HAVE_MONITORINFO
+  try {
+    if (_MonitorFromWindow.isValid()) {
+      HMONITOR monitor = (*_MonitorFromWindow)(window, MONITOR_DEFAULTTONEAREST);
+      if (!monitor)
+        throw rdr::SystemException("failed to get monitor", GetLastError());
+      fillMonitorInfo(monitor, this);
+      return;
+    }
+  } catch (rdr::Exception& e) {
+    vlog.error(e.str());
+  }
+#endif
+
+  // Legacy fallbacks - just return the desktop settings
+  vlog.debug("using legacy fall-backs");
+  HWND desktop = GetDesktopWindow();
+  GetWindowRect(desktop, &rcMonitor);
+  SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
+  dwFlags = 0;
+}
+
+MonitorInfo::MonitorInfo(const RECT& r) {
+  cbSize = sizeof(MonitorInfo);
+  szDevice[0] = 0;
+
+#ifdef RFB_HAVE_MONITORINFO
+  try {
+    if (_MonitorFromRect.isValid()) {
+      HMONITOR monitor = (*_MonitorFromRect)(&r, MONITOR_DEFAULTTONEAREST);
+      if (!monitor)
+        throw rdr::SystemException("failed to get monitor", GetLastError());
+      fillMonitorInfo(monitor, this);
+      return;
+    }
+  } catch (rdr::Exception& e) {
+    vlog.error(e.str());
+  }
+#endif
+
+  // Legacy fallbacks - just return the desktop settings
+  vlog.debug("using legacy fall-backs");
+  HWND desktop = GetDesktopWindow();
+  GetWindowRect(desktop, &rcMonitor);
+  SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
+  dwFlags = 0;
+}
+
+
+#ifdef RFB_HAVE_MONITORINFO
+
+struct monitorByNameData {
+  MonitorInfo* info;
+  const char* monitorName;
+};
+
+static BOOL CALLBACK monitorByNameEnumProc(HMONITOR monitor,
+                                    HDC dc,
+                                    LPRECT pos,
+                                    LPARAM d) {
+  monitorByNameData* data = (monitorByNameData*)d;
+  memset(data->info, 0, sizeof(MONITORINFOEXA));
+  data->info->cbSize = sizeof(MONITORINFOEXA);
+  if ((*_GetMonitorInfo)(monitor, data->info)) {
+    if (stricmp(data->monitorName, data->info->szDevice) == 0)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+#endif
+
+MonitorInfo::MonitorInfo(const char* devName) {
+#ifdef RFB_HAVE_MONITORINFO
+  if (!_EnumDisplayMonitors.isValid()) {
+    vlog.debug("EnumDisplayMonitors not found");
+  } else {
+    monitorByNameData data;
+    data.info = this;
+    data.monitorName = devName;
+
+    (*_EnumDisplayMonitors)(0, 0, &monitorByNameEnumProc, (LPARAM)&data);
+    if (stricmp(data.monitorName, szDevice) == 0)
+      return;
+  }
+#endif
+  // If multi-monitor is not built, or not supported by the OS,
+  //   or if the named monitor is not found, revert to the primary monitor.
+  vlog.debug("reverting to primary monitor");
+  cbSize = sizeof(MonitorInfo);
+  szDevice[0] = 0;
+
+  HWND desktop = GetDesktopWindow();
+  GetWindowRect(desktop, &rcMonitor);
+  SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
+  dwFlags = 0;
+}
+
+void MonitorInfo::moveTo(HWND handle) {
+  vlog.debug("moveTo monitor=%s", szDevice);
+
+#ifdef RFB_HAVE_MONITORINFO
+  MonitorInfo mi(handle);
+  if (strcmp(szDevice, mi.szDevice) != 0) {
+    centerWindow(handle, rcWork);
+    clipTo(handle);
+  }
+#endif
+}
+
+void MonitorInfo::clipTo(RECT* r) {
+  vlog.debug("clipTo monitor=%s", szDevice);
+
+  if (r->top < rcWork.top) {
+    r->bottom += rcWork.top - r->top; r->top = rcWork.top;
+  }
+  if (r->left < rcWork.left) {
+    r->right += rcWork.left - r->left; r->left = rcWork.left;
+  }
+  if (r->bottom > rcWork.bottom) {
+    r->top += rcWork.bottom - r->bottom; r->bottom = rcWork.bottom;
+  }
+  if (r->right > rcWork.right) {
+    r->left += rcWork.right - r->right; r->right = rcWork.right;
+  }
+  r->left = max(r->left, rcWork.left);
+  r->right = min(r->right, rcWork.right);
+  r->top = max(r->top, rcWork.top);
+  r->bottom = min(r->bottom, rcWork.bottom);
+}
+
+void MonitorInfo::clipTo(HWND handle) {
+  RECT r;
+  GetWindowRect(handle, &r);
+  clipTo(&r);
+  SetWindowPos(handle, 0, r.left, r.top, r.right-r.left, r.bottom-r.top,
+               SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+}
+
+
diff --git a/win/rfb_win32/MonitorInfo.h b/win/rfb_win32/MonitorInfo.h
new file mode 100644 (file)
index 0000000..acf2775
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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.
+ */
+
+// Helper class used to obtain information about a particular monitor.
+// This class wraps the Windows MONITORINFOEX ASCII structure, providing
+// methods that can safely be called on both multi-monitor aware systems
+// and older "legacy" systems.
+
+
+#ifndef __RFB_WIN32_MONITORINFO_H__
+#define __RFB_WIN32_MONITORINFO_H__
+
+#include <windows.h>
+#ifdef MONITOR_DEFAULTTONULL
+#define RFB_HAVE_MONITORINFO
+#endif
+
+namespace rfb {
+  namespace win32 {
+
+    // Structure containing info on the monitor nearest the window.
+    // Copes with multi-monitor OSes and older ones.
+#ifdef RFB_HAVE_MONITORINFO
+    struct MonitorInfo : MONITORINFOEXA {
+#else
+    struct MonitorInfo {
+      DWORD cbSize;
+      RECT rcMonitor;
+      RECT rcWork;
+      DWORD dwFlags;
+      char szDevice[1]; // Always null...
+#endif
+
+      // Constructor: Obtains monitor info for the monitor that has the
+      //   greatest overlap with the supplied window or rectangle.
+      MonitorInfo(HWND hwnd);
+      MonitorInfo(const RECT& r);
+
+      // Constructor: Obtains monitor info for the name monitor.  Monitor
+      //   names should be those obtained from the MonitorInfo
+      //   szDevice field, and usually look like "\\.\DISPLAY<n>"
+      MonitorInfo(const char* devName);
+
+      // Move the specified window to reside on the monitor.
+      void moveTo(HWND handle);
+
+      // Clip the specified rectangle or window to the monitor's working area.
+      //   The rectangle/window is moved so that as much as possible resides
+      //   on the working area of the monitor, and is then intersected with it.
+      void clipTo(HWND handle);
+      void clipTo(RECT* r);
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/MsgBox.h b/win/rfb_win32/MsgBox.h
new file mode 100644 (file)
index 0000000..5957139
--- /dev/null
@@ -0,0 +1,63 @@
+/* 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 __RFB_WIN32_MSGBOX_H__
+#define __RFB_WIN32_MSGBOX_H__
+
+#include <windows.h>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+  namespace win32 {
+
+    // Define rfb::win32::AppName somewhere in the application.
+    // The MsgBox function will use the specified application name
+    // as the prefix for the message box title.
+    // Message box titles are based on the (standard Win32) flags
+    // passed to the MsgBox helper function.
+
+    extern TStr AppName;
+
+    // Wrapper around Win32 MessageBox()
+    static int MsgBox(HWND parent, const TCHAR* msg, UINT flags) {
+      const TCHAR* msgType = 0;
+      UINT tflags = flags & 0x70;
+      if (tflags == MB_ICONHAND)
+        msgType = _T("Error");
+      else if (tflags == MB_ICONQUESTION)
+        msgType = _T("Question");
+      else if (tflags == MB_ICONEXCLAMATION)
+        msgType = _T("Warning");
+      else if (tflags == MB_ICONASTERISK)
+        msgType = _T("Information");
+      flags |= MB_TOPMOST | MB_SETFOREGROUND;
+      int len = _tcslen(AppName.buf) + 1;
+      if (msgType) len += _tcslen(msgType) + 3;
+      TCharArray title = new TCHAR[len];
+      _tcscpy(title.buf, AppName.buf);
+      if (msgType) {
+        _tcscat(title.buf, _T(" : "));
+        _tcscat(title.buf, msgType);
+      }
+      return MessageBox(parent, msg, title.buf, flags);
+    }
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/MsgWindow.cxx b/win/rfb_win32/MsgWindow.cxx
new file mode 100644 (file)
index 0000000..95bd523
--- /dev/null
@@ -0,0 +1,116 @@
+/* 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.
+ */
+
+// -=- MsgWindow.cxx
+
+#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb/LogWriter.h>
+#include <rdr/Exception.h>
+#include <malloc.h>
+#include <tchar.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("MsgWindow");
+
+//
+// -=- MsgWindowClass
+//
+
+class MsgWindowClass {
+public:
+  MsgWindowClass();
+  ~MsgWindowClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK MsgWindowProc(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);
+  MsgWindow* _this = (MsgWindow*) GetWindowLong(wnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %x", wnd, msg);
+    return SafeDefWindowProc(wnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processMessage(msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+};
+
+MsgWindowClass::MsgWindowClass() : classAtom(0) {
+  WNDCLASS wndClass;
+  wndClass.style = 0;
+  wndClass.lpfnWndProc = MsgWindowProc;
+  wndClass.cbClsExtra = 0;
+  wndClass.cbWndExtra = 0;
+  wndClass.hInstance = instance = GetModuleHandle(0);
+  wndClass.hIcon = 0;
+  wndClass.hCursor = 0;
+  wndClass.hbrBackground = 0;
+  wndClass.lpszMenuName = 0;
+  wndClass.lpszClassName = _T("rfb::win32::MsgWindowClass");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register MsgWindow window class", GetLastError());
+  }
+}
+
+MsgWindowClass::~MsgWindowClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+MsgWindowClass baseClass;
+
+//
+// -=- MsgWindow
+//
+
+MsgWindow::MsgWindow(const TCHAR* name_) : name(tstrDup(name_)), handle(0) {
+  vlog.debug("creating window \"%s\"", (const char*)CStr(name.buf));
+  handle = CreateWindow((const TCHAR*)baseClass.classAtom, name.buf, WS_OVERLAPPED,
+    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)", (const char*)CStr(name.buf), handle);
+}
+
+MsgWindow::~MsgWindow() {
+  if (handle)
+    DestroyWindow(handle);
+  vlog.debug("destroyed window \"%s\" (%x)", (const char*)CStr(name.buf), handle); 
+}
+
+LRESULT
+MsgWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  return SafeDefWindowProc(getHandle(), msg, wParam, lParam);
+}
diff --git a/win/rfb_win32/MsgWindow.h b/win/rfb_win32/MsgWindow.h
new file mode 100644 (file)
index 0000000..92b6cf2
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+// -=- MsgWindow.h
+
+// Base-class for any hidden message-handling windows used in the rfb::win32
+// implementation.
+
+#ifndef __RFB_WIN32_MSG_WINDOW_H__
+#define __RFB_WIN32_MSG_WINDOW_H__
+
+#include <windows.h>
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class MsgWindow {
+    public:
+      MsgWindow(const TCHAR* _name);
+      virtual ~MsgWindow();
+
+      const TCHAR* getName() {return name.buf;}
+      HWND getHandle() const {return handle;}
+
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+    protected:
+      TCharArray name;
+      HWND handle;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_MSG_WINDOW_H__
diff --git a/win/rfb_win32/OSVersion.cxx b/win/rfb_win32/OSVersion.cxx
new file mode 100644 (file)
index 0000000..3d74c95
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+// -=- OSVersion.cxx
+
+#include <rfb_win32/OSVersion.h>
+#include <rdr/Exception.h>
+#include <tchar.h>
+
+using namespace rfb;
+using namespace win32;
+
+
+OSVersionInfo::OSVersionInfo() {
+  // Get OS Version Info
+  ZeroMemory(static_cast<OSVERSIONINFO*>(this), sizeof(this));
+  dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  if (!GetVersionEx(this))
+    throw rdr::SystemException("unable to get system version info", GetLastError());
+
+  // Set the special extra flags
+  isPlatformNT = dwPlatformId == VER_PLATFORM_WIN32_NT;
+  isPlatformWindows = dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;
+
+  cannotSwitchDesktop = isPlatformNT && (dwMajorVersion==4) &&
+    ((_tcscmp(szCSDVersion, _T("")) == 0) ||
+     (_tcscmp(szCSDVersion, _T("Service Pack 1")) == 0) ||
+     (_tcscmp(szCSDVersion, _T("Service Pack 2")) == 0));
+
+}
+
+OSVersionInfo rfb::win32::osVersion;
diff --git a/win/rfb_win32/OSVersion.h b/win/rfb_win32/OSVersion.h
new file mode 100644 (file)
index 0000000..18ec003
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+// -=- OSVersion.h
+
+// Operating system version info.
+// GetVersionInfo is called once at process initialisation, and any
+// extra flags (such as isWinNT) are calculated and saved at that
+// point.  It is assumed that the OS Version seldom changes during a
+// program's execution...
+
+#ifndef __RFB_WIN32_OS_VERSION_H__
+#define __RFB_WIN32_OS_VERSION_H__
+
+#include <windows.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    extern struct OSVersionInfo : OSVERSIONINFO {
+      OSVersionInfo();
+
+      // Is the OS one of the NT family (NT 3.51, NT4.0, 2K, XP, etc.)?
+      bool isPlatformNT;
+      // Is one of the Windows family?
+      bool isPlatformWindows;
+
+      // Is this OS one of those that blue-screens when grabbing another desktop (NT4 pre SP3)?
+      bool cannotSwitchDesktop;
+
+    } osVersion;
+
+  };
+
+};
+
+#endif // __RFB_WIN32_OS_VERSION_H__
diff --git a/win/rfb_win32/ProgressControl.cxx b/win/rfb_win32/ProgressControl.cxx
new file mode 100644 (file)
index 0000000..85bd15f
--- /dev/null
@@ -0,0 +1,97 @@
+/* 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- ProgressControl.cxx
+
+#include <rfb_win32/ProgressControl.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+#define MAX_RANGE 0xFFFF
+
+ProgressControl::ProgressControl(HWND hwndProgress)
+{
+  m_hwndProgress = hwndProgress;
+  
+  m_dw64MaxValue = 0;
+  m_dw64CurrentValue = 0;
+}
+
+ProgressControl::~ProgressControl()
+{
+}
+
+bool
+ProgressControl::init(DWORD64 maxValue, DWORD64 position)
+{
+  if (m_dw64CurrentValue > m_dw64MaxValue) return false;
+  
+  m_dw64CurrentValue = position;
+  m_dw64MaxValue = maxValue;
+  
+  if (!SendMessage(m_hwndProgress, PBM_SETRANGE, (WPARAM) 0, MAKELPARAM(0, MAX_RANGE))) 
+    return false;
+  
+  return true;
+}
+
+bool
+ProgressControl::clear()
+{
+  m_dw64CurrentValue = 0;
+  return show();
+}
+
+bool
+ProgressControl::increase(DWORD64 value)
+{
+  if ((m_dw64MaxValue - m_dw64CurrentValue) > value) {
+    m_dw64CurrentValue += value;
+  } else {
+    m_dw64CurrentValue = m_dw64MaxValue;
+  }
+  return show();
+}
+
+bool
+ProgressControl::show()
+{
+  DWORD curPos;
+  if (m_dw64MaxValue != 0) {
+    curPos = (DWORD) ((m_dw64CurrentValue * MAX_RANGE) / m_dw64MaxValue);
+  } else {
+    curPos = 0;
+  }
+  
+  if (!SendMessage(m_hwndProgress, PBM_SETPOS, (WPARAM) curPos, (LPARAM) 0))
+    return false;
+  
+  return true;
+}
+
+int 
+ProgressControl::getCurrentPercent()
+{
+  if (m_dw64MaxValue == 0) return 0;
+
+  return ((int) ((m_dw64CurrentValue * 100) / m_dw64MaxValue));
+}
\ No newline at end of file
diff --git a/win/rfb_win32/ProgressControl.h b/win/rfb_win32/ProgressControl.h
new file mode 100644 (file)
index 0000000..ceeb153
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- ProgressControl.h
+
+#ifndef __RFB_WIN32_PROGRESSCONTROL_H__
+#define __RFB_WIN32_PROGRESSCONTROL_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+namespace rfb {
+  namespace win32 {
+    class ProgressControl
+    {
+    public:
+      ProgressControl(HWND hwndProgress);
+      ~ProgressControl();
+      
+      bool init(DWORD64 maxValue, DWORD64 position);
+      
+      bool increase(DWORD64 value);
+      bool clear();
+
+      int getCurrentPercent();
+      
+    private:
+      HWND m_hwndProgress;
+      
+      DWORD64 m_dw64MaxValue;
+      DWORD64 m_dw64CurrentValue;
+      
+      bool show();
+    };
+  }
+}
+
+#endif // __RFB_WIN32_PROGRESSCONTROL_H__
diff --git a/win/rfb_win32/RegConfig.cxx b/win/rfb_win32/RegConfig.cxx
new file mode 100644 (file)
index 0000000..dd1c3b0
--- /dev/null
@@ -0,0 +1,114 @@
+/* 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.
+ */
+
+// -=- RegConfig.cxx
+
+#include <malloc.h>
+
+#include <rfb_win32/RegConfig.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+//#include <rdr/HexOutStream.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+static LogWriter vlog("RegConfig");
+
+
+RegConfig::RegConfig(EventManager* em) : eventMgr(em), event(CreateEvent(0, TRUE, FALSE, 0)), callback(0) {
+  if (em->addEvent(event, this))
+    eventMgr = em;
+}
+
+RegConfig::~RegConfig() {
+  if (eventMgr)
+    eventMgr->removeEvent(event);
+}
+
+bool RegConfig::setKey(const HKEY rootkey, const TCHAR* keyname) {
+  try {
+    key.createKey(rootkey, keyname);
+    processEvent(event);
+    return true;
+  } catch (rdr::Exception& e) {
+    vlog.debug(e.str());
+    return false;
+  }
+}
+
+void RegConfig::loadRegistryConfig(RegKey& key) {
+  DWORD i = 0;
+  try {
+    while (1) {
+      TCharArray name = tstrDup(key.getValueName(i++));
+      if (!name.buf) break;
+      TCharArray value = key.getRepresentation(name.buf);
+      if (!value.buf || !Configuration::setParam(CStr(name.buf), CStr(value.buf)))
+        vlog.info("unable to process %s", CStr(name.buf));
+    }
+  } catch (rdr::SystemException& e) {
+    if (e.err != 6)
+      vlog.error(e.str());
+  }
+}
+
+void RegConfig::processEvent(HANDLE event_) {
+  vlog.info("registry changed");
+
+  // Reinstate the registry change notifications
+  ResetEvent(event);
+  key.awaitChange(true, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET, event);
+
+  // Load settings
+  loadRegistryConfig(key);
+
+  // Notify the callback, if supplied
+  if (callback)
+    callback->regConfigChanged();
+}
+
+
+RegConfigThread::RegConfigThread() : Thread("RegConfigThread"), config(&eventMgr) {
+}
+
+RegConfigThread::~RegConfigThread() {
+  join();
+}
+
+bool RegConfigThread::start(const HKEY rootKey, const TCHAR* keyname) {
+  if (config.setKey(rootKey, keyname)) {
+    Thread::start();
+    return true;
+  }
+  return false;
+}
+
+void RegConfigThread::run() {
+  DWORD result = 0;
+  MSG msg;
+  while ((result = eventMgr.getMessage(&msg, 0, 0, 0)) > 0) {}
+  if (result < 0)
+    throw rdr::SystemException("RegConfigThread failed", GetLastError());
+}
+
+Thread* RegConfigThread::join() {
+  PostThreadMessage(getThreadId(), WM_QUIT, 0, 0);
+  return Thread::join();
+}
diff --git a/win/rfb_win32/RegConfig.h b/win/rfb_win32/RegConfig.h
new file mode 100644 (file)
index 0000000..e9c01b1
--- /dev/null
@@ -0,0 +1,84 @@
+/* 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.
+ */
+
+// -=- RegConfig.h
+
+// Class which monitors the registry and reads in the registry settings
+// whenever they change, or are added or removed.
+
+#ifndef __RFB_WIN32_REG_CONFIG_H__
+#define __RFB_WIN32_REG_CONFIG_H__
+
+#include <rfb/Threading.h>
+#include <rfb/Configuration.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/EventManager.h>
+#include <rfb_win32/Handle.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class RegConfig : EventHandler {
+    public:
+      RegConfig(EventManager* em);
+      ~RegConfig();
+
+      // Specify the registry key to read Configuration items from
+      bool setKey(const HKEY rootkey, const TCHAR* keyname);
+
+      // Support for a callback, run in the RegConfig host thread whenever
+      // the registry configuration changes
+      class Callback {
+      public:
+        virtual ~Callback() {}
+        virtual void regConfigChanged() = 0;
+      };
+      void setCallback(Callback* cb) { callback = cb; }
+
+      // Read entries from the specified key into the Configuration
+      static void loadRegistryConfig(RegKey& key);
+    protected:
+      // EventHandler interface and trigger event
+      virtual void processEvent(HANDLE event);
+
+      EventManager* eventMgr;
+      Handle event;
+      Callback* callback;
+      RegKey key;
+    };
+
+    class RegConfigThread : Thread {
+    public:
+      RegConfigThread();
+      ~RegConfigThread();
+
+      // Start the thread, reading from the specified key
+      bool start(const HKEY rootkey, const TCHAR* keyname);
+    protected:
+      void run();
+      Thread* join();
+      EventManager eventMgr;
+      RegConfig config;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_REG_CONFIG_H__
diff --git a/win/rfb_win32/Registry.cxx b/win/rfb_win32/Registry.cxx
new file mode 100644 (file)
index 0000000..4ece4ba
--- /dev/null
@@ -0,0 +1,316 @@
+/* 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.
+ */
+
+// -=- Registry.cxx
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Security.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rdr/MemOutStream.h>
+#include <rdr/HexOutstream.h>
+#include <rdr/HexInStream.h>
+#include <stdlib.h>
+#include <rfb/LogWriter.h>
+
+// These flags are required to control access control inheritance,
+// but are not defined by VC6's headers.  These definitions comes
+// from the Microsoft Platform SDK.
+#ifndef PROTECTED_DACL_SECURITY_INFORMATION
+#define PROTECTED_DACL_SECURITY_INFORMATION     (0x80000000L)
+#endif
+#ifndef UNPROTECTED_DACL_SECURITY_INFORMATION
+#define UNPROTECTED_DACL_SECURITY_INFORMATION     (0x20000000L)
+#endif
+
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+static LogWriter vlog("Registry");
+
+
+RegKey::RegKey() : key(0), freeKey(false), valueNameBufLen(0) {}
+
+RegKey::RegKey(const HKEY k) : key(0), freeKey(false), valueNameBufLen(0) {
+  LONG result = RegOpenKeyEx(k, 0, 0, KEY_ALL_ACCESS, &key);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegOpenKeyEx(HKEY)", result);
+  vlog.debug("duplicated %x to %x", k, key);
+  freeKey = true;
+}
+
+RegKey::RegKey(const RegKey& k) : key(0), freeKey(false), valueNameBufLen(0) {
+  LONG result = RegOpenKeyEx(k.key, 0, 0, KEY_ALL_ACCESS, &key);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegOpenKeyEx(RegKey&)", result);
+  vlog.debug("duplicated %x to %x", k.key, key);
+  freeKey = true;
+}
+
+RegKey::~RegKey() {
+  close();
+}
+
+
+void RegKey::setHKEY(HKEY k, bool fK) {
+  vlog.debug("setHKEY(%x,%d)", k, (int)fK);
+  close();
+  freeKey = fK;
+  key = k;
+}
+
+
+bool RegKey::createKey(const RegKey& root, const TCHAR* name) {
+  close();
+  LONG result = RegCreateKey(root.key, name, &key);
+  if (result != ERROR_SUCCESS) {
+    vlog.error("RegCreateKey(%x, %s): %x", root.key, name, result);
+    throw rdr::SystemException("RegCreateKeyEx", result);
+  }
+  vlog.debug("createKey(%x,%s) = %x", root.key, (const char*)CStr(name), key);
+  freeKey = true;
+  return true;
+}
+
+void RegKey::openKey(const RegKey& root, const TCHAR* name, bool readOnly) {
+  close();
+  LONG result = RegOpenKeyEx(root.key, name, 0, readOnly ? KEY_READ : KEY_ALL_ACCESS, &key);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegOpenKeyEx (open)", result);
+  vlog.debug("openKey(%x,%s,%s) = %x", root.key, (const char*)CStr(name),
+                readOnly ? "ro" : "rw", key);
+  freeKey = true;
+}
+
+void RegKey::setDACL(const PACL acl, bool inherit) {
+  DWORD result;
+  typedef DWORD (WINAPI *_SetSecurityInfo_proto) (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID, PSID, PACL, PACL);
+  DynamicFn<_SetSecurityInfo_proto> _SetSecurityInfo(_T("advapi32.dll"), "SetSecurityInfo");
+  if (!_SetSecurityInfo.isValid())
+    throw rdr::SystemException("RegKey::setDACL failed", ERROR_CALL_NOT_IMPLEMENTED);
+  if ((result = (*_SetSecurityInfo)(key, SE_REGISTRY_KEY,
+    DACL_SECURITY_INFORMATION |
+    (inherit ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION),
+    0, 0, acl, 0)) != ERROR_SUCCESS)
+    throw rdr::SystemException("RegKey::setDACL failed", result);
+}
+
+void RegKey::close() {
+  if (freeKey) {
+    vlog.debug("RegCloseKey(%x)", key);
+    RegCloseKey(key);
+    key = 0;
+  }
+}
+
+void RegKey::deleteKey(const TCHAR* name) const {
+  LONG result = RegDeleteKey(key, name);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegDeleteKey", result);
+}
+
+void RegKey::deleteValue(const TCHAR* name) const {
+  LONG result = RegDeleteValue(key, name);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegDeleteValue", result);
+}
+
+void RegKey::awaitChange(bool watchSubTree, DWORD filter, HANDLE event) const {
+  LONG result = RegNotifyChangeKeyValue(key, watchSubTree, filter, event, event != 0);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegNotifyChangeKeyValue", result);
+}
+
+
+RegKey::operator HKEY() const {return key;}
+
+
+void RegKey::setExpandString(const TCHAR* valname, const TCHAR* value) const {
+  LONG result = RegSetValueEx(key, valname, 0, REG_EXPAND_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR));
+  if (result != ERROR_SUCCESS) throw rdr::SystemException("setExpandString", result);
+}
+
+void RegKey::setString(const TCHAR* valname, const TCHAR* value) const {
+  LONG result = RegSetValueEx(key, valname, 0, REG_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR));
+  if (result != ERROR_SUCCESS) throw rdr::SystemException("setString", result);
+}
+
+void RegKey::setBinary(const TCHAR* valname, const void* value, int length) const {
+  LONG result = RegSetValueEx(key, valname, 0, REG_BINARY, (const BYTE*)value, length);
+  if (result != ERROR_SUCCESS) throw rdr::SystemException("setBinary", result);
+}
+
+void RegKey::setInt(const TCHAR* valname, int value) const {
+  LONG result = RegSetValueEx(key, valname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
+  if (result != ERROR_SUCCESS) throw rdr::SystemException("setInt", result);
+}
+
+void RegKey::setBool(const TCHAR* valname, bool value) const {
+  setInt(valname, value ? 1 : 0);
+}
+
+TCHAR* RegKey::getString(const TCHAR* valname) const {return getRepresentation(valname);}
+TCHAR* RegKey::getString(const TCHAR* valname, const TCHAR* def) const {
+  try {
+    return getString(valname);
+  } catch(rdr::Exception) {
+    return tstrDup(def);
+  }
+}
+
+void RegKey::getBinary(const TCHAR* valname, void** data, int* length) const {
+  TCharArray hex = getRepresentation(valname);
+  if (!rdr::HexInStream::hexStrToBin(CStr(hex.buf), (char**)data, length))
+    throw rdr::Exception("getBinary failed");
+}
+void RegKey::getBinary(const TCHAR* valname, void** data, int* length, void* def, int deflen) const {
+  try {
+    getBinary(valname, data, length);
+  } catch(rdr::Exception) {
+    if (deflen) {
+      *data = new char[deflen];
+      memcpy(*data, def, deflen);
+    } else
+      *data = 0;
+    *length = deflen;
+  }
+}
+
+int RegKey::getInt(const TCHAR* valname) const {
+  TCharArray tmp = getRepresentation(valname);
+  return _ttoi(tmp.buf);
+}
+int RegKey::getInt(const TCHAR* valname, int def) const {
+  try {
+    return getInt(valname);
+  } catch(rdr::Exception) {
+    return def;
+  }
+}
+
+bool RegKey::getBool(const TCHAR* valname) const {
+  return getInt(valname) > 0;
+}
+bool RegKey::getBool(const TCHAR* valname, bool def) const {
+  return getInt(valname, def ? 1 : 0) > 0;
+}
+
+static inline TCHAR* terminateData(char* data, int length)
+{
+  // We must terminate the string, just to be sure.  Stupid Win32...
+  int len = length/sizeof(TCHAR);
+  TCharArray str(len+1);
+  memcpy(str.buf, data, length);
+  str.buf[len] = 0;
+  return str.takeBuf();
+}
+
+TCHAR* RegKey::getRepresentation(const TCHAR* valname) const {
+  DWORD type, length;
+  LONG result = RegQueryValueEx(key, valname, 0, &type, 0, &length);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("get registry value length", result);
+  CharArray data(length);
+  result = RegQueryValueEx(key, valname, 0, &type, (BYTE*)data.buf, &length);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("get registry value", result);
+
+  switch (type) {
+  case REG_BINARY:
+    {
+      TCharArray hex = rdr::HexOutStream::binToHexStr(data.buf, length);
+      return hex.takeBuf();
+    }
+  case REG_SZ:
+    if (length) {
+      return terminateData(data.buf, length);
+    } else {
+      return tstrDup(_T(""));
+    }
+  case REG_DWORD:
+    {
+      TCharArray tmp(16);
+      _stprintf(tmp.buf, _T("%u"), *((DWORD*)data.buf));
+      return tmp.takeBuf();
+    }
+  case REG_EXPAND_SZ:
+    {
+    if (length) {
+      TCharArray str(terminateData(data.buf, length));
+      DWORD required = ExpandEnvironmentStrings(str.buf, 0, 0);
+      if (required==0)
+        throw rdr::SystemException("ExpandEnvironmentStrings", GetLastError());
+      TCharArray result(required);
+      length = ExpandEnvironmentStrings(str.buf, result.buf, required);
+      if (required<length)
+        rdr::Exception("unable to expand environment strings");
+      return result.takeBuf();
+    } else {
+      return tstrDup(_T(""));
+    }
+    }
+  default:
+    throw rdr::Exception("unsupported registry type");
+  }
+}
+
+bool RegKey::isValue(const TCHAR* valname) const {
+  try {
+    TCharArray tmp = getRepresentation(valname);
+    return true;
+  } catch(rdr::Exception) {
+    return false;
+  }
+}
+
+const TCHAR* RegKey::getValueName(int i) {
+  DWORD maxValueNameLen;
+  LONG result = RegQueryInfoKey(key, 0, 0, 0, 0, 0, 0, 0, &maxValueNameLen, 0, 0, 0);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegQueryInfoKey", result);
+  if (valueNameBufLen < maxValueNameLen + 1) {
+    valueNameBufLen = maxValueNameLen + 1;
+    delete [] valueName.buf;
+    valueName.buf = new TCHAR[valueNameBufLen];
+  }
+  DWORD length = valueNameBufLen;
+  result = RegEnumValue(key, i, valueName.buf, &length, NULL, 0, 0, 0);
+  if (result == ERROR_NO_MORE_ITEMS) return 0;
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegEnumValue", result);
+  return valueName.buf;
+}
+
+const TCHAR* RegKey::getKeyName(int i) {
+  DWORD maxValueNameLen;
+  LONG result = RegQueryInfoKey(key, 0, 0, 0, 0, &maxValueNameLen, 0, 0, 0, 0, 0, 0);
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegQueryInfoKey", result);
+  if (valueNameBufLen < maxValueNameLen + 1) {
+    valueNameBufLen = maxValueNameLen + 1;
+    delete [] valueName.buf;
+    valueName.buf = new TCHAR[valueNameBufLen];
+  }
+  DWORD length = valueNameBufLen;
+  result = RegEnumKeyEx(key, i, valueName.buf, &length, NULL, 0, 0, 0);
+  if (result == ERROR_NO_MORE_ITEMS) return 0;
+  if (result != ERROR_SUCCESS)
+    throw rdr::SystemException("RegEnumKey", result);
+  return valueName.buf;
+}
diff --git a/win/rfb_win32/Registry.h b/win/rfb_win32/Registry.h
new file mode 100644 (file)
index 0000000..68d535c
--- /dev/null
@@ -0,0 +1,112 @@
+/* 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.
+ */
+// -=- Registry.h
+
+// C++ wrappers around the Win32 Registry APIs
+
+#ifndef __RFB_WIN32_REGISTRY_H__
+#define __RFB_WIN32_REGISTRY_H__
+
+#include <windows.h>
+#include <rfb_win32/Security.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class RegKey {
+    public:
+      // No key open
+      RegKey();
+
+      // Duplicate the specified existing key
+      RegKey(const HKEY k);
+      RegKey(const RegKey& k);
+
+      // Calls close() internally
+      ~RegKey();
+
+      void setHKEY(HKEY key, bool freeKey);
+    private:
+      RegKey& operator=(const RegKey& k);
+      HKEY& operator=(const HKEY& k);
+    public:
+
+      // Returns true if key was created, false if already existed
+      bool createKey(const RegKey& root, const TCHAR* name);
+
+      // Opens key if it exists, or raises an exception if not
+      void openKey(const RegKey& root, const TCHAR* name, bool readOnly=false);
+
+      // Set the (discretionary) access control list for the key
+      void setDACL(const PACL acl, bool inheritFromParent=true);
+
+      // Closes current key, if required
+      void close();
+
+      // Delete a subkey/value
+      void deleteKey(const TCHAR* name) const;
+      void deleteValue(const TCHAR* name) const;
+
+
+      // Block waiting for a registry change, OR return immediately and notify the
+      // event when there is a change, if specified
+      void awaitChange(bool watchSubTree, DWORD filter, HANDLE event=0) const;
+
+      void setExpandString(const TCHAR* valname, const TCHAR* s) const;
+      void setString(const TCHAR* valname, const TCHAR* s) const;
+      void setBinary(const TCHAR* valname, const void* data, int length) const;
+      void setInt(const TCHAR* valname, int i) const;
+      void setBool(const TCHAR* valname, bool b) const;
+
+      TCHAR* getString(const TCHAR* valname) const;
+      TCHAR* getString(const TCHAR* valname, const TCHAR* def) const;
+
+      void getBinary(const TCHAR* valname, void** data, int* length) const;
+      void getBinary(const TCHAR* valname, void** data, int* length, void* def, int deflength) const;
+
+      int getInt(const TCHAR* valname) const;
+      int getInt(const TCHAR* valname, int def) const;
+
+      bool getBool(const TCHAR* valname) const;
+      bool getBool(const TCHAR* valname, bool def) const;
+
+      TCHAR* getRepresentation(const TCHAR* valname) const;
+
+      bool isValue(const TCHAR* valname) const;
+
+      // Get the name of value/key number "i"
+      // If there are fewer than "i" values then return 0
+      // NAME IS OWNED BY RegKey OBJECT!
+      const TCHAR* getValueName(int i);
+      const TCHAR* getKeyName(int i);
+
+      operator HKEY() const;
+    protected:
+      HKEY key;
+      bool freeKey;
+      TCharArray valueName;
+      DWORD valueNameBufLen;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_REG_CONFIG_H__
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
new file mode 100644 (file)
index 0000000..0af5064
--- /dev/null
@@ -0,0 +1,524 @@
+/* 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.
+ */
+
+// -=- SDisplay.cxx
+//
+// The SDisplay class encapsulates a particular system display.
+
+#include <rfb_win32/SDisplay.h>
+#include <rfb_win32/Service.h>
+#include <rfb_win32/TsSessions.h>
+#include <rfb_win32/CleanDesktop.h>
+#include <rfb_win32/CurrentUser.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/SDisplayCorePolling.h>
+#include <rfb_win32/SDisplayCoreWMHooks.h>
+#include <rfb_win32/SDisplayCoreDriver.h>
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+
+
+using namespace rdr;
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("SDisplay");
+
+// - SDisplay-specific configuration options
+
+IntParameter rfb::win32::SDisplay::updateMethod("UpdateMethod",
+  "How to discover desktop updates; 0 - Polling, 1 - Application hooking, 2 - Driver hooking.", 1);
+BoolParameter rfb::win32::SDisplay::disableLocalInputs("DisableLocalInputs",
+  "Disable local keyboard and pointer input while the server is in use", false);
+StringParameter rfb::win32::SDisplay::disconnectAction("DisconnectAction",
+  "Action to perform when all clients have disconnected.  (None, Lock, Logoff)", "None");
+StringParameter displayDevice("DisplayDevice",
+  "Display device name of the monitor to be remoted, or empty to export the whole desktop.", "");
+BoolParameter rfb::win32::SDisplay::removeWallpaper("RemoveWallpaper",
+  "Remove the desktop wallpaper when the server is in use.", false);
+BoolParameter rfb::win32::SDisplay::removePattern("RemovePattern",
+  "Remove the desktop background pattern when the server is in use.", false);
+BoolParameter rfb::win32::SDisplay::disableEffects("DisableEffects",
+  "Disable desktop user interface effects when the server is in use.", false);
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// SDisplay
+//
+
+typedef BOOL (WINAPI *_LockWorkStation_proto)();
+DynamicFn<_LockWorkStation_proto> _LockWorkStation(_T("user32.dll"), "LockWorkStation");
+
+// -=- Constructor/Destructor
+
+SDisplay::SDisplay()
+  : server(0), pb(0), device(0),
+    core(0), ptr(0), kbd(0), clipboard(0),
+    inputs(0), monitor(0), cleanDesktop(0), cursor(0),
+    statusLocation(0)
+{
+  updateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
+}
+
+SDisplay::~SDisplay()
+{
+  // XXX when the VNCServer has been deleted with clients active, stop()
+  // doesn't get called - this ought to be fixed in VNCServerST.  In any event,
+  // we should never call any methods on VNCServer once we're being deleted.
+  // This is because it is supposed to be guaranteed that the SDesktop exists
+  // throughout the lifetime of the VNCServer.  So if we're being deleted, then
+  // the VNCServer ought not to exist and therefore we shouldn't invoke any
+  // methods on it.  Setting server to zero here ensures that stop() doesn't
+  // call setPixelBuffer(0) on the server.
+  server = 0;
+  if (core) stop();
+}
+
+
+// -=- SDesktop interface
+
+void SDisplay::start(VNCServer* vs)
+{
+  vlog.debug("starting");
+
+  // Try to make session zero the console session
+  if (!inConsoleSession())
+    setConsoleSession();
+
+  // Start the SDisplay core
+  server = vs;
+  startCore();
+
+  vlog.debug("started");
+
+  if (statusLocation) *statusLocation = true;
+}
+
+void SDisplay::stop()
+{
+  vlog.debug("stopping");
+
+  // If we successfully start()ed then perform the DisconnectAction
+  if (core) {
+    CurrentUserToken cut;
+    CharArray action = disconnectAction.getData();
+    if (stricmp(action.buf, "Logoff") == 0) {
+      if (!cut.h)
+        vlog.info("ignoring DisconnectAction=Logoff - no current user");
+      else
+        ExitWindowsEx(EWX_LOGOFF, 0);
+    } else if (stricmp(action.buf, "Lock") == 0) {
+      if (!cut.h) {
+        vlog.info("ignoring DisconnectAction=Lock - no current user");
+      } else {
+        if (_LockWorkStation.isValid())
+          (*_LockWorkStation)();
+        else
+          ExitWindowsEx(EWX_LOGOFF, 0);
+      }
+    }
+  }
+
+  // Stop the SDisplayCore
+  if (server)
+    server->setPixelBuffer(0);
+  stopCore();
+  server = 0;
+
+  vlog.debug("stopped");
+
+  if (statusLocation) *statusLocation = false;
+}
+
+
+void SDisplay::startCore() {
+
+  // Currently, we just check whether we're in the console session, and
+  //   fail if not
+  if (!inConsoleSession())
+    throw rdr::Exception("Console is not session zero - oreconnect to restore Console sessin");
+  
+  // Switch to the current input desktop
+  if (rfb::win32::desktopChangeRequired()) {
+    if (!rfb::win32::changeDesktop())
+      throw rdr::Exception("unable to switch into input desktop");
+  }
+
+  // Initialise the change tracker and clipper
+  updates.clear();
+  clipper.setUpdateTracker(server);
+
+  // Create the framebuffer object
+  recreatePixelBuffer(true);
+
+  // Create the SDisplayCore
+  updateMethod_ = updateMethod;
+  int tryMethod = updateMethod_;
+  while (!core) {
+    try {
+      if (tryMethod == 2)
+        core = new SDisplayCoreDriver(this, &updates);
+      else if (tryMethod == 1)
+        core = new SDisplayCoreWMHooks(this, &updates);
+      else
+        core = new SDisplayCorePolling(this, &updates);
+      core->setScreenRect(screenRect);
+    } catch (rdr::Exception& e) {
+      delete core; core = 0;
+      if (tryMethod == 0)
+        throw rdr::Exception("unable to access desktop");
+      tryMethod--;
+      vlog.error(e.str());
+    }
+  }
+  vlog.info("Started %s", core->methodName());
+
+  // Start display monitor, clipboard handler and input handlers
+  monitor = new WMMonitor;
+  monitor->setNotifier(this);
+  clipboard = new Clipboard;
+  clipboard->setNotifier(this);
+  ptr = new SPointer;
+  kbd = new SKeyboard;
+  inputs = new WMBlockInput;
+  cursor = new WMCursor;
+
+  // Apply desktop optimisations
+  cleanDesktop = new CleanDesktop;
+  if (removePattern)
+    cleanDesktop->disablePattern();
+  if (removeWallpaper)
+    cleanDesktop->disableWallpaper();
+  if (disableEffects)
+    cleanDesktop->disableEffects();
+  isWallpaperRemoved = removeWallpaper;
+  isPatternRemoved = removePattern;
+  areEffectsDisabled = disableEffects;
+}
+
+void SDisplay::stopCore() {
+  if (core)
+    vlog.info("Stopping %s", core->methodName());
+  delete core; core = 0;
+  delete pb; pb = 0;
+  delete device; device = 0;
+  delete monitor; monitor = 0;
+  delete clipboard; clipboard = 0;
+  delete inputs; inputs = 0;
+  delete ptr; ptr = 0;
+  delete kbd; kbd = 0;
+  delete cleanDesktop; cleanDesktop = 0;
+  delete cursor; cursor = 0;
+  ResetEvent(updateEvent);
+}
+
+
+bool SDisplay::areHooksAvailable() {
+  return WMHooks::areAvailable();
+}
+
+bool SDisplay::isDriverAvailable() {
+  return SDisplayCoreDriver::isAvailable();
+}
+
+
+bool SDisplay::isRestartRequired() {
+  // - We must restart the SDesktop if:
+  // 1. We are no longer in the input desktop.
+  // 2. The any setting has changed.
+
+  // - Check that our session is the Console
+  if (!inConsoleSession())
+    return true;
+
+  // - Check that we are in the input desktop
+  if (rfb::win32::desktopChangeRequired())
+    return true;
+
+  // - Check that the update method setting hasn't changed
+  //   NB: updateMethod reflects the *selected* update method, not
+  //   necessarily the one in use, since we fall back to simpler
+  //   methods if more advanced ones fail!
+  if (updateMethod_ != updateMethod)
+    return true;
+
+  // - Check that the desktop optimisation settings haven't changed
+  //   This isn't very efficient, but it shouldn't change very often!
+  if ((isWallpaperRemoved != removeWallpaper) ||
+      (isPatternRemoved != removePattern) ||
+      (areEffectsDisabled != disableEffects))
+    return true;
+
+  return false;
+}
+
+
+void SDisplay::restartCore() {
+  vlog.info("restarting");
+
+  // Stop the existing Core  related resources
+  stopCore();
+  try {
+    // Start a new Core if possible
+    startCore();
+    vlog.info("restarted");
+  } catch (rdr::Exception& e) {
+    // If startCore() fails then we MUST disconnect all clients,
+    // to cause the server to stop() the desktop.
+    // Otherwise, the SDesktop is in an inconsistent state
+    // and the server will crash.
+    server->closeClients(e.str());
+  }
+}
+
+
+void SDisplay::pointerEvent(const Point& pos, int buttonmask) {
+  if (pb->getRect().contains(pos)) {
+    Point screenPos = pos.translate(screenRect.tl);
+    // - Check that the SDesktop doesn't need restarting
+    if (isRestartRequired())
+      restartCore();
+    if (ptr)
+      ptr->pointerEvent(screenPos, buttonmask);
+  }
+}
+
+void SDisplay::keyEvent(rdr::U32 key, bool down) {
+  // - Check that the SDesktop doesn't need restarting
+  if (isRestartRequired())
+    restartCore();
+  if (kbd)
+    kbd->keyEvent(key, down);
+}
+
+void SDisplay::clientCutText(const char* text, int len) {
+  CharArray clip_sz(len+1);
+  memcpy(clip_sz.buf, text, len);
+  clip_sz.buf[len] = 0;
+  clipboard->setClipText(clip_sz.buf);
+}
+
+
+void SDisplay::framebufferUpdateRequest()
+{
+  SetEvent(updateEvent);
+}
+
+Point SDisplay::getFbSize() {
+  bool startAndStop = !core;
+
+  // If not started, do minimal initialisation to get desktop size.
+  if (startAndStop)
+    recreatePixelBuffer();
+  Point result = Point(pb->width(), pb->height());
+
+  // Destroy the initialised structures.
+  if (startAndStop)
+    stopCore();
+  return result;
+}
+
+
+void
+SDisplay::notifyClipboardChanged(const char* text, int len) {
+  vlog.debug("clipboard text changed");
+  if (server)
+    server->serverCutText(text, len);
+}
+
+
+void
+SDisplay::notifyDisplayEvent(WMMonitor::Notifier::DisplayEventType evt) {
+  switch (evt) {
+  case WMMonitor::Notifier::DisplaySizeChanged:
+    vlog.debug("desktop size changed");
+    recreatePixelBuffer();
+    break;
+  case WMMonitor::Notifier::DisplayPixelFormatChanged:
+    vlog.debug("desktop format changed");
+    recreatePixelBuffer();
+    break;
+  case WMMonitor::Notifier::DisplayColourMapChanged:
+    vlog.debug("desktop colormap changed");
+    pb->updateColourMap();
+    if (server)
+      server->setColourMapEntries();
+    break;
+  default:
+    vlog.error("unknown display event received");
+  }
+}
+
+void
+SDisplay::processEvent(HANDLE event) {
+  if (event == updateEvent) {
+    vlog.write(120, "processEvent");
+    ResetEvent(updateEvent);
+
+    // - If the SDisplay isn't even started then quit now
+    if (!core) {
+      vlog.error("not start()ed");
+      return;
+    }
+
+    // - Ensure that the disableLocalInputs flag is respected
+    inputs->blockInputs(disableLocalInputs);
+
+    // - Only process updates if the server is ready
+    if (server && server->clientsReadyForUpdate()) {
+      bool try_update = false;
+
+      // - Check that the SDesktop doesn't need restarting
+      if (isRestartRequired()) {
+        restartCore();
+        return;
+      }
+
+      // - Flush any updates from the core
+      try {
+        core->flushUpdates();
+      } catch (rdr::Exception& e) {
+        vlog.error(e.str());
+        restartCore();
+        return;
+      }
+
+      // Ensure the cursor is up to date
+      WMCursor::Info info = cursor->getCursorInfo();
+      if (old_cursor != info) {
+        // Update the cursor shape if the visibility has changed
+        bool set_cursor = info.visible != old_cursor.visible;
+        // OR if the cursor is visible and the shape has changed.
+        set_cursor |= info.visible && (old_cursor.cursor != info.cursor);
+
+        // Update the cursor shape
+        if (set_cursor)
+          pb->setCursor(info.visible ? info.cursor : 0, server);
+
+        // Update the cursor position
+        // NB: First translate from Screen coordinates to Desktop
+        Point desktopPos = info.position.translate(screenRect.tl.negate());
+        server->setCursorPos(desktopPos);
+        try_update = true;
+
+        old_cursor = info;
+      }
+
+      // Flush any changes to the server
+      try_update = flushChangeTracker() || try_update;
+      if (try_update) {
+        server->tryUpdate();
+      }
+    }
+    return;
+  }
+  throw rdr::Exception("No such event");
+}
+
+
+// -=- Protected methods
+
+void
+SDisplay::recreatePixelBuffer(bool force) {
+  // Open the specified display device
+  //   If no device is specified, open entire screen using GetDC().
+  //   Opening the whole display with CreateDC doesn't work on multi-monitor
+  //   systems for some reason.
+  DeviceContext* new_device = 0;
+  TCharArray deviceName(displayDevice.getData());
+  if (deviceName.buf[0]) {
+    vlog.info("Attaching to device %s", (const char*)CStr(deviceName.buf));
+    new_device = new DeviceDC(deviceName.buf);
+  }
+  if (!new_device) {
+    vlog.info("Attaching to virtual desktop");
+    new_device = new WindowDC(0);
+  }
+
+  // Get the coordinates of the specified dispay device
+  Rect newScreenRect;
+  if (deviceName.buf[0]) {
+    MonitorInfo info(CStr(deviceName.buf));
+    newScreenRect = Rect(info.rcMonitor.left, info.rcMonitor.top,
+                         info.rcMonitor.right, info.rcMonitor.bottom);
+  } else {
+    newScreenRect = new_device->getClipBox();
+  }
+
+  // If nothing has changed & a recreate has not been forced, delete
+  // the new device context and return
+  if (pb && !force &&
+    newScreenRect.equals(screenRect) &&
+    new_device->getPF().equal(pb->getPF())) {
+    delete new_device;
+    return;
+  }
+
+  // Flush any existing changes to the server
+  flushChangeTracker();
+
+  // Delete the old pixelbuffer and device context
+  vlog.debug("deleting old pixel buffer & device");
+  if (pb)
+    delete pb;
+  if (device)
+    delete device;
+
+  // Create a DeviceFrameBuffer attached to the new device
+  vlog.debug("creating pixel buffer");
+  DeviceFrameBuffer* new_buffer = new DeviceFrameBuffer(*new_device);
+
+  // Replace the old PixelBuffer
+  screenRect = newScreenRect;
+  pb = new_buffer;
+  device = new_device;
+
+  // Initialise the pixels
+  pb->grabRegion(pb->getRect());
+
+  // Prevent future grabRect operations from throwing exceptions
+  pb->setIgnoreGrabErrors(true);
+
+  // Update the clipping update tracker
+  clipper.setClipRect(pb->getRect());
+
+  // Inform the core of the changes
+  if (core)
+    core->setScreenRect(screenRect);
+
+  // Inform the server of the changes
+  if (server)
+    server->setPixelBuffer(pb);
+}
+
+bool SDisplay::flushChangeTracker() {
+  if (updates.is_empty())
+    return false;
+
+  vlog.write(120, "flushChangeTracker");
+
+  // Translate the update coordinates from Screen coords to Desktop
+  updates.translate(screenRect.tl.negate());
+
+  // Clip the updates & flush them to the server
+  updates.copyTo(&clipper);
+  updates.clear();
+  return true;
+}
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
new file mode 100644 (file)
index 0000000..6dbb50a
--- /dev/null
@@ -0,0 +1,163 @@
+/* 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.
+ */
+
+// -=- SDisplay.h
+//
+// The SDisplay class encapsulates a system display.
+
+#ifndef __RFB_SDISPLAY_H__
+#define __RFB_SDISPLAY_H__
+
+#include <rfb/SDesktop.h>
+#include <rfb/UpdateTracker.h>
+#include <rfb/Configuration.h>
+#include <rfb_win32/Handle.h>
+#include <rfb_win32/EventManager.h>
+#include <rfb_win32/SInput.h>
+#include <rfb_win32/Clipboard.h>
+#include <rfb_win32/CleanDesktop.h>
+#include <rfb_win32/WMCursor.h>
+#include <rfb_win32/WMNotifier.h>
+#include <rfb_win32/DeviceFrameBuffer.h>
+#include <rfb_win32/DeviceContext.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    //
+    // -=- SDisplay
+    //
+
+    class SDisplayCore {
+    public:
+      virtual ~SDisplayCore() {};
+      virtual void setScreenRect(const Rect& screenRect_) = 0;
+      virtual void flushUpdates() = 0;
+      virtual const char* methodName() const = 0;
+    };
+
+    class SDisplay : public SDesktop,
+      WMMonitor::Notifier,
+      Clipboard::Notifier,
+      public EventHandler
+    {
+    public:
+      SDisplay();
+      virtual ~SDisplay();
+
+      // -=- SDesktop interface
+
+      virtual void start(VNCServer* vs);
+      virtual void stop();
+      virtual void pointerEvent(const Point& pos, int buttonmask);
+      virtual void keyEvent(rdr::U32 key, bool down);
+      virtual void clientCutText(const char* str, int len);
+      virtual void framebufferUpdateRequest();
+      virtual Point getFbSize();
+
+      // -=- Clipboard
+      
+      virtual void notifyClipboardChanged(const char* text, int len);
+
+      // -=- Display events
+      
+      virtual void notifyDisplayEvent(WMMonitor::Notifier::DisplayEventType evt);
+
+      // -=- EventHandler interface
+
+      HANDLE getUpdateEvent() {return updateEvent;}
+      virtual void processEvent(HANDLE event);
+
+      // -=- Notification of whether or not SDisplay is started
+
+      void setStatusLocation(bool* status) {statusLocation = status;}
+
+      friend class SDisplayCore;
+
+      static IntParameter updateMethod;
+      static BoolParameter disableLocalInputs;
+      static StringParameter disconnectAction;
+      static BoolParameter removeWallpaper;
+      static BoolParameter removePattern;
+      static BoolParameter disableEffects;
+
+      // -=- Use by VNC Config to determine whether hooks, driver, etc are available
+      static bool areHooksAvailable();
+      static bool isDriverAvailable();
+
+
+    protected:
+      bool isRestartRequired();
+      void startCore();
+      void stopCore();
+      void restartCore();
+      void recreatePixelBuffer(bool force=false);
+      bool flushChangeTracker();  // true if flushed, false if empty
+
+      VNCServer* server;
+
+      // -=- Display pixel buffer
+      DeviceFrameBuffer* pb;
+      DeviceContext* device;
+
+      // -=- The coordinates of Window's entire virtual Screen
+      Rect screenRect;
+
+      // -=- All changes are collected in UN-CLIPPED Display coords and merged
+      //     When they are to be flushed to the VNCServer, they are changed
+      //     to server coords and clipped appropriately.
+      SimpleUpdateTracker updates;
+      ClippingUpdateTracker clipper;
+
+      // -=- Internal SDisplay implementation
+      SDisplayCore* core;
+      int updateMethod_;
+
+      // Inputs
+      SPointer* ptr;
+      SKeyboard* kbd;
+      Clipboard* clipboard;
+      WMBlockInput* inputs;
+
+      // Desktop state
+      WMMonitor* monitor;
+
+      // Desktop optimisation
+      CleanDesktop* cleanDesktop;
+      bool isWallpaperRemoved;
+      bool isPatternRemoved;
+      bool areEffectsDisabled;
+
+      // Cursor
+      WMCursor* cursor;
+      WMCursor::Info old_cursor;
+      Region old_cursor_region;
+      Point cursor_renderpos;
+
+      // -=- Event signalled to trigger an update to be flushed
+      Handle updateEvent;
+
+      // -=- Where to write the active/inactive indicator to
+      bool* statusLocation;
+    };
+
+  }
+}
+
+#endif // __RFB_SDISPLAY_H__
diff --git a/win/rfb_win32/SDisplayCoreDriver.h b/win/rfb_win32/SDisplayCoreDriver.h
new file mode 100644 (file)
index 0000000..5fea75c
--- /dev/null
@@ -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.
+ */
+
+// -=- SDisplayCoreDriver.h
+//
+// Placeholder for SDisplayCore mirror-driver implementation.
+
+#ifndef __RFB_SDISPLAY_CORE_DRIVER_H__
+#define __RFB_SDISPLAY_CORE_DRIVER_H__
+
+#include <rfb_win32/SDisplay.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class SDisplayCoreDriver: public SDisplayCore {
+    public:
+      SDisplayCoreDriver(SDisplay* display, UpdateTracker* ut) {
+        throw rdr::Exception("Not supported");
+      }
+
+      // - Called by SDisplay to inform Core of the screen size
+      virtual void setScreenRect(const Rect& screenRect_) {}
+
+      // - Called by SDisplay to flush updates to the specified tracker
+      virtual void flushUpdates() {}
+
+      virtual const char* methodName() const { return "VNC Mirror Driver"; }
+
+      // - Determine whether the display driver is installed & usable
+      static bool isAvailable() { return false; }
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/SDisplayCorePolling.cxx b/win/rfb_win32/SDisplayCorePolling.cxx
new file mode 100644 (file)
index 0000000..fc57ecd
--- /dev/null
@@ -0,0 +1,81 @@
+/* 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.
+ */
+
+// -=- SDisplayCorePolling.cxx
+
+#include <rfb_win32/SDisplayCorePolling.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("SDisplayCorePolling");
+
+const int POLLING_SEGMENTS = 16;
+
+const int SDisplayCorePolling::pollTimerId = 1;
+
+SDisplayCorePolling::SDisplayCorePolling(SDisplay* d, UpdateTracker* ut, int pollInterval_)
+  : MsgWindow(_T("rfb::win32::SDisplayCorePolling")), updateTracker(ut),
+  pollTimer(getHandle(), pollTimerId), pollNextStrip(false), display(d) {
+  pollInterval = max(10, (pollInterval_ / POLLING_SEGMENTS));
+  copyrect.setUpdateTracker(ut);
+}
+
+SDisplayCorePolling::~SDisplayCorePolling() {
+}
+
+LRESULT SDisplayCorePolling::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  if (msg == WM_TIMER && wParam == pollTimerId) {
+    pollNextStrip = true;
+    SetEvent(display->getUpdateEvent());
+    return 0;
+  }
+  return MsgWindow::processMessage(msg, wParam, lParam);
+}
+
+void SDisplayCorePolling::setScreenRect(const Rect& screenRect_) {
+  vlog.info("setScreenRect");
+  screenRect = screenRect_;
+  pollIncrementY = (screenRect.height()+POLLING_SEGMENTS-1)/POLLING_SEGMENTS;
+  pollNextY = screenRect.tl.y;
+  pollTimer.start(pollInterval);
+}
+
+void SDisplayCorePolling::flushUpdates() {
+  vlog.write(120, "flushUpdates");
+
+  // Check for window movement
+  while (copyrect.processEvent()) {}
+
+  if (pollNextStrip) {
+    // Poll the next strip of the screen (in Screen coordinates)
+    pollNextStrip = false;
+    Rect pollrect = screenRect;
+    if (pollNextY >= pollrect.br.y) {
+      // Yes.  Reset the counter and return
+      pollNextY = pollrect.tl.y;
+    } else {
+      // No.  Poll the next section
+      pollrect.tl.y = pollNextY;
+      pollNextY += pollIncrementY;
+      pollrect.br.y = min(pollNextY, pollrect.br.y);
+      updateTracker->add_changed(pollrect);
+    }
+  }
+}
diff --git a/win/rfb_win32/SDisplayCorePolling.h b/win/rfb_win32/SDisplayCorePolling.h
new file mode 100644 (file)
index 0000000..9e1b5ad
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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.
+ */
+
+// -=- SDisplayCorePolling.h
+//
+// SDisplayCore implementation that simply polls the screen, in sections,
+// in order to detect changes.  This Core will signal the SDisplay's
+// updateEvent regularly, causing it to call the Core back to propagate
+// changes to the VNC Server.
+
+
+#ifndef __RFB_SDISPLAY_CORE_POLLING_H__
+#define __RFB_SDISPLAY_CORE_POLLING_H__
+
+#include <rfb_win32/SDisplay.h>
+#include <rfb_win32/IntervalTimer.h>
+#include <rfb_win32/WMWindowCopyRect.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class SDisplayCorePolling : public SDisplayCore, protected MsgWindow {
+    public:
+      SDisplayCorePolling(SDisplay* display, UpdateTracker* ut, int pollIntervalMs=50);
+      ~SDisplayCorePolling();
+
+      // - Called by SDisplay to inform Core of the screen size
+      virtual void setScreenRect(const Rect& screenRect_);
+
+      // - Called by SDisplay to flush updates to the specified tracker
+      virtual void flushUpdates();
+
+      virtual const char* methodName() const { return "Polling"; }
+
+    protected:
+      // - MsgWindow overrides
+      //   processMessage is used to service the cursor & polling timers
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      // - Hooking subcomponents used to track the desktop state
+      WMCopyRect copyrect;
+
+      // - Background full screen polling fields
+      IntervalTimer pollTimer;
+      static const int pollTimerId;
+      Rect screenRect;
+      int pollInterval;
+      int pollNextY;
+      int pollIncrementY;
+      bool pollNextStrip;
+
+      // - Handle back to the owning SDisplay, and to the UpdateTracker to flush to
+      SDisplay* display;
+      UpdateTracker* updateTracker;
+    };
+
+  };
+};
+
+#endif
\ No newline at end of file
diff --git a/win/rfb_win32/SDisplayCoreWMHooks.cxx b/win/rfb_win32/SDisplayCoreWMHooks.cxx
new file mode 100644 (file)
index 0000000..10b88e0
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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.
+ */
+
+// -=- SDisplayCoreWMHooks.cxx
+
+#include <rfb_win32/SDisplayCoreWMHooks.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("SDisplayCoreWMHooks");
+
+const int SDisplayCoreWMHooks::cursorTimerId = 2;
+const int SDisplayCoreWMHooks::consolePollTimerId = 3;
+
+
+SDisplayCoreWMHooks::SDisplayCoreWMHooks(SDisplay* d, UpdateTracker* ut)
+  : SDisplayCorePolling(d, ut, 5000),
+  cursorTimer(getHandle(), cursorTimerId),
+  consolePollTimer(getHandle(), consolePollTimerId),
+  pollConsoles(false) {
+  if (!hooks.setEvent(display->getUpdateEvent()))
+    throw rdr::Exception("hook subsystem failed to initialise");
+  poller.setUpdateTracker(updateTracker);
+  cursorTimer.start(20);
+  consolePollTimer.start(200);
+}
+
+SDisplayCoreWMHooks::~SDisplayCoreWMHooks() {
+}
+
+LRESULT SDisplayCoreWMHooks::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  if (msg == WM_TIMER) {
+    if (wParam == cursorTimerId) {
+      SetEvent(display->getUpdateEvent());
+      return 0;
+    } else if (wParam == consolePollTimerId) {
+      pollConsoles = true;
+      SetEvent(display->getUpdateEvent());
+      return 0;
+    }
+  }
+  return SDisplayCorePolling::processMessage(msg, wParam, lParam);
+}
+
+void SDisplayCoreWMHooks::flushUpdates() {
+  // Poll any visible console windows
+  if (pollConsoles) {
+    pollConsoles = false;
+    poller.processEvent();
+  }
+
+  // Check for updates from the hooks
+  hooks.getUpdates(updateTracker);
+
+  // Check for updates from the polling Core
+  SDisplayCorePolling::flushUpdates();
+}
diff --git a/win/rfb_win32/SDisplayCoreWMHooks.h b/win/rfb_win32/SDisplayCoreWMHooks.h
new file mode 100644 (file)
index 0000000..24fa5cd
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+// -=- SDisplayCoreWMHooks.h
+//
+// SDisplayCore implementation that uses WMHooks to capture changes to
+// the display.
+// Whenever changes are detected, the SDisplay's updateEvent is signalled,
+// so that it can perform housekeeping tasks (like ensuring the currently
+// active desktop is the correct one), before flushing changes from the
+// Core to the VNC Server.  The SDisplay will clip the changes before they
+// reach the VNC Server.
+
+
+#ifndef __RFB_SDISPLAY_CORE_WMHOOKS_H__
+#define __RFB_SDISPLAY_CORE_WMHOOKS_H__
+
+#include <rfb_win32/SDisplayCorePolling.h>
+#include <rfb_win32/WMHooks.h>
+#include <rfb_win32/WMPoller.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class SDisplayCoreWMHooks : public SDisplayCorePolling {
+    public:
+      SDisplayCoreWMHooks(SDisplay* display, UpdateTracker* ut);
+      ~SDisplayCoreWMHooks();
+
+      // - Called by SDisplay to flush updates to the specified tracker
+      virtual void flushUpdates();
+
+      virtual const char* methodName() const { return "VNC Hooks"; }
+
+    protected:
+      // - MsgWindow overrides
+      //   processMessage is used to service the cursor & polling timers
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      // - Hooking subcomponents used to track the desktop state
+      WMHooks hooks;
+      WMPoller poller;
+      IntervalTimer cursorTimer;
+      IntervalTimer consolePollTimer;
+      bool pollConsoles;
+      static const int consolePollTimerId;
+      static const int cursorTimerId;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/rfb_win32/SFileTransferManagerWin32.cxx b/win/rfb_win32/SFileTransferManagerWin32.cxx
new file mode 100644 (file)
index 0000000..edc898b
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2006 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/
+ *
+ */
+
+// -=- SFileTransferManagerWin32.cxx
+
+#include <rfb_win32/SFileTransferManagerWin32.h>
+
+using namespace rfb;
+using namespace win32;
+
+SFileTransferManagerWin32::SFileTransferManagerWin32()
+{
+
+}
+
+SFileTransferManagerWin32::~SFileTransferManagerWin32()
+{
+
+}
+
+SFileTransfer *
+SFileTransferManagerWin32::createObject(network::Socket *sock)
+{
+  rfb::SFileTransfer *pFT = 0;
+  rfb::win32::SFileTransferWin32 *pFTWin32 = 0;
+
+  pFTWin32 = new SFileTransferWin32(sock);
+  if (pFTWin32 == NULL) return NULL;
+
+  pFT = (SFileTransfer *) pFTWin32;
+
+  m_lstFTObjects.push_front(pFT);
+
+  return pFT;
+}
+
+void 
+SFileTransferManagerWin32::processDownloadMsg(MSG msg)
+{
+  SFileTransfer *pFT = (SFileTransfer *)msg.lParam;
+
+  if (pFT != NULL) {
+    std::list<SFileTransfer*>::iterator i;
+    for (i=m_lstFTObjects.begin(); i!=m_lstFTObjects.end(); i++) {
+      if ((*i) == pFT) {
+        (*i)->sendFileDownloadPortion();
+        return;
+      }
+    }
+  }
+}
diff --git a/win/rfb_win32/SFileTransferManagerWin32.h b/win/rfb_win32/SFileTransferManagerWin32.h
new file mode 100644 (file)
index 0000000..ed1f997
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2006 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/
+ *
+ */
+
+// -=- SFileTransferManagerWin32.h
+
+#ifndef __RFB_WIN32_SFILETRANSFERMANAGERWIN32_H__
+#define __RFB_WIN32_SFILETRANSFERMANAGERWIN32_H__
+
+#include <rfb/SFileTransfer.h>
+#include <rfb/SFileTransferManager.h>
+#include <rfb_win32/SFileTransferWin32.h>
+
+namespace rfb {
+  namespace win32 {
+    class SFileTransferManagerWin32 : public rfb::SFileTransferManager
+    {
+    public:
+      SFileTransferManagerWin32();
+      virtual ~SFileTransferManagerWin32();
+
+      void processDownloadMsg(MSG msg);
+
+      virtual SFileTransfer *createObject(network::Socket *sock);
+    };
+  };
+}
+
+#endif // __RFB_WIN32_SFILETRANSFERMANAGERWIN32_H__
diff --git a/win/rfb_win32/SFileTransferWin32.cxx b/win/rfb_win32/SFileTransferWin32.cxx
new file mode 100644 (file)
index 0000000..5aea412
--- /dev/null
@@ -0,0 +1,125 @@
+/* Copyright (C) 2006 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/
+ *
+ */
+
+// -=- SFileTransferWin32.cxx
+
+#include <rfb/msgTypes.h>
+#include <rfb_win32/FolderManager.h>
+#include <rfb_win32/SFileTransferWin32.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+SFileTransferWin32::SFileTransferWin32(network::Socket *sock) : SFileTransfer(sock)
+{
+}
+
+SFileTransferWin32::~SFileTransferWin32()
+{
+}
+
+bool 
+SFileTransferWin32::initDownloadCallback()
+{
+  PostThreadMessage(GetCurrentThreadId(), VNCM_FT_DOWNLOAD, (WPARAM) 0, (LPARAM) this);
+  return true;
+}
+
+bool 
+SFileTransferWin32::processDownloadCallback()
+{
+  return sendFileDownloadPortion();
+}
+
+bool 
+SFileTransferWin32::convertPathFromNet(char *pszPath)
+{
+  int len = strlen(pszPath);
+  if (pszPath[0] == '/') {
+    if (len == 1) { 
+      pszPath[0] = '\0'; 
+      return true; 
+    }
+  } else {
+    return false;
+  }
+
+  for(int i = 0; i < (len - 1); i++) {
+    if(pszPath[i+1] == '/') pszPath[i+1] = '\\';
+    pszPath[i] = pszPath[i+1];
+  }
+
+  pszPath[len-1] = '\0';
+  return true;
+}
+
+bool 
+SFileTransferWin32::makeFileList(char *pszPath, FileInfo *pFI, bool bDirOnly)
+{
+  FolderManager fm;
+  if (fm.getDirInfo(pszPath, pFI, bDirOnly)) 
+    return true; 
+  else 
+    return false;
+}
+
+bool 
+SFileTransferWin32::deleteIt(char *pszPath)
+{
+  FolderManager fm;
+
+  return fm.deleteIt(pszPath);
+}
+
+bool 
+SFileTransferWin32::renameIt(char *pszOldPath, char *pszNewPath)
+{
+  FolderManager fm;
+
+  return fm.renameIt(pszOldPath, pszNewPath);
+}
+
+bool 
+SFileTransferWin32::createDir(char *pszPath)
+{
+  FolderManager fm;
+
+  return fm.createDir(pszPath);
+}
+
+bool 
+SFileTransferWin32::getDirSize(char *pszName, unsigned short *pHighSize16, 
+                               unsigned int *pLowSize32)
+{
+  FolderManager fm;
+  DWORD64 dw64DirSize = 0;
+
+  if (!fm.getDirSize(pszName, &dw64DirSize)) return false;
+
+  if (dw64DirSize & 0xFFFF000000000000) return false;
+
+  *pHighSize16 = ((dw64DirSize & 0x0000FFFF00000000) >> 32);
+  *pLowSize32 = (dw64DirSize & 0x00000000FFFFFFFF);
+
+  return true;
+}
diff --git a/win/rfb_win32/SFileTransferWin32.h b/win/rfb_win32/SFileTransferWin32.h
new file mode 100644 (file)
index 0000000..5f682a4
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) 2006 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/
+ *
+ */
+
+// -=- SFileTransferWin32.h
+
+#ifndef __RFB_SFILETRANSFERWIN32_H__
+#define __RFB_SFILETRANSFERWIN32_H__
+
+#include <windows.h>
+
+#include <rfb/SFileTransfer.h>
+
+const UINT VNCM_FT_DOWNLOAD = WM_USER + 2;
+
+namespace rfb {
+  namespace win32 {
+    class SFileTransferWin32 : public rfb::SFileTransfer
+    {
+    public:
+      SFileTransferWin32(network::Socket *sock);
+      virtual ~SFileTransferWin32();
+
+      bool processDownloadCallback();
+      virtual bool initDownloadCallback();
+
+      virtual bool convertPathFromNet(char *pszPath);
+      virtual bool makeFileList(char *pszPath, FileInfo *pFI, bool bDirOnly);
+  
+      virtual bool deleteIt(char *pszPath);
+      virtual bool renameIt(char *pszOldPath, char *pszNewPath);
+      virtual bool createDir(char *pszPath);
+
+      virtual bool getDirSize(char *pszName, unsigned short *pHighSize16, unsigned int *pLowSize32);
+
+    };
+  };
+}
+
+#endif // __RFB_SFILETRANSFERWIN32_H__
diff --git a/win/rfb_win32/SInput.cxx b/win/rfb_win32/SInput.cxx
new file mode 100644 (file)
index 0000000..db59287
--- /dev/null
@@ -0,0 +1,466 @@
+/* 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.
+ */
+
+// -=- SInput.cxx
+//
+// A number of routines that accept VNC input event data and perform
+// the appropriate actions under Win32
+
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define XK_CURRENCY
+#include <rfb/keysymdef.h>
+
+#include <tchar.h>
+#include <rfb_win32/SInput.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/Service.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb_win32/keymap.h>
+#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
+
+#if(defined(INPUT_MOUSE) && defined(RFB_HAVE_MONITORINFO))
+#define RFB_HAVE_SENDINPUT
+#else
+#pragma message("  NOTE: Not building SendInput support.")
+#endif
+
+using namespace rfb;
+
+static LogWriter vlog("SInput");
+
+#ifdef RFB_HAVE_SENDINPUT
+typedef UINT (WINAPI *_SendInput_proto)(UINT, LPINPUT, int);
+static win32::DynamicFn<_SendInput_proto> _SendInput(_T("user32.dll"), "SendInput");
+#endif
+
+//
+// -=- Pointer implementation for Win32
+//
+
+static DWORD buttonDownMapping[8] = {
+  MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN,
+  MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, 0, 0, 0
+};
+
+static DWORD buttonUpMapping[8] = {
+  MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP,
+  MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, 0, 0, 0
+};
+
+static DWORD buttonDataMapping[8] = {
+  0, 0, 0, 120, -120, 0, 0, 0
+};
+
+win32::SPointer::SPointer()
+  : last_buttonmask(0)
+{
+}
+
+void
+win32::SPointer::pointerEvent(const Point& pos, int buttonmask)
+{
+  // - We are specifying absolute coordinates
+  DWORD flags = MOUSEEVENTF_ABSOLUTE;
+
+  // - Has the pointer moved since the last event?
+  if (!last_position.equals(pos))
+    flags |= MOUSEEVENTF_MOVE;
+
+  // - If the system swaps left and right mouse buttons then we must
+  //   swap them here to negate the effect, so that we do the actual
+  //   action we mean to do
+  if (::GetSystemMetrics(SM_SWAPBUTTON)) {
+    bool leftDown = buttonmask & 1;
+    bool rightDown = buttonmask & 4;
+    buttonmask = (buttonmask & ~(1 | 4));
+    if (leftDown) buttonmask |= 4;
+    if (rightDown) buttonmask |= 1;
+  }
+
+  DWORD data = 0;
+  for (int i = 0; i < 8; i++) {
+    if ((buttonmask & (1<<i)) != (last_buttonmask & (1<<i))) {
+      if (buttonmask & (1<<i)) {
+        flags |= buttonDownMapping[i];
+        if (buttonDataMapping[i]) {
+          if (data) vlog.info("warning - two buttons set mouse_event data field");
+          data = buttonDataMapping[i];
+        }
+      } else {
+        flags |= buttonUpMapping[i];
+      }
+    }
+  }
+
+  last_position = pos;
+  last_buttonmask = buttonmask;
+
+  Rect primaryDisplay(0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
+  if (primaryDisplay.contains(pos)) {
+    // mouse_event wants coordinates specified as a proportion of the
+    // primary display's size, scaled to the range 0 to 65535
+    Point scaled;
+    scaled.x = (pos.x * 65535) / (primaryDisplay.width()-1);
+    scaled.y = (pos.y * 65535) / (primaryDisplay.height()-1);
+    ::mouse_event(flags, scaled.x, scaled.y, data, 0);
+  } else {
+    // The event lies outside the primary monitor.  Under Win2K, we can just use
+    // SendInput, which allows us to provide coordinates scaled to the virtual desktop.
+    // SendInput is available on all multi-monitor-aware platforms.
+#ifdef RFB_HAVE_SENDINPUT
+    if (osVersion.isPlatformNT) {
+      if (!_SendInput.isValid())
+        throw rdr::Exception("SendInput not available");
+      INPUT evt;
+      evt.type = INPUT_MOUSE;
+      Point vPos(pos.x-GetSystemMetrics(SM_XVIRTUALSCREEN),
+                 pos.y-GetSystemMetrics(SM_YVIRTUALSCREEN));
+      evt.mi.dx = (vPos.x * 65535) / (GetSystemMetrics(SM_CXVIRTUALSCREEN)-1);
+      evt.mi.dy = (vPos.y * 65535) / (GetSystemMetrics(SM_CYVIRTUALSCREEN)-1);
+      evt.mi.dwFlags = flags | MOUSEEVENTF_VIRTUALDESK;
+      evt.mi.dwExtraInfo = 0;
+      evt.mi.mouseData = data;
+      evt.mi.time = 0;
+      if ((*_SendInput)(1, &evt, sizeof(evt)) != 1)
+        throw rdr::SystemException("SendInput", GetLastError());
+    } else {
+      // Under Win9x, this is not addressable by either mouse_event or SendInput
+      // *** STUPID KLUDGY HACK ***
+      POINT cursorPos; GetCursorPos(&cursorPos);
+      ULONG oldSpeed, newSpeed = 10;
+      ULONG mouseInfo[3];
+      if (flags & MOUSEEVENTF_MOVE) {
+        flags &= ~MOUSEEVENTF_ABSOLUTE;
+        SystemParametersInfo(SPI_GETMOUSE, 0, &mouseInfo, 0);
+        SystemParametersInfo(SPI_GETMOUSESPEED, 0, &oldSpeed, 0);
+        vlog.debug("SPI_GETMOUSE %d, %d, %d, speed %d", mouseInfo[0], mouseInfo[1], mouseInfo[2], oldSpeed);
+        ULONG idealMouseInfo[] = {10, 0, 0};
+        SystemParametersInfo(SPI_SETMOUSESPEED, 0, &newSpeed, 0);
+        SystemParametersInfo(SPI_SETMOUSE, 0, &idealMouseInfo, 0);
+      }
+      ::mouse_event(flags, pos.x-cursorPos.x, pos.y-cursorPos.y, data, 0);
+      if (flags & MOUSEEVENTF_MOVE) {
+        SystemParametersInfo(SPI_SETMOUSE, 0, &mouseInfo, 0);
+        SystemParametersInfo(SPI_SETMOUSESPEED, 0, &oldSpeed, 0);
+      }
+    }
+#endif
+  }
+}
+
+//
+// -=- Keyboard implementation
+//
+
+BoolParameter rfb::win32::SKeyboard::deadKeyAware("DeadKeyAware",
+  "Whether to assume the viewer has already interpreted dead key sequences "
+  "into latin-1 characters", true);
+
+static bool oneShift;
+
+// The keysymToAscii table transforms a couple of awkward keysyms into their
+// ASCII equivalents.
+struct  keysymToAscii_t {
+  rdr::U32 keysym;
+  rdr::U8 ascii;
+};
+
+keysymToAscii_t keysymToAscii[] = {
+  { XK_KP_Space, ' ' },
+  { XK_KP_Equal, '=' },
+};
+
+rdr::U8 latin1DeadChars[] = {
+  XK_grave, XK_acute, XK_asciicircum, XK_diaeresis, XK_degree, XK_cedilla,
+  XK_asciitilde
+};
+
+struct latin1ToDeadChars_t {
+  rdr::U8 latin1Char;
+  rdr::U8 deadChar;
+  rdr::U8 baseChar;
+};
+
+latin1ToDeadChars_t latin1ToDeadChars[] = {
+
+  { XK_Agrave, XK_grave, XK_A },
+  { XK_Egrave, XK_grave, XK_E },
+  { XK_Igrave, XK_grave, XK_I },
+  { XK_Ograve, XK_grave, XK_O },
+  { XK_Ugrave, XK_grave, XK_U },
+  { XK_agrave, XK_grave, XK_a },
+  { XK_egrave, XK_grave, XK_e },
+  { XK_igrave, XK_grave, XK_i },
+  { XK_ograve, XK_grave, XK_o},
+  { XK_ugrave, XK_grave, XK_u },
+
+  { XK_Aacute, XK_acute, XK_A },
+  { XK_Eacute, XK_acute, XK_E },
+  { XK_Iacute, XK_acute, XK_I },
+  { XK_Oacute, XK_acute, XK_O },
+  { XK_Uacute, XK_acute, XK_U },
+  { XK_Yacute, XK_acute, XK_Y },
+  { XK_aacute, XK_acute, XK_a },
+  { XK_eacute, XK_acute, XK_e },
+  { XK_iacute, XK_acute, XK_i },
+  { XK_oacute, XK_acute, XK_o},
+  { XK_uacute, XK_acute, XK_u },
+  { XK_yacute, XK_acute, XK_y },
+
+  { XK_Acircumflex, XK_asciicircum, XK_A },
+  { XK_Ecircumflex, XK_asciicircum, XK_E },
+  { XK_Icircumflex, XK_asciicircum, XK_I },
+  { XK_Ocircumflex, XK_asciicircum, XK_O },
+  { XK_Ucircumflex, XK_asciicircum, XK_U },
+  { XK_acircumflex, XK_asciicircum, XK_a },
+  { XK_ecircumflex, XK_asciicircum, XK_e },
+  { XK_icircumflex, XK_asciicircum, XK_i },
+  { XK_ocircumflex, XK_asciicircum, XK_o},
+  { XK_ucircumflex, XK_asciicircum, XK_u },
+
+  { XK_Adiaeresis, XK_diaeresis, XK_A },
+  { XK_Ediaeresis, XK_diaeresis, XK_E },
+  { XK_Idiaeresis, XK_diaeresis, XK_I },
+  { XK_Odiaeresis, XK_diaeresis, XK_O },
+  { XK_Udiaeresis, XK_diaeresis, XK_U },
+  { XK_adiaeresis, XK_diaeresis, XK_a },
+  { XK_ediaeresis, XK_diaeresis, XK_e },
+  { XK_idiaeresis, XK_diaeresis, XK_i },
+  { XK_odiaeresis, XK_diaeresis, XK_o},
+  { XK_udiaeresis, XK_diaeresis, XK_u },
+  { XK_ydiaeresis, XK_diaeresis, XK_y },
+
+  { XK_Aring, XK_degree, XK_A },
+  { XK_aring, XK_degree, XK_a },
+
+  { XK_Ccedilla, XK_cedilla, XK_C },
+  { XK_ccedilla, XK_cedilla, XK_c },
+
+  { XK_Atilde, XK_asciitilde, XK_A },
+  { XK_Ntilde, XK_asciitilde, XK_N },
+  { XK_Otilde, XK_asciitilde, XK_O },
+  { XK_atilde, XK_asciitilde, XK_a },
+  { XK_ntilde, XK_asciitilde, XK_n },
+  { XK_otilde, XK_asciitilde, XK_o },
+};
+
+// doKeyboardEvent wraps the system keybd_event function and attempts to find
+// the appropriate scancode corresponding to the supplied virtual keycode.
+
+inline void doKeyboardEvent(BYTE vkCode, DWORD flags) {
+  vlog.debug("vkCode 0x%x flags 0x%x", vkCode, flags);
+  keybd_event(vkCode, MapVirtualKey(vkCode, 0), flags, 0);
+}
+
+// KeyStateModifier is a class which helps simplify generating a "fake" press
+// or release of shift, ctrl, alt, etc.  An instance of the class is created
+// for every key which may need to be pressed or released.  Then either press()
+// or release() may be called to make sure that the corresponding key is in the
+// right state.  The destructor of the class automatically reverts to the
+// previous state.
+
+class KeyStateModifier {
+public:
+  KeyStateModifier(int vkCode_, int flags_=0)
+    : vkCode(vkCode_), flags(flags_), pressed(false), released(false)
+  {}
+  void press() {
+    if (!(GetAsyncKeyState(vkCode) & 0x8000)) {
+      doKeyboardEvent(vkCode, flags);
+      pressed = true;
+    }
+  }
+  void release() {
+    if (GetAsyncKeyState(vkCode) & 0x8000) {
+      doKeyboardEvent(vkCode, flags | KEYEVENTF_KEYUP);
+      released = true;
+    }
+  }
+  ~KeyStateModifier() {
+    if (pressed) {
+      doKeyboardEvent(vkCode, flags | KEYEVENTF_KEYUP);
+    } else if (released) {
+      doKeyboardEvent(vkCode, flags);
+    }
+  }
+  int vkCode;
+  int flags;
+  bool pressed;
+  bool released;
+};
+
+
+// doKeyEventWithModifiers() generates a key event having first "pressed" or
+// "released" the shift, ctrl or alt modifiers if necessary.
+
+void doKeyEventWithModifiers(BYTE vkCode, BYTE modifierState, bool down)
+{
+  KeyStateModifier ctrl(VK_CONTROL);
+  KeyStateModifier alt(VK_MENU);
+  KeyStateModifier shift(VK_SHIFT);
+
+  if (down) {
+    if (modifierState & 2) ctrl.press();
+    if (modifierState & 4) alt.press();
+    if (modifierState & 1) {
+      shift.press(); 
+    } else {
+      shift.release();
+    }
+  }
+  doKeyboardEvent(vkCode, down ? 0 : KEYEVENTF_KEYUP);
+}
+
+
+win32::SKeyboard::SKeyboard()
+{
+  oneShift = rfb::win32::osVersion.isPlatformWindows;
+  for (int i = 0; i < sizeof(keymap) / sizeof(keymap_t); i++) {
+    vkMap[keymap[i].keysym] = keymap[i].vk;
+    extendedMap[keymap[i].keysym] = keymap[i].extended;
+  }
+
+  // Find dead characters for the current keyboard layout
+  // XXX how could we handle the keyboard layout changing?
+  BYTE keystate[256];
+  memset(keystate, 0, 256);
+  for (int j = 0; j < sizeof(latin1DeadChars); j++) {
+    SHORT s = VkKeyScan(latin1DeadChars[j]);
+    if (s != -1) {
+      BYTE vkCode = LOBYTE(s);
+      BYTE modifierState = HIBYTE(s);
+      keystate[VK_SHIFT] = (modifierState & 1) ? 0x80 : 0;
+      keystate[VK_CONTROL] = (modifierState & 2) ? 0x80 : 0;
+      keystate[VK_MENU] = (modifierState & 4) ? 0x80 : 0;
+      rdr::U8 chars[2];
+      int nchars = ToAscii(vkCode, 0, keystate, (WORD*)&chars, 0);
+      if (nchars < 0) {
+        vlog.debug("Found dead key 0x%x '%c'",
+                   latin1DeadChars[j], latin1DeadChars[j]);
+        deadChars.push_back(latin1DeadChars[j]);
+        ToAscii(vkCode, 0, keystate, (WORD*)&chars, 0);
+      }
+    }
+  }
+}
+
+
+void win32::SKeyboard::keyEvent(rdr::U32 keysym, bool down)
+{
+  for (int i = 0; i < sizeof(keysymToAscii) / sizeof(keysymToAscii_t); i++) {
+    if (keysymToAscii[i].keysym == keysym) {
+      keysym = keysymToAscii[i].ascii;
+      break;
+    }
+  }
+
+  if ((keysym >= 32 && keysym <= 126) ||
+      (keysym >= 160 && keysym <= 255))
+  {
+    // ordinary Latin-1 character
+
+    if (deadKeyAware) {
+      // Detect dead chars and generate the dead char followed by space so
+      // that we'll end up with the original char.
+      for (int i = 0; i < deadChars.size(); i++) {
+        if (keysym == deadChars[i]) {
+          SHORT dc = VkKeyScan(keysym);
+          if (dc != -1) {
+            if (down) {
+              vlog.info("latin-1 dead key: 0x%x vkCode 0x%x mod 0x%x "
+                        "followed by space", keysym, LOBYTE(dc), HIBYTE(dc));
+              doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), true);
+              doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), false);
+              doKeyEventWithModifiers(VK_SPACE, 0, true);
+              doKeyEventWithModifiers(VK_SPACE, 0, false);
+            }
+            return;
+          }
+        }
+      }
+    }
+
+    SHORT s = VkKeyScan(keysym);
+    if (s == -1) {
+      if (down) {
+        // not a single keypress - try synthesizing dead chars.
+        for (int j = 0;
+             j < sizeof(latin1ToDeadChars) / sizeof(latin1ToDeadChars_t);
+             j++) {
+          if (keysym == latin1ToDeadChars[j].latin1Char) {
+            for (int i = 0; i < deadChars.size(); i++) {
+              if (deadChars[i] == latin1ToDeadChars[j].deadChar) {
+                SHORT dc = VkKeyScan(latin1ToDeadChars[j].deadChar);
+                SHORT bc = VkKeyScan(latin1ToDeadChars[j].baseChar);
+                if (dc != -1 && bc != -1) {
+                  vlog.info("latin-1 key: 0x%x dead key vkCode 0x%x mod 0x%x "
+                            "followed by vkCode 0x%x mod 0x%x",
+                            keysym, LOBYTE(dc), HIBYTE(dc),
+                            LOBYTE(bc), HIBYTE(bc));
+                  doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), true);
+                  doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), false);
+                  doKeyEventWithModifiers(LOBYTE(bc), HIBYTE(bc), true);
+                  doKeyEventWithModifiers(LOBYTE(bc), HIBYTE(bc), false);
+                  return;
+                }
+                break;
+              }
+            }
+            break;
+          }
+        }
+        vlog.info("ignoring unrecognised Latin-1 keysym 0x%x",keysym);
+      }
+      return;
+    }
+
+    BYTE vkCode = LOBYTE(s);
+    BYTE modifierState = HIBYTE(s);
+    vlog.debug("latin-1 key: 0x%x vkCode 0x%x mod 0x%x down %d",
+               keysym, vkCode, modifierState, down);
+    doKeyEventWithModifiers(vkCode, modifierState, down);
+
+  } else {
+
+    // see if it's a recognised keyboard key, otherwise ignore it
+
+    if (vkMap.find(keysym) == vkMap.end()) {
+      vlog.info("ignoring unknown keysym 0x%x",keysym);
+      return;
+    }
+    BYTE vkCode = vkMap[keysym];
+    DWORD flags = 0;
+    if (extendedMap[keysym]) flags |= KEYEVENTF_EXTENDEDKEY;
+    if (!down) flags |= KEYEVENTF_KEYUP;
+
+    vlog.debug("keyboard key: keysym 0x%x vkCode 0x%x ext %d down %d",
+               keysym, vkCode, extendedMap[keysym], down);
+    if (down && (vkCode == VK_DELETE) &&
+        ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) &&
+        ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0))
+    {
+      rfb::win32::emulateCtrlAltDel();
+      return;
+    }
+
+    doKeyboardEvent(vkCode, flags);
+  }
+}
diff --git a/win/rfb_win32/SInput.h b/win/rfb_win32/SInput.h
new file mode 100644 (file)
index 0000000..2a0b3e6
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+// -=- Input.h
+//
+// A number of routines that accept VNC-style input event data and perform
+// the appropriate actions under Win32
+
+#ifndef __RFB_WIN32_INPUT_H__
+#define __RFB_WIN32_INPUT_H__
+
+#include <rfb/Rect.h>
+#include <rfb/Configuration.h>
+#include <rdr/types.h>
+#include <map>
+#include <vector>
+
+namespace rfb {
+
+  namespace win32 {
+
+    // -=- Pointer event handling
+
+    class SPointer {
+    public:
+      SPointer();
+      // - Create a pointer event at a the given coordinates, with the
+      //   specified button state.  The event must be specified using
+      //   Screen coordinates.
+      void pointerEvent(const Point& pos, int buttonmask);
+    protected:
+      Point last_position;
+      rdr::U8 last_buttonmask;
+    };
+
+    // -=- Keyboard event handling
+
+    class SKeyboard {
+    public:
+      SKeyboard();
+      void keyEvent(rdr::U32 key, bool down);
+      static BoolParameter deadKeyAware;
+    private:
+      std::map<rdr::U32,rdr::U8> vkMap;
+      std::map<rdr::U32,bool> extendedMap;
+      std::vector<rdr::U8> deadChars;
+    };
+
+  }; // win32
+
+}; // rfb
+
+#endif // __RFB_WIN32_INPUT_H__
diff --git a/win/rfb_win32/ScaledDIBSectionBuffer.cxx b/win/rfb_win32/ScaledDIBSectionBuffer.cxx
new file mode 100644 (file)
index 0000000..e6c15b8
--- /dev/null
@@ -0,0 +1,124 @@
+/* Copyright (C) 2006 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- ScaledDIBSectionBuffer.cxx
+
+#include <math.h>
+
+#include <rfb_win32/ScaledDIBSectionBuffer.h>
+
+using namespace rfb;
+using namespace win32;
+
+ScaledDIBSectionBuffer::ScaledDIBSectionBuffer(HWND window) 
+  : src_buffer(0), scaling(false), DIBSectionBuffer(window) {
+  scaled_data = data;
+}
+
+ScaledDIBSectionBuffer::~ScaledDIBSectionBuffer() {
+  if (src_buffer) delete src_buffer;
+}
+
+void ScaledDIBSectionBuffer::setScale(int scale_) {
+  if (scale_ == getScale()) return;
+
+  if (src_buffer) {
+    delete src_buffer;
+    src_buffer = 0;
+  }
+  if (scale_ != 100) {
+    scaling = true;
+    src_buffer = new ManagedPixelBuffer(format, src_width, src_height);
+    src_data = &(src_buffer->data);
+  } else {
+    scaling = false;
+  }
+  ScaledPixelBuffer::setScale(scale_);
+}
+
+void ScaledDIBSectionBuffer::setPF(const PixelFormat &pf) {
+  if (scaling) src_buffer->setPF(pf);
+  DIBSectionBuffer::setPF(pf);
+  scaled_data = data;
+}
+
+void ScaledDIBSectionBuffer::setSize(int src_width_, int src_height_) {
+  src_width = src_width_;
+  src_height = src_height_;
+  if (scaling) {
+    src_buffer->setSize(src_width, src_height);
+  }
+  calculateScaledBufferSize();
+  recreateScaledBuffer();
+  scaled_data = data;
+}
+
+void ScaledDIBSectionBuffer::recreateScaledBuffer() {
+  width_  = scaled_width;
+  height_ = scaled_height;
+  DIBSectionBuffer::recreateBuffer();
+  scaled_data = data;
+}
+
+void ScaledDIBSectionBuffer::fillRect(const Rect &dest, Pixel pix) {
+  if (scaling) {
+    src_buffer->fillRect(dest, pix);
+    scaleRect(dest);
+  } else {
+    DIBSectionBuffer::fillRect(dest, pix);
+  }
+}
+
+void ScaledDIBSectionBuffer::imageRect(const Rect &dest, const void* pixels, int stride) {
+  if (scaling) {
+    src_buffer->imageRect(dest, pixels, stride);
+    scaleRect(dest);
+  } else {
+    DIBSectionBuffer::imageRect(dest, pixels, stride);
+  }
+}
+
+void ScaledDIBSectionBuffer::copyRect(const Rect &dest, const Point &move_by_delta) {
+  if (scaling) {
+    src_buffer->copyRect(dest, move_by_delta);
+    scaleRect(dest);
+  } else {
+    DIBSectionBuffer::copyRect(dest, move_by_delta);
+  }
+}
+      
+void ScaledDIBSectionBuffer::maskRect(const Rect& r, const void* pixels, const void* mask_) {
+  if (scaling) {
+    src_buffer->maskRect(r, pixels, mask_);
+    scaleRect(r);
+  } else {
+    DIBSectionBuffer::maskRect(r, pixels, mask_);
+  }
+}
+
+void ScaledDIBSectionBuffer::maskRect(const Rect& r, Pixel pixel, const void* mask_) {
+  if (scaling) {
+    src_buffer->maskRect(r, pixel, mask_);
+    scaleRect(r);
+  } else {
+    DIBSectionBuffer::maskRect(r, pixel, mask_);
+  }
+}
diff --git a/win/rfb_win32/ScaledDIBSectionBuffer.h b/win/rfb_win32/ScaledDIBSectionBuffer.h
new file mode 100644 (file)
index 0000000..3cc267b
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright (C) 2006 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- ScaledDIBSectionBuffer.h
+
+#ifndef __RFB_WIN32_SCALED_DIB_SECTION_BUFFER_H__
+#define __RFB_WIN32_SCALED_DIB_SECTION_BUFFER_H__
+
+#include <rfb/ScaledPixelBuffer.h>
+
+#include <rfb_win32/DIBSectionBuffer.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    //
+    // -=- ScaledDIBSectionBuffer
+    //
+
+    class ScaledDIBSectionBuffer : public ScaledPixelBuffer, public DIBSectionBuffer {
+    public:
+      ScaledDIBSectionBuffer(HWND window);
+      virtual ~ScaledDIBSectionBuffer();
+
+      int width()  const { return scaled_width; }
+      int height() const { return scaled_height; }
+      bool isScaling() const { return scaling; }
+
+      virtual void setPF(const PixelFormat &pf);
+      virtual void setSize(int w, int h);
+      virtual void setScale(int scale);
+
+      Rect getRect() const { return ScaledPixelBuffer::getRect(); }
+      Rect getRect(const Point& pos) const { return ScaledPixelBuffer::getRect(pos); }
+
+      // -=- Overrides basic rendering operations of 
+      //     FullFramePixelBuffer class
+
+      virtual void fillRect(const Rect &dest, Pixel pix);
+      virtual void imageRect(const Rect &dest, const void* pixels, int stride=0);
+      virtual void copyRect(const Rect &dest, const Point &move_by_delta);
+      virtual void maskRect(const Rect& r, const void* pixels, const void* mask_);
+      virtual void maskRect(const Rect& r, Pixel pixel, const void* mask_);
+
+    protected:
+      virtual void recreateScaledBuffer();
+      virtual void recreateBuffer() {
+        recreateScaledBuffer();
+      };
+
+      ManagedPixelBuffer *src_buffer;
+      bool scaling;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_SCALED_DIB_SECTION_BUFFER_H__
diff --git a/win/rfb_win32/Security.cxx b/win/rfb_win32/Security.cxx
new file mode 100644 (file)
index 0000000..985f00c
--- /dev/null
@@ -0,0 +1,192 @@
+/* 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.
+ */
+
+// -=- Security.cxx
+
+#include <rfb_win32/Security.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb/LogWriter.h>
+
+#include <lmcons.h>
+#include <Accctrl.h>
+#include <list>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("SecurityWin32");
+
+
+Trustee::Trustee(const TCHAR* name,
+                 TRUSTEE_FORM form,
+                 TRUSTEE_TYPE type) {
+  pMultipleTrustee = 0;
+  MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  TrusteeForm = form;
+  TrusteeType = type;
+  ptstrName = (TCHAR*)name;
+}
+
+
+ExplicitAccess::ExplicitAccess(const TCHAR* name,
+                               TRUSTEE_FORM type,
+                               DWORD perms,
+                               ACCESS_MODE mode,
+                               DWORD inherit) {
+  Trustee = rfb::win32::Trustee(name, type);
+  grfAccessPermissions = perms;
+  grfAccessMode = mode;
+  grfInheritance = inherit;
+}
+
+
+AccessEntries::AccessEntries() : entries(0), entry_count(0) {}
+
+AccessEntries::~AccessEntries() {
+  delete [] entries;
+}
+
+void AccessEntries::allocMinEntries(int count) {
+  if (count > entry_count) {
+    EXPLICIT_ACCESS* new_entries = new EXPLICIT_ACCESS[entry_count+1];
+    if (entries) {
+      memcpy(new_entries, entries, sizeof(EXPLICIT_ACCESS) * entry_count);
+      delete entries;
+    }
+    entries = new_entries;
+  }
+}
+
+void AccessEntries::addEntry(const TCHAR* trusteeName,
+                             DWORD permissions,
+                             ACCESS_MODE mode) {
+  allocMinEntries(entry_count+1);
+  ZeroMemory(&entries[entry_count], sizeof(EXPLICIT_ACCESS));
+  entries[entry_count] = ExplicitAccess(trusteeName, TRUSTEE_IS_NAME, permissions, mode);
+  entry_count++;
+}
+
+void AccessEntries::addEntry(const PSID sid,
+                             DWORD permissions,
+                             ACCESS_MODE mode) {
+  allocMinEntries(entry_count+1);
+  ZeroMemory(&entries[entry_count], sizeof(EXPLICIT_ACCESS));
+  entries[entry_count] = ExplicitAccess((TCHAR*)sid, TRUSTEE_IS_SID, permissions, mode);
+  entry_count++;
+}
+
+
+PSID Sid::copySID(const PSID sid) {
+  if (!IsValidSid(sid))
+    throw rdr::Exception("invalid SID in copyPSID");
+  PSID buf = (PSID)new rdr::U8[GetLengthSid(sid)];
+  if (!CopySid(GetLengthSid(sid), buf, sid))
+    throw rdr::SystemException("CopySid failed", GetLastError());
+  return buf;
+}
+
+void Sid::setSID(const PSID sid) {
+  delete [] buf;
+  buf = (rdr::U8*)copySID(sid);
+}
+
+void Sid::getUserNameAndDomain(TCHAR** name, TCHAR** domain) {
+  DWORD nameLen = 0;
+  DWORD domainLen = 0;
+  SID_NAME_USE use;
+  LookupAccountSid(0, (PSID)buf, 0, &nameLen, 0, &domainLen, &use);
+  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+    throw rdr::SystemException("Unable to determine SID name lengths", GetLastError());
+  vlog.info("nameLen=%d, domainLen=%d, use=%d", nameLen, domainLen, use);
+  *name = new TCHAR[nameLen];
+  *domain = new TCHAR[domainLen];
+  if (!LookupAccountSid(0, (PSID)buf, *name, &nameLen, *domain, &domainLen, &use))
+    throw rdr::SystemException("Unable to lookup account SID", GetLastError());
+}
+
+
+Sid::Administrators::Administrators() {
+  PSID sid = 0;
+  SID_IDENTIFIER_AUTHORITY ntAuth = SECURITY_NT_AUTHORITY;
+  if (!AllocateAndInitializeSid(&ntAuth, 2,
+                                SECURITY_BUILTIN_DOMAIN_RID,
+                                DOMAIN_ALIAS_RID_ADMINS,
+                                0, 0, 0, 0, 0, 0, &sid)) 
+    throw rdr::SystemException("Sid::Administrators", GetLastError());
+  setSID(sid);
+  FreeSid(sid);
+}
+
+Sid::SYSTEM::SYSTEM() {
+  PSID sid = 0;
+  SID_IDENTIFIER_AUTHORITY ntAuth = SECURITY_NT_AUTHORITY;
+  if (!AllocateAndInitializeSid(&ntAuth, 1,
+                                SECURITY_LOCAL_SYSTEM_RID,
+                                0, 0, 0, 0, 0, 0, 0, &sid))
+          throw rdr::SystemException("Sid::SYSTEM", GetLastError());
+  setSID(sid);
+  FreeSid(sid);
+}
+
+Sid::FromToken::FromToken(HANDLE h) {
+  DWORD required = 0;
+  GetTokenInformation(h, TokenUser, 0, 0, &required);
+  rdr::U8Array tmp(required);
+  if (!GetTokenInformation(h, TokenUser, tmp.buf, required, &required))
+    throw rdr::SystemException("GetTokenInformation", GetLastError());
+  TOKEN_USER* tokenUser = (TOKEN_USER*)tmp.buf;
+  setSID(tokenUser->User.Sid);
+}
+
+
+PACL rfb::win32::CreateACL(const AccessEntries& ae, PACL existing_acl) {
+  typedef DWORD (WINAPI *_SetEntriesInAcl_proto) (ULONG, PEXPLICIT_ACCESS, PACL, PACL*);
+#ifdef UNICODE
+  const char* fnName = "SetEntriesInAclW";
+#else
+  const char* fnName = "SetEntriesInAclA";
+#endif
+  DynamicFn<_SetEntriesInAcl_proto> _SetEntriesInAcl(_T("advapi32.dll"), fnName);
+  if (!_SetEntriesInAcl.isValid())
+    throw rdr::SystemException("CreateACL failed; no SetEntriesInAcl", ERROR_CALL_NOT_IMPLEMENTED);
+  PACL new_dacl;
+  DWORD result;
+  if ((result = (*_SetEntriesInAcl)(ae.entry_count, ae.entries, existing_acl, &new_dacl)) != ERROR_SUCCESS)
+    throw rdr::SystemException("SetEntriesInAcl", result);
+  return new_dacl;
+}
+
+
+PSECURITY_DESCRIPTOR rfb::win32::CreateSdWithDacl(const PACL dacl) {
+  SECURITY_DESCRIPTOR absSD;
+  if (!InitializeSecurityDescriptor(&absSD, SECURITY_DESCRIPTOR_REVISION))
+    throw rdr::SystemException("InitializeSecurityDescriptor", GetLastError());
+  Sid::SYSTEM owner;
+  if (!SetSecurityDescriptorOwner(&absSD, owner, FALSE))
+    throw rdr::SystemException("SetSecurityDescriptorOwner", GetLastError());
+  Sid::Administrators group;
+  if (!SetSecurityDescriptorGroup(&absSD, group, FALSE))
+    throw rdr::SystemException("SetSecurityDescriptorGroupp", GetLastError());
+  if (!SetSecurityDescriptorDacl(&absSD, TRUE, dacl, FALSE))
+    throw rdr::SystemException("SetSecurityDescriptorDacl", GetLastError());
+  DWORD sdSize = GetSecurityDescriptorLength(&absSD);
+  SecurityDescriptorPtr sd(sdSize);
+  if (!MakeSelfRelativeSD(&absSD, sd, &sdSize))
+    throw rdr::SystemException("MakeSelfRelativeSD", GetLastError());
+  return sd.takeSD();
+}
diff --git a/win/rfb_win32/Security.h b/win/rfb_win32/Security.h
new file mode 100644 (file)
index 0000000..1e2e906
--- /dev/null
@@ -0,0 +1,123 @@
+/* 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.
+ */
+
+// Security.h
+
+// Wrapper classes for a few Windows NT security structures/functions
+// that are used by VNC
+
+#ifndef __RFB_WIN32_SECURITY_H__
+#define __RFB_WIN32_SECURITY_H__
+
+#include <rdr/types.h>
+#include <rfb_win32/LocalMem.h>
+#include <rfb_win32/TCharArray.h>
+#include <aclapi.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    struct Trustee : public TRUSTEE {
+      Trustee(const TCHAR* name,
+              TRUSTEE_FORM form=TRUSTEE_IS_NAME,
+              TRUSTEE_TYPE type=TRUSTEE_IS_UNKNOWN);
+    };
+
+    struct ExplicitAccess : public EXPLICIT_ACCESS {
+      ExplicitAccess(const TCHAR* name,
+                     TRUSTEE_FORM type,
+                     DWORD perms,
+                     ACCESS_MODE mode,
+                     DWORD inherit=0);
+    };
+
+    // Helper class for building access control lists
+    struct AccessEntries {
+      AccessEntries();
+      ~AccessEntries();
+      void allocMinEntries(int count);
+      void addEntry(const TCHAR* trusteeName,
+                    DWORD permissions,
+                    ACCESS_MODE mode);
+      void addEntry(const PSID sid,
+                    DWORD permissions,
+                    ACCESS_MODE mode);
+
+      EXPLICIT_ACCESS* entries;
+      int entry_count;
+    };
+
+    // Helper class for handling SIDs
+    struct Sid : rdr::U8Array {
+      Sid() {}
+      operator PSID() const {return (PSID)buf;}
+      PSID takePSID() {PSID r = (PSID)buf; buf = 0; return r;}
+
+      static PSID copySID(const PSID sid);
+
+      void setSID(const PSID sid);
+
+      void getUserNameAndDomain(TCHAR** name, TCHAR** domain);
+
+      struct Administrators;
+      struct SYSTEM;
+      struct FromToken;
+
+    private:
+      Sid(const Sid&);
+      Sid& operator=(const Sid&);
+    };
+      
+    struct Sid::Administrators : public Sid {
+      Administrators();
+    };
+    struct Sid::SYSTEM : public Sid {
+      SYSTEM();
+    };
+    struct Sid::FromToken : public Sid {
+      FromToken(HANDLE h);
+    };
+
+    // Helper class for handling & freeing ACLs
+    struct AccessControlList : public LocalMem {
+      AccessControlList(int size) : LocalMem(size) {}
+      AccessControlList(PACL acl_=0) : LocalMem(acl_) {}
+      operator PACL() {return (PACL)ptr;}
+    };
+
+    // Create a new ACL based on supplied entries and, if supplied, existing ACL 
+    PACL CreateACL(const AccessEntries& ae, PACL existing_acl=0);
+
+    // Helper class for memory-management of self-relative SecurityDescriptors
+    struct SecurityDescriptorPtr : LocalMem {
+      SecurityDescriptorPtr(int size) : LocalMem(size) {}
+      SecurityDescriptorPtr(PSECURITY_DESCRIPTOR sd_=0) : LocalMem(sd_) {}
+      PSECURITY_DESCRIPTOR takeSD() {return takePtr();}
+    };
+
+    // Create a new self-relative Security Descriptor, owned by SYSTEM/Administrators,
+    //   with the supplied DACL and no SACL.  The returned value can be assigned
+    //   to a SecurityDescriptorPtr to be managed.
+    PSECURITY_DESCRIPTOR CreateSdWithDacl(const PACL dacl);
+
+  }
+
+}
+
+#endif
diff --git a/win/rfb_win32/Service.cxx b/win/rfb_win32/Service.cxx
new file mode 100644 (file)
index 0000000..2b11a22
--- /dev/null
@@ -0,0 +1,645 @@
+/* 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.
+ */
+
+// -=- Service.cxx
+
+#include <rfb_win32/Service.h>
+#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb_win32/ModuleFileName.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb/Threading.h>
+#include <logmessages/messages.h>
+#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
+
+
+using namespace rdr;
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("Service");
+
+
+// - Internal service implementation functions
+
+Service* service = 0;
+
+VOID WINAPI serviceHandler(DWORD control) {
+  switch (control) {
+  case SERVICE_CONTROL_INTERROGATE:
+    vlog.info("cmd: report status");
+    service->setStatus();
+    return;
+  case SERVICE_CONTROL_PARAMCHANGE:
+    vlog.info("cmd: param change");
+    service->readParams();
+    return;
+  case SERVICE_CONTROL_SHUTDOWN:
+    vlog.info("cmd: OS shutdown");
+    service->osShuttingDown();
+    return;
+  case SERVICE_CONTROL_STOP:
+    vlog.info("cmd: stop");
+    service->setStatus(SERVICE_STOP_PENDING);
+    service->stop();
+    return;
+  };
+  vlog.debug("cmd: unknown %lu", control);
+}
+
+
+// -=- Message window derived class used under Win9x to implement stopService
+
+#define WM_SMSG_SERVICE_STOP WM_USER
+
+class ServiceMsgWindow : public MsgWindow {
+public:
+  ServiceMsgWindow(const TCHAR* name) : MsgWindow(name) {}
+  LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+    switch (msg) {
+    case WM_SMSG_SERVICE_STOP:
+      service->stop();
+      return TRUE;
+    }
+    return MsgWindow::processMessage(msg, wParam, lParam);
+  }
+
+  static const TCHAR* baseName;
+};
+
+const TCHAR* ServiceMsgWindow::baseName = _T("ServiceWindow:");
+
+
+// -=- Service main procedure, used under WinNT/2K/XP by the SCM
+
+VOID WINAPI serviceProc(DWORD dwArgc, LPTSTR* lpszArgv) {
+  vlog.debug("entering %s serviceProc", service->getName());
+  vlog.info("registering handler...");
+  service->status_handle = RegisterServiceCtrlHandler(service->getName(), serviceHandler);
+  if (!service->status_handle) {
+    DWORD err = GetLastError();
+    vlog.error("failed to register handler: %lu", err);
+    ExitProcess(err);
+  }
+  vlog.debug("registered handler (%lx)", service->status_handle);
+  service->setStatus(SERVICE_START_PENDING);
+  vlog.debug("entering %s serviceMain", service->getName());
+  service->status.dwWin32ExitCode = service->serviceMain(dwArgc, lpszArgv);
+  vlog.debug("leaving %s serviceMain", service->getName());
+  service->setStatus(SERVICE_STOPPED);
+}
+
+
+// -=- Service
+
+Service::Service(const TCHAR* name_) : name(name_) {
+  vlog.debug("Service");
+  status_handle = 0;
+  status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
+  status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
+  status.dwWin32ExitCode = NO_ERROR;
+  status.dwServiceSpecificExitCode = 0;
+  status.dwCheckPoint = 0;
+  status.dwWaitHint = 30000;
+  status.dwCurrentState = SERVICE_STOPPED;
+}
+
+void
+Service::start() {
+  if (osVersion.isPlatformNT) {
+    SERVICE_TABLE_ENTRY entry[2];
+    entry[0].lpServiceName = (TCHAR*)name;
+    entry[0].lpServiceProc = serviceProc;
+    entry[1].lpServiceName = NULL;
+    entry[1].lpServiceProc = NULL;
+    vlog.debug("entering dispatcher");
+    if (!SetProcessShutdownParameters(0x100, 0))
+      vlog.error("unable to set shutdown parameters: %d", GetLastError());
+    service = this;
+    if (!StartServiceCtrlDispatcher(entry))
+      throw SystemException("unable to start service", GetLastError());
+  } else {
+
+    // - Create the service window, so the service can be stopped
+    TCharArray wndName(_tcslen(getName()) + _tcslen(ServiceMsgWindow::baseName) + 1);
+    _tcscpy(wndName.buf, ServiceMsgWindow::baseName);
+    _tcscat(wndName.buf, getName());
+    ServiceMsgWindow service_window(wndName.buf);
+
+    // - Locate the RegisterServiceProcess function
+         typedef DWORD (WINAPI * _RegisterServiceProcess_proto)(DWORD, DWORD);
+    DynamicFn<_RegisterServiceProcess_proto> _RegisterServiceProcess(_T("kernel32.dll"), "RegisterServiceProcess");
+    if (!_RegisterServiceProcess.isValid())
+      throw Exception("unable to find RegisterServiceProcess");
+
+    // - Run the service
+    (*_RegisterServiceProcess)(NULL, 1);
+    service = this;
+    serviceMain(0, 0);
+         (*_RegisterServiceProcess)(NULL, 0);
+  }
+}
+
+void
+Service::setStatus() {
+  setStatus(status.dwCurrentState);
+}
+
+void
+Service::setStatus(DWORD state) {
+  if (!osVersion.isPlatformNT)
+    return;
+  if (status_handle == 0) {
+    vlog.debug("warning - cannot setStatus");
+    return;
+  }
+  status.dwCurrentState = state;
+  status.dwCheckPoint++;
+  if (!SetServiceStatus(status_handle, &status)) {
+    status.dwCurrentState = SERVICE_STOPPED;
+    status.dwWin32ExitCode = GetLastError();
+    vlog.error("unable to set service status:%u", status.dwWin32ExitCode);
+  }
+  vlog.debug("set status to %u(%u)", state, status.dwCheckPoint);
+}
+
+Service::~Service() {
+  vlog.debug("~Service");
+  service = 0;
+}
+
+
+// Find out whether this process is running as the WinVNC service
+bool thisIsService() {
+  return service && (service->status.dwCurrentState != SERVICE_STOPPED);
+}
+
+
+// -=- Desktop handling code
+
+// Switch the current thread to the specified desktop
+static bool
+switchToDesktop(HDESK desktop) {
+  HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
+  if (!SetThreadDesktop(desktop)) {
+    vlog.debug("switchToDesktop failed:%u", GetLastError());
+    return false;
+  }
+  if (!CloseDesktop(old_desktop))
+    vlog.debug("unable to close old desktop:%u", GetLastError());
+  return true;
+}
+
+// Determine whether the thread's current desktop is the input one
+static bool
+inputDesktopSelected() {
+  HDESK current = GetThreadDesktop(GetCurrentThreadId());
+       HDESK input = OpenInputDesktop(0, FALSE,
+       DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+               DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+               DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+               DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
+  if (!input) {
+    vlog.debug("unable to OpenInputDesktop(1):%u", GetLastError());
+    return false;
+  }
+
+  DWORD size;
+  char currentname[256];
+  char inputname[256];
+
+  if (!GetUserObjectInformation(current, UOI_NAME, currentname, 256, &size)) {
+    vlog.debug("unable to GetUserObjectInformation(1):%u", GetLastError());
+    CloseDesktop(input);
+    return false;
+  }
+  if (!GetUserObjectInformation(input, UOI_NAME, inputname, 256, &size)) {
+    vlog.debug("unable to GetUserObjectInformation(2):%u", GetLastError());
+    CloseDesktop(input);
+    return false;
+  }
+  if (!CloseDesktop(input))
+    vlog.debug("unable to close input desktop:%u", GetLastError());
+
+  // *** vlog.debug("current=%s, input=%s", currentname, inputname);
+  bool result = strcmp(currentname, inputname) == 0;
+  return result;
+}
+
+// Switch the current thread into the input desktop
+static bool
+selectInputDesktop() {
+  // - Open the input desktop
+  HDESK desktop = OpenInputDesktop(0, FALSE,
+               DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+               DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+               DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+               DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
+  if (!desktop) {
+    vlog.debug("unable to OpenInputDesktop(2):%u", GetLastError());
+    return false;
+  }
+
+  // - Switch into it
+  if (!switchToDesktop(desktop)) {
+    CloseDesktop(desktop);
+    return false;
+  }
+
+  // ***
+  DWORD size = 256;
+  char currentname[256];
+  if (GetUserObjectInformation(desktop, UOI_NAME, currentname, 256, &size)) {
+    vlog.debug("switched to %s", currentname);
+  }
+  // ***
+
+  vlog.debug("switched to input desktop");
+
+  return true;
+}
+
+
+// -=- Access points to desktop-switching routines
+
+bool
+rfb::win32::desktopChangeRequired() {
+  if (!osVersion.isPlatformNT)
+    return false;
+
+  return !inputDesktopSelected();
+}
+
+bool
+rfb::win32::changeDesktop() {
+  if (!osVersion.isPlatformNT)
+    return true;
+  if (osVersion.cannotSwitchDesktop)
+    return false;
+
+  return selectInputDesktop();
+}
+
+
+// -=- Ctrl-Alt-Del emulation
+
+class CADThread : public Thread {
+public:
+  CADThread() : Thread("CtrlAltDel Emulator"), result(false) {}
+  virtual void run() {
+         HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
+
+    if (switchToDesktop(OpenDesktop(_T("Winlogon"), 0, FALSE, DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+                 DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+                 DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+      DESKTOP_SWITCHDESKTOP | GENERIC_WRITE))) {
+           PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
+      switchToDesktop(old_desktop);
+      result = true;
+    }
+  }
+  bool result;
+};
+
+bool
+rfb::win32::emulateCtrlAltDel() {
+  if (!osVersion.isPlatformNT)
+    return false;
+
+  CADThread* cad_thread = new CADThread();
+  vlog.debug("emulate Ctrl-Alt-Del");
+  if (cad_thread) {
+    cad_thread->start();
+    cad_thread->join();
+    bool result = cad_thread->result;
+    delete cad_thread;
+    return result;
+  }
+  return false;
+}
+
+
+// -=- Application Event Log target Logger class
+
+class Logger_EventLog : public Logger {
+public:
+  Logger_EventLog(const TCHAR* srcname) : Logger("EventLog") {
+    eventlog = RegisterEventSource(NULL, srcname);
+    if (!eventlog)
+      printf("Unable to open event log:%ld\n", GetLastError());
+  }
+  ~Logger_EventLog() {
+    if (eventlog)
+      DeregisterEventSource(eventlog);
+  }
+
+  virtual void write(int level, const char *logname, const char *message) {
+    if (!eventlog) return;
+    TStr log(logname), msg(message);
+    const TCHAR* strings[] = {log, msg};
+    WORD type = EVENTLOG_INFORMATION_TYPE;
+    if (level == 0) type = EVENTLOG_ERROR_TYPE;
+    if (!ReportEvent(eventlog, type, 0, VNC4LogMessage, NULL, 2, 0, strings, NULL)) {
+      // *** It's not at all clear what is the correct behaviour if this fails...
+      printf("ReportEvent failed:%ld\n", GetLastError());
+    }
+  }
+
+protected:
+  HANDLE eventlog;
+};
+
+static Logger_EventLog* logger = 0;
+
+bool rfb::win32::initEventLogLogger(const TCHAR* srcname) {
+  if (logger)
+    return false;
+  if (osVersion.isPlatformNT) {
+    logger = new Logger_EventLog(srcname);
+    logger->registerLogger();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+
+// -=- Registering and unregistering the service
+
+bool rfb::win32::registerService(const TCHAR* name, const TCHAR* desc,
+                                 int argc, const char* argv[]) {
+
+  // - Initialise the default service parameters
+  const TCHAR* defaultcmdline;
+  if (osVersion.isPlatformNT)
+    defaultcmdline = _T("-service");
+  else
+    defaultcmdline = _T("-noconsole -service");
+
+  // - Get the full pathname of our executable
+  ModuleFileName buffer;
+
+  // - Calculate the command-line length
+  int cmdline_len = _tcslen(buffer.buf) + 4;
+  int i;
+  for (i=0; i<argc; i++) {
+    cmdline_len += strlen(argv[i]) + 3;
+  }
+
+  // - Add the supplied extra parameters to the command line
+  TCharArray cmdline(cmdline_len+_tcslen(defaultcmdline));
+  _stprintf(cmdline.buf, _T("\"%s\" %s"), buffer.buf, defaultcmdline);
+  for (i=0; i<argc; i++) {
+    _tcscat(cmdline.buf, _T(" \""));
+    _tcscat(cmdline.buf, TStr(argv[i]));
+    _tcscat(cmdline.buf, _T("\""));
+  }
+    
+  // - Register the service
+
+  if (osVersion.isPlatformNT) {
+
+    // - Open the SCM
+    ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+    if (!scm)
+      throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
+
+
+    ServiceHandle service = CreateService(scm,
+      name, desc, SC_MANAGER_ALL_ACCESS,
+      SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+      SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
+      cmdline.buf, NULL, NULL, NULL, NULL, NULL);
+    if (!service)
+      throw rdr::SystemException("unable to create service", GetLastError());
+
+    // - Register the event log source
+    RegKey hk, hk2;
+
+    hk2.createKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
+    hk.createKey(hk2, name);
+
+    for (i=_tcslen(buffer.buf); i>0; i--) {
+      if (buffer.buf[i] == _T('\\')) {
+        buffer.buf[i+1] = 0;
+        break;
+      }
+    }
+
+    const TCHAR* dllFilename = _T("logmessages.dll");
+    TCharArray dllPath(_tcslen(buffer.buf) + _tcslen(dllFilename) + 1);
+    _tcscpy(dllPath.buf, buffer.buf);
+    _tcscat(dllPath.buf, dllFilename);
+    hk.setExpandString(_T("EventMessageFile"), dllPath.buf);
+    hk.setInt(_T("TypesSupported"), EVENTLOG_ERROR_TYPE | EVENTLOG_INFORMATION_TYPE);
+
+  } else {
+
+    RegKey services;
+    services.createKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
+    services.setString(name, cmdline.buf);
+
+  }
+
+  Sleep(500);
+
+  return true;
+}
+
+bool rfb::win32::unregisterService(const TCHAR* name) {
+  if (osVersion.isPlatformNT) {
+
+    // - Open the SCM
+    ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+    if (!scm)
+      throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
+
+    // - Create the service
+    ServiceHandle service = OpenService(scm, name, SC_MANAGER_ALL_ACCESS);
+    if (!service)
+      throw rdr::SystemException("unable to locate the service", GetLastError());
+    if (!DeleteService(service))
+      throw rdr::SystemException("unable to remove the service", GetLastError());
+
+    // - Register the event log source
+    RegKey hk;
+    hk.openKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
+    hk.deleteKey(name);
+
+  } else {
+
+               RegKey services;
+    services.openKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
+    services.deleteValue(name);
+
+  }
+
+  Sleep(500);
+
+  return true;
+}
+
+
+// -=- Starting and stopping the service
+
+HWND findServiceWindow(const TCHAR* name) {
+  TCharArray wndName(_tcslen(ServiceMsgWindow::baseName)+_tcslen(name)+1);
+  _tcscpy(wndName.buf, ServiceMsgWindow::baseName);
+  _tcscat(wndName.buf, name);
+  vlog.debug("searching for %s window", CStr(wndName.buf));
+  return FindWindow(0, wndName.buf);
+}
+
+bool rfb::win32::startService(const TCHAR* name) {
+
+  if (osVersion.isPlatformNT) {
+    // - Open the SCM
+    ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+    if (!scm)
+      throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
+
+    // - Locate the service
+    ServiceHandle service = OpenService(scm, name, SERVICE_START);
+    if (!service)
+      throw rdr::SystemException("unable to open the service", GetLastError());
+
+    // - Start the service
+    if (!StartService(service, 0, NULL))
+      throw rdr::SystemException("unable to start the service", GetLastError());
+  } else {
+    // - Check there is no service window
+    if (findServiceWindow(name))
+      throw rdr::Exception("the service is already running");
+
+    // - Find the RunServices registry key
+               RegKey services;
+               services.openKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"));
+
+    // - Read the command-line from it
+    TCharArray cmdLine = services.getString(name);
+
+    // - Start the service
+    PROCESS_INFORMATION proc_info;
+    STARTUPINFO startup_info;
+    ZeroMemory(&startup_info, sizeof(startup_info));
+    startup_info.cb = sizeof(startup_info);
+    if (!CreateProcess(0, cmdLine.buf, 0, 0, FALSE, CREATE_NEW_CONSOLE, 0, 0, &startup_info, &proc_info)) {
+      throw SystemException("unable to start service", GetLastError());
+    }
+  }
+
+  Sleep(500);
+
+  return true;
+}
+
+bool rfb::win32::stopService(const TCHAR* name) {
+  if (osVersion.isPlatformNT) {
+    // - Open the SCM
+    ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+    if (!scm)
+      throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
+
+    // - Locate the service
+    ServiceHandle service = OpenService(scm, name, SERVICE_STOP);
+    if (!service)
+      throw rdr::SystemException("unable to open the service", GetLastError());
+
+    // - Start the service
+    SERVICE_STATUS status;
+    if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
+      throw rdr::SystemException("unable to stop the service", GetLastError());
+
+  } else {
+    // - Find the service window
+    HWND service_window = findServiceWindow(name);
+    if (!service_window)
+      throw Exception("unable to locate running service");
+
+    // Tell it to quit
+    vlog.debug("sending service stop request");
+    if (!SendMessage(service_window, WM_SMSG_SERVICE_STOP, 0, 0))
+      throw Exception("unable to stop service");
+
+    // Check it's quitting...
+    DWORD process_id = 0;
+    HANDLE process = 0;
+    if (!GetWindowThreadProcessId(service_window, &process_id))
+      throw SystemException("unable to verify service has quit", GetLastError());
+    process = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, process_id);
+    if (!process)
+      throw SystemException("unable to obtain service handle", GetLastError());
+    int retries = 5;
+    vlog.debug("checking status");
+    while (retries-- && (WaitForSingleObject(process, 1000) != WAIT_OBJECT_0)) {}
+    if (!retries) {
+      vlog.debug("failed to quit - terminating");
+      // May not have quit because of silly Win9x registry watching bug..
+      if (!TerminateProcess(process, 1))
+        throw SystemException("unable to terminate process!", GetLastError());
+      throw Exception("service failed to quit - called TerminateProcess");
+    }
+  }
+
+  Sleep(500);
+
+  return true;
+}
+
+DWORD rfb::win32::getServiceState(const TCHAR* name) {
+  if (osVersion.isPlatformNT) {
+    // - Open the SCM
+    ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+    if (!scm)
+      throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
+
+    // - Locate the service
+    ServiceHandle service = OpenService(scm, name, SERVICE_INTERROGATE);
+    if (!service)
+      throw rdr::SystemException("unable to open the service", GetLastError());
+
+    // - Get the service status
+    SERVICE_STATUS status;
+    if (!ControlService(service, SERVICE_CONTROL_INTERROGATE, (SERVICE_STATUS*)&status))
+      throw rdr::SystemException("unable to query the service", GetLastError());
+
+    return status.dwCurrentState;
+  } else {
+    HWND service_window = findServiceWindow(name);
+    return service_window ? SERVICE_RUNNING : SERVICE_STOPPED;
+  }
+}
+
+char* rfb::win32::serviceStateName(DWORD state) {
+  switch (state) {
+  case SERVICE_RUNNING: return strDup("Running");
+  case SERVICE_STOPPED: return strDup("Stopped");
+  case SERVICE_STOP_PENDING: return strDup("Stopping");
+  };
+  CharArray tmp(32);
+  sprintf(tmp.buf, "Unknown (%lu)", state);
+  return tmp.takeBuf();
+}
+
+
+bool rfb::win32::isServiceProcess() {
+  return service != 0;
+}
diff --git a/win/rfb_win32/Service.h b/win/rfb_win32/Service.h
new file mode 100644 (file)
index 0000000..00abe10
--- /dev/null
@@ -0,0 +1,128 @@
+/* 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.
+ */
+
+// -=- Service.h
+//
+// Win32 service-mode code.
+// Derive your service from this code and let it handle the annoying Win32
+// service API.
+// The underlying implementation takes care of the differences between
+// Windows NT and Windows 95 based systems
+
+#ifndef __RFB_WIN32_SERVICE_H__
+#define __RFB_WIN32_SERVICE_H__
+
+#include <windows.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    //
+    // -=- Service
+    //
+
+    // Application base-class for services.
+
+    class Service {
+    public:
+
+      Service(const TCHAR* name_);
+      virtual ~Service();
+
+      const TCHAR* getName() {return name;}
+      SERVICE_STATUS& getStatus() {return status;}
+
+      void setStatus(DWORD status);
+      void setStatus();
+
+      // - Start the service, having initialised it
+      void start();
+
+      // - Service main procedure - override to implement a service
+      virtual DWORD serviceMain(int argc, TCHAR* argv[]) = 0;
+
+      // - Service control notifications
+
+      // To get notified when the OS is shutting down
+      virtual void osShuttingDown() {};
+
+      // To get notified when the service parameters change
+      virtual void readParams() {};
+
+      // To cause the serviceMain() routine to return
+      virtual void stop() {};
+
+    public:
+      SERVICE_STATUS_HANDLE status_handle;
+      SERVICE_STATUS status;
+    protected:
+      const TCHAR* name;
+    };
+
+    class ServiceHandle {
+    public:
+      ServiceHandle(SC_HANDLE h) : handle(h) {}
+      ~ServiceHandle() {CloseServiceHandle(handle);}
+      operator SC_HANDLE() const {return handle;}
+    protected:
+      SC_HANDLE handle;
+    };
+
+    // -=- Routines used by desktop back-end code to manage desktops/window stations
+
+    //     Returns false under Win9x
+    bool desktopChangeRequired();
+
+    //     Returns true under Win9x
+    bool changeDesktop();
+
+    // -=- Routines used by the SInput Keyboard class to emulate Ctrl-Alt-Del
+    //     Returns false under Win9x
+    bool emulateCtrlAltDel();
+
+    // -=- Routines to initialise the Event Log target Logger
+    //     Returns false under Win9x
+    bool initEventLogLogger(const TCHAR* srcname);
+
+    // -=- Routines to register/unregister the service
+    //     These routines also take care of registering the required
+    //     event source information, etc.
+    // *** should really accept TCHAR argv
+
+    bool registerService(const TCHAR* name, const TCHAR* desc, int argc, const char* argv[]);
+    bool unregisterService(const TCHAR* name);
+
+    bool startService(const TCHAR* name);
+    bool stopService(const TCHAR* name);
+
+    // -=- Get the state of the named service (one of the NT service state values)
+    DWORD getServiceState(const TCHAR* name);
+
+    // -=- Convert a supplied service state value to a printable string e.g. Running, Stopped...
+    //     The caller must delete the returned string buffer
+    char* serviceStateName(DWORD state);
+
+    // -=- Routine to determine whether the host process is running a service
+    bool isServiceProcess();
+
+  };
+
+};
+
+#endif // __RFB_WIN32_SERVICE_NT_H__
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
new file mode 100644 (file)
index 0000000..1d52bc8
--- /dev/null
@@ -0,0 +1,213 @@
+/* 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.
+ */
+
+// -=- SocketManager.cxx
+
+#include <winsock2.h>
+#include <list>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/SocketManager.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("SocketManager");
+
+
+// -=- SocketManager
+
+SocketManager::SocketManager() {
+}
+
+SocketManager::~SocketManager() {
+}
+
+
+static requestAddressChangeEvents(network::SocketListener* sock_) {
+  DWORD dummy = 0;
+  if (WSAIoctl(sock_->getFd(), SIO_ADDRESS_LIST_CHANGE, 0, 0, 0, 0, &dummy, 0, 0) == SOCKET_ERROR) {
+    DWORD err = WSAGetLastError();
+    if (err != WSAEWOULDBLOCK)
+      vlog.error("Unable to track address changes", err);
+  }
+}
+
+
+void SocketManager::addListener(network::SocketListener* sock_,
+                                network::SocketServer* srvr,
+                                AddressChangeNotifier* acn) {
+  WSAEVENT event = WSACreateEvent();
+  long flags = FD_ACCEPT | FD_CLOSE;
+  if (acn)
+    flags |= FD_ADDRESS_LIST_CHANGE;
+  try {
+    if (event && (WSAEventSelect(sock_->getFd(), event, flags) == SOCKET_ERROR))
+      throw rdr::SystemException("Unable to select on listener", WSAGetLastError());
+
+    // requestAddressChangeEvents MUST happen after WSAEventSelect, so that the socket is non-blocking
+    if (acn)
+      requestAddressChangeEvents(sock_);
+
+    // addEvent is the last thing we do, so that the event is NOT registered if previous steps fail
+    if (!event || !addEvent(event, this))
+      throw rdr::Exception("Unable to add listener");
+  } catch (rdr::Exception& e) {
+    if (event)
+      WSACloseEvent(event);
+    delete sock_;
+    vlog.error(e.str());
+    throw;
+  }
+
+  ListenInfo li;
+  li.sock = sock_;
+  li.server = srvr;
+  li.notifier = acn;
+  listeners[event] = li;
+}
+
+void SocketManager::remListener(network::SocketListener* sock) {
+  std::map<HANDLE,ListenInfo>::iterator i;
+  for (i=listeners.begin(); i!=listeners.end(); i++) {
+    if (i->second.sock == sock) {
+      removeEvent(i->first);
+      WSACloseEvent(i->first);
+      delete sock;
+      listeners.erase(i);
+      return;
+    }
+  }
+  throw rdr::Exception("Listener not registered");
+}
+
+
+void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
+  WSAEVENT event = WSACreateEvent();
+  if (!event || !addEvent(event, this) ||
+      (WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
+    if (event)
+      WSACloseEvent(event);
+    delete sock_;
+    vlog.error("Unable to add connection");
+    return;
+  }
+  ConnInfo ci;
+  ci.sock = sock_;
+  ci.server = srvr;
+  connections[event] = ci;
+  srvr->addSocket(sock_, outgoing);
+}
+
+void SocketManager::remSocket(network::Socket* sock_) {
+  std::map<HANDLE,ConnInfo>::iterator i;
+  for (i=connections.begin(); i!=connections.end(); i++) {
+    if (i->second.sock == sock_) {
+      i->second.server->removeSocket(sock_);
+      removeEvent(i->first);
+      WSACloseEvent(i->first);
+      delete sock_;
+      connections.erase(i);
+      return;
+    }
+  }
+  throw rdr::Exception("Socket not registered");
+}
+
+
+int SocketManager::checkTimeouts() {
+  network::SocketServer* server = 0;
+  int timeout = EventManager::checkTimeouts();
+
+  std::map<HANDLE,ListenInfo>::iterator i;
+  for (i=listeners.begin(); i!=listeners.end(); i++)
+    soonestTimeout(&timeout, i->second.server->checkTimeouts());
+
+  std::list<network::Socket*> shutdownSocks;
+  std::map<HANDLE,ConnInfo>::iterator j, j_next;
+  for (j=connections.begin(); j!=connections.end(); j=j_next) {
+    j_next = j; j_next++;
+    if (j->second.sock->isShutdown())
+      shutdownSocks.push_back(j->second.sock);
+  }
+
+  std::list<network::Socket*>::iterator k;
+  for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
+    remSocket(*k);
+
+  return timeout;
+}
+
+
+void SocketManager::processEvent(HANDLE event) {
+  if (listeners.count(event)) {
+    ListenInfo li = listeners[event];
+
+    // Accept an incoming connection
+    vlog.debug("accepting incoming connection");
+
+    // What kind of event is this?
+    WSANETWORKEVENTS network_events;
+    WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
+    if (network_events.lNetworkEvents & FD_ACCEPT) {
+      network::Socket* new_sock = li.sock->accept();
+      if (new_sock && li.server->getDisable()) {
+        delete new_sock;
+        new_sock = 0;
+      }
+      if (new_sock)
+        addSocket(new_sock, li.server, false);
+    } else if (network_events.lNetworkEvents & FD_CLOSE) {
+      vlog.info("deleting listening socket");
+      remListener(li.sock);
+    } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
+      li.notifier->processAddressChange(li.sock);
+      DWORD dummy = 0;
+      requestAddressChangeEvents(li.sock);
+    } else {
+      vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
+    }
+  } else if (connections.count(event)) {
+    ConnInfo ci = connections[event];
+
+    try {
+      // Process data from an active connection
+
+      // Cancel event notification for this socket
+      if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
+        throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
+
+      // Reset the event object
+      WSAResetEvent(event);
+
+      // Call the socket server to process the event
+      ci.server->processSocketEvent(ci.sock);
+      if (ci.sock->isShutdown()) {
+        remSocket(ci.sock);
+        return;
+      }
+
+      // Re-instate the required socket event
+      // If the read event is still valid, the event object gets set here
+      if (WSAEventSelect(ci.sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
+        throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
+    } catch (rdr::Exception& e) {
+      vlog.error(e.str());
+      remSocket(ci.sock);
+    }
+  }
+}
diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h
new file mode 100644 (file)
index 0000000..ef35974
--- /dev/null
@@ -0,0 +1,90 @@
+/* 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.
+ */
+
+// -=- SocketManager.h
+
+// Socket manager class for Win32.
+// Passed a network::SocketListener and a network::SocketServer when
+// constructed.  Uses WSAAsyncSelect to get notifications of network 
+// connection attempts.  When an incoming connection is received,
+// the manager will call network::SocketServer::addClient().  If
+// addClient returns true then the manager registers interest in
+// network events on that socket, and calls
+// network::SocketServer::processSocketEvent().
+
+#ifndef __RFB_WIN32_SOCKET_MGR_H__
+#define __RFB_WIN32_SOCKET_MGR_H__
+
+#include <map>
+#include <network/Socket.h>
+#include <rfb_win32/EventManager.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class SocketManager : public EventManager, EventHandler {
+    public:
+      SocketManager();
+      virtual ~SocketManager();
+
+      // AddressChangeNotifier callback interface
+      // If an object implementing this is passed to addListener then it will be
+      // called whenever the SocketListener's address list changes
+      class AddressChangeNotifier {
+      public:
+        virtual ~AddressChangeNotifier() {}
+        virtual void processAddressChange(network::SocketListener* sl) = 0;
+      };
+
+      // Add a listening socket.  Incoming connections will be added to the supplied
+      // SocketServer.
+      void addListener(network::SocketListener* sock_,
+                       network::SocketServer* srvr,
+                       AddressChangeNotifier* acn = 0);
+
+      // Remove and delete a listening socket.
+      void remListener(network::SocketListener* sock);
+
+      // Add an already-connected socket.  Socket events will cause the supplied
+      // SocketServer to be called.  The socket must ALREADY BE REGISTERED with
+      // the SocketServer.
+      void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);
+
+    protected:
+      virtual int checkTimeouts();
+      virtual void processEvent(HANDLE event);
+      virtual void remSocket(network::Socket* sock);
+
+      struct ConnInfo {
+        network::Socket* sock;
+        network::SocketServer* server;
+      };
+      struct ListenInfo {
+        network::SocketListener* sock;
+        network::SocketServer* server;
+        AddressChangeNotifier* notifier;
+      };
+      std::map<HANDLE, ListenInfo> listeners;
+      std::map<HANDLE, ConnInfo> connections;
+   };
+
+  }
+
+}
+
+#endif
diff --git a/win/rfb_win32/TCharArray.cxx b/win/rfb_win32/TCharArray.cxx
new file mode 100644 (file)
index 0000000..fd4c078
--- /dev/null
@@ -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 <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  WCHAR* wstrDup(const WCHAR* s) {
+    if (!s) return 0;
+    WCHAR* t = new WCHAR[wcslen(s)+1];
+    memcpy(t, s, sizeof(WCHAR)*(wcslen(s)+1));
+    return t;
+  }
+  void wstrFree(WCHAR* s) {delete [] s;}
+
+  char* strDup(const WCHAR* s) {
+    if (!s) return 0;
+    int len = wcslen(s);
+    char* t = new char[len+1];
+    t[WideCharToMultiByte(CP_ACP, 0, s, len, t, len, 0, 0)] = 0;
+    return t;
+  }
+
+  WCHAR* wstrDup(const char* s) {
+    if (!s) return 0;
+    int len = strlen(s);
+    WCHAR* t = new WCHAR[len+1];
+    t[MultiByteToWideChar(CP_ACP, 0, s, len, t, len)] = 0;
+    return t;
+  }
+
+
+  bool wstrSplit(const WCHAR* src, const WCHAR limiter, WCHAR** out1, WCHAR** out2, bool fromEnd) {
+    WCharArray out1old, out2old;
+    if (out1) out1old.buf = *out1;
+    if (out2) out2old.buf = *out2;
+    int len = wcslen(src);
+    int i=0, increment=1, limit=len;
+    if (fromEnd) {
+      i=len-1; increment = -1; limit = -1;
+    }
+    while (i!=limit) {
+      if (src[i] == limiter) {
+        if (out1) {
+          *out1 = new WCHAR[i+1];
+          if (i) memcpy(*out1, src, sizeof(WCHAR)*i);
+          (*out1)[i] = 0;
+        }
+        if (out2) {
+          *out2 = new WCHAR[len-i];
+          if (len-i-1) memcpy(*out2, &src[i+1], sizeof(WCHAR)*(len-i-1));
+          (*out2)[len-i-1] = 0;
+        }
+        return true;
+      }
+      i+=increment;
+    }
+    if (out1) *out1 = wstrDup(src);
+    if (out2) *out2 = 0;
+    return false;
+  }
+
+  bool wstrContains(const WCHAR* src, WCHAR c) {
+    int l=wcslen(src);
+    for (int i=0; i<l; i++)
+      if (src[i] == c) return true;
+    return false;
+  }
+
+};
diff --git a/win/rfb_win32/TCharArray.h b/win/rfb_win32/TCharArray.h
new file mode 100644 (file)
index 0000000..dde63b7
--- /dev/null
@@ -0,0 +1,135 @@
+/* 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.
+ */
+
+// -=- TCharArray.h
+
+// This library contains the wide-character equivalent of CharArray, named
+// WCharArray.  In addition to providing wide-character equivalents of
+// the char* string manipulation functions (strDup, strFree, etc), special
+// versions of those functions are provided which attempt to convert from
+// one format to the other.
+//    e.g. char* t = "hello world"; WCHAR* w = wstrDup(t);
+//    Results in w containing the wide-character text "hello world".
+// For convenience, the WStr and CStr classes are also provided.  These
+// accept an existing (const) WCHAR* or char* null-terminated string and
+// create a read-only copy of that in the desired format.  The new copy
+// will actually be the original copy if the format has not changed, otherwise
+// it will be a new buffer owned by the WStr/CStr.
+
+// In addition to providing wide character functions, this header defines
+// TCHAR* handling classes & functions.  TCHAR is defined at compile time to
+// either char or WCHAR.  Programs can treat this as a third data type and
+// call TStr() whenever a TCHAR* is required but a char* or WCHAR* is supplied,
+// and TStr will do the right thing.
+
+#ifndef __RFB_WIN32_TCHARARRAY_H__
+#define __RFB_WIN32_TCHARARRAY_H__
+
+#include <windows.h>
+#include <tchar.h>
+#include <rfb/util.h>
+#include <rfb/Password.h>
+
+namespace rfb {
+
+  // -=- String duplication and cleanup functions.
+  //     These routines also handle conversion between WCHAR* and char*
+
+  char* strDup(const WCHAR* s);
+  WCHAR* wstrDup(const WCHAR* s);
+  WCHAR* wstrDup(const char* s);
+  void wstrFree(WCHAR* s);
+
+  bool wstrSplit(const WCHAR* src, const WCHAR limiter, WCHAR** out1, WCHAR** out2, bool fromEnd=false);
+  bool wstrContains(const WCHAR* src, WCHAR c);
+
+  // -=- Temporary format conversion classes
+  //     CStr accepts WCHAR* or char* and behaves like a char*
+  //     WStr accepts WCHAR* or char* and behaves like a WCHAR*
+
+  struct WStr {
+    WStr(const char* s) : buf(wstrDup(s)), free_(true) {}
+    WStr(const WCHAR* s) : buf(s), free_(false) {}
+    ~WStr() {if (free_) wstrFree((WCHAR*)buf);}
+    operator const WCHAR*() {return buf;}
+    const WCHAR* buf;
+    bool free_;
+  };
+
+  struct CStr {
+    CStr(const char* s) : buf(s), free_(false) {}
+    CStr(const WCHAR* s) : buf(strDup(s)), free_(true) {}
+    ~CStr() {if (free_) strFree((char*)buf);}
+    operator const char*() {return buf;}
+    const char* buf;
+    bool free_;
+  };
+
+  // -=- Class to handle cleanup of arrays of native Win32 characters
+  class WCharArray {
+  public:
+    WCharArray() : buf(0) {}
+    WCharArray(char* str) : buf(wstrDup(str)) {strFree(str);} // note: assumes ownership
+    WCharArray(WCHAR* str) : buf(str) {}                      // note: assumes ownership
+    WCharArray(int len) {
+      buf = new WCHAR[len];
+    }
+    ~WCharArray() {
+      delete [] buf;
+    }
+    // Get the buffer pointer & clear it (i.e. caller takes ownership)
+    WCHAR* takeBuf() {WCHAR* tmp = buf; buf = 0; return tmp;}
+    void replaceBuf(WCHAR* str) {delete [] buf; buf = str;}
+    WCHAR* buf;
+  };
+
+  // -=- Wide-character-based password-buffer handler.  Zeroes the password
+  //     buffer when deleted or replaced.
+  class WPlainPasswd : public WCharArray {
+  public:
+    WPlainPasswd() {}
+    WPlainPasswd(WCHAR* str) : WCharArray(str) {}
+    ~WPlainPasswd() {replaceBuf(0);}
+    void replaceBuf(WCHAR* str) {
+      if (buf)
+        memset(buf, 0, sizeof(WCHAR)*wcslen(buf));
+      WCharArray::replaceBuf(str);
+    }
+  };
+    
+#ifdef _UNICODE
+#define tstrDup wstrDup
+#define tstrFree wstrFree
+#define tstrSplit wstrSplit
+#define tstrContains wstrContains
+  typedef WCharArray TCharArray;
+  typedef WStr TStr;
+  typedef WPlainPasswd TPlainPasswd;
+#else
+#define tstrDup strDup
+#define tstrFree strFree
+#define tstrSplit strSplit
+#define tstrContains strContains
+  typedef CharArray TCharArray;
+  typedef CStr TStr;
+  typedef PlainPasswd TPlainPasswd;
+#endif
+
+};
+
+#endif
diff --git a/win/rfb_win32/Threading.cxx b/win/rfb_win32/Threading.cxx
new file mode 100644 (file)
index 0000000..c41ac38
--- /dev/null
@@ -0,0 +1,151 @@
+/* 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.
+ */
+
+// -=- Threading.cxx
+// Win32 Threading interface implementation
+
+#include <malloc.h>
+
+#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb_win32/Threading.h>
+
+using namespace rfb;
+
+static LogWriter vlog("Threading");
+
+static DWORD threadStorage = TlsAlloc();
+
+
+inline void logAction(Thread* t, const char* action) {
+  vlog.debug("%-16.16s %s(%lx)", action, t->getName(), t);
+}
+
+inline void logError(Thread* t, const char* err) {
+  vlog.error("%-16.16s %s(%lx):%s", "failed", t->getName(), t, err);
+}
+
+
+DWORD WINAPI
+Thread::threadProc(LPVOID lpParameter) {
+  Thread* thread = (Thread*) lpParameter;
+  TlsSetValue(threadStorage, thread);
+  logAction(thread, "started");
+  try {
+    thread->run();
+    logAction(thread, "stopped");
+  } catch (rdr::Exception& e) {
+    logError(thread, e.str());
+  }
+  bool deleteThread = false;
+  {
+    Lock l(thread->mutex);
+    thread->state = ThreadStopped;
+    thread->sig->signal();
+    deleteThread = thread->deleteAfterRun;
+  }
+  if (deleteThread)
+    delete thread;
+  return 0;
+}
+
+Thread::Thread(const char* name_) : name(strDup(name_ ? name_ : "Unnamed")), sig(0), deleteAfterRun(false) {
+  sig = new Condition(mutex);
+  cond_event.h = CreateEvent(NULL, TRUE, FALSE, NULL);
+  thread.h = CreateThread(NULL, 0, threadProc, this, CREATE_SUSPENDED, &thread_id);
+  state = ThreadCreated;
+  logAction(this, "created");
+}
+
+Thread::Thread(HANDLE thread_, DWORD thread_id_) : name(strDup("Native")), sig(0), deleteAfterRun(false),
+  thread(thread_), thread_id(thread_id_) {
+  cond_event.h = CreateEvent(NULL, TRUE, FALSE, NULL);
+  state = ThreadNative;
+  logAction(this, "created");
+}
+
+Thread::~Thread() {
+  logAction(this, "destroying");
+  if (!deleteAfterRun && state != ThreadNative)
+    this->join();
+  if (sig)
+    delete sig;
+  logAction(this, "destroyed");
+}
+
+void
+Thread::run() {
+}
+
+void
+Thread::start() {
+  Lock l(mutex);
+  if (state == ThreadCreated) {
+    state = ThreadStarted;
+    sig->signal();
+    ResumeThread(thread);
+  }
+}
+
+Thread*
+Thread::join() {
+  if (deleteAfterRun)
+    throw rdr::Exception("attempt to join() with deleteAfterRun thread");
+  Lock l(mutex);
+  if (state == ThreadJoined) {
+    logAction(this, "already joined");
+  } else {
+    logAction(this, "joining");
+    while (state == ThreadStarted) {
+      sig->wait();
+      logAction(this, "checking");
+    }
+    state = ThreadJoined;
+    logAction(this, "joined");
+  }
+  return this;
+}
+
+const char*
+Thread::getName() const {
+  return name.buf;
+}
+
+ThreadState
+Thread::getState() const {
+  return state;
+}
+
+unsigned long
+Thread::getThreadId() const {
+  return thread_id;
+}
+
+
+Thread*
+Thread::self() {
+  Thread* thread = (Thread*) TlsGetValue(threadStorage);
+  if (!thread) {
+    // *** memory leak - could use GetExitCodeThread to lazily detect when
+    //     to clean up native thread objects
+    thread = new Thread(GetCurrentThread(), GetCurrentThreadId());
+    TlsSetValue(threadStorage, thread);
+  }
+  return thread;
+}
diff --git a/win/rfb_win32/Threading.h b/win/rfb_win32/Threading.h
new file mode 100644 (file)
index 0000000..850f04d
--- /dev/null
@@ -0,0 +1,154 @@
+/* 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.
+ */
+
+// -=- Threading_win32.h
+// Win32 Threading interface implementation
+
+#ifndef __RFB_THREADING_IMPL_WIN32
+#define __RFB_THREADING_IMPL_WIN32
+
+#define __RFB_THREADING_IMPL WIN32
+
+#include <rfb_win32/Handle.h>
+#include <rfb/util.h>
+#include <rdr/Exception.h>
+//#include <stdio.h>
+
+
+namespace rfb {
+
+  class Mutex {
+  public:
+    Mutex() {
+      InitializeCriticalSection(&crit);
+    }
+    ~Mutex() {
+      DeleteCriticalSection(&crit);
+    }
+    friend class Lock;
+    friend class Condition;
+  protected:
+    void enter() {EnterCriticalSection(&crit);}
+    void exit() {LeaveCriticalSection(&crit);}
+    CRITICAL_SECTION crit;
+  };
+
+  class Lock {
+  public:
+    Lock(Mutex& m) : mutex(m) {m.enter();}
+    ~Lock() {mutex.exit();}
+  protected:
+    Mutex& mutex;
+  };
+
+  enum ThreadState {ThreadCreated, ThreadStarted, ThreadStopped, ThreadJoined, ThreadNative};
+
+  class Thread {
+  public:
+    Thread(const char* name_=0);
+    virtual ~Thread();
+
+    virtual void run();
+
+    virtual void start();
+    virtual Thread* join();
+
+    const char* getName() const;
+    ThreadState getState() const;
+
+    // Determines whether the thread should delete itself when run() returns
+    // If you set this, you must NEVER call join()!
+    void setDeleteAfterRun() {deleteAfterRun = true;};
+
+    unsigned long getThreadId() const;
+
+    static Thread* self();
+
+    friend class Condition;
+
+  protected:
+    Thread(HANDLE thread_, DWORD thread_id_);
+    static DWORD WINAPI threadProc(LPVOID lpParameter);
+
+    win32::Handle thread;
+    DWORD thread_id;
+    CharArray name;
+    ThreadState state;
+    Condition* sig;
+    Mutex mutex;
+
+    win32::Handle cond_event;
+         Thread* cond_next;
+
+    bool deleteAfterRun;
+  };
+
+  class Condition {
+  public:
+    Condition(Mutex& m) : mutex(m), waiting(0) {
+    }
+    ~Condition() {
+    }
+
+    // Wake up the specified number of threads that are waiting
+    // on this Condition, or all of them if -1 is specified.
+    void signal(int howMany=1) {
+      Lock l(cond_lock);
+      while (waiting && howMany!=0) {
+        SetEvent(waiting->cond_event);
+        waiting = waiting->cond_next;
+        if (howMany>0) --howMany;
+      }
+    }
+
+    // NB: Must hold "mutex" to call wait()
+    // Wait until either the Condition is signalled or the timeout
+    // expires.
+    void wait(DWORD timeout=INFINITE) {
+      Thread* self = Thread::self();
+      ResetEvent(self->cond_event);
+      { Lock l(cond_lock);
+        self->cond_next = waiting;
+        waiting = self;
+      }
+      mutex.exit();
+      DWORD result = WaitForSingleObject(self->cond_event, timeout);
+      mutex.enter();
+      if (result == WAIT_TIMEOUT) {
+        Lock l(cond_lock);
+        // Remove this thread from the Condition
+        for (Thread** removeFrom = &waiting; *removeFrom; removeFrom = &(*removeFrom)->cond_next) {
+          if (*removeFrom == self) {
+            *removeFrom = self->cond_next;
+            break;
+          }
+        }
+      } else if (result == WAIT_FAILED) {
+        throw rdr::SystemException("failed to wait on Condition", GetLastError());
+      }
+    }
+    
+  protected:
+    Mutex& mutex;
+    Mutex cond_lock;
+         Thread* waiting;
+  };
+
+};
+
+#endif // __RFB_THREADING_IMPL
diff --git a/win/rfb_win32/ToolBar.cxx b/win/rfb_win32/ToolBar.cxx
new file mode 100644 (file)
index 0000000..6392ebd
--- /dev/null
@@ -0,0 +1,216 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- ToolBar control class.
+
+#include "ToolBar.h"
+
+using namespace rfb::win32;
+
+ToolBar::ToolBar() : hwndToolBar(0), tbID(-1) {
+  INITCOMMONCONTROLSEX icex;
+
+  // Ensure that the common control DLL is loaded
+  icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+  icex.dwICC  = ICC_BAR_CLASSES;
+  InitCommonControlsEx(&icex);
+}
+
+ToolBar::~ToolBar() {
+  DestroyWindow(getHandle());
+}
+
+bool ToolBar::create(int _tbID, HWND _parentHwnd, DWORD dwStyle) {
+  parentHwnd = _parentHwnd;
+  dwStyle |= WS_CHILD;
+
+  // Create the ToolBar window
+  hwndToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, 0, dwStyle, 
+    0, 0, 25, 25, parentHwnd, (HMENU)_tbID, GetModuleHandle(0), 0);
+
+  if (hwndToolBar) {
+    tbID = _tbID;
+
+    // It's required for backward compatibility
+    SendMessage(hwndToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
+  }
+  return (hwndToolBar ? true : false);
+};
+
+int ToolBar::addBitmap(int nButtons, UINT bitmapID) {
+  assert(nButtons > 0);
+  TBADDBITMAP resBitmap;
+  resBitmap.hInst = GetModuleHandle(0);
+  resBitmap.nID = bitmapID;
+  return SendMessage(getHandle(), TB_ADDBITMAP, nButtons, (LPARAM)&resBitmap);
+}
+
+int ToolBar::addSystemBitmap(UINT stdBitmapID) {
+  TBADDBITMAP resBitmap;
+  resBitmap.hInst = HINST_COMMCTRL;
+  resBitmap.nID = stdBitmapID;
+  return SendMessage(getHandle(), TB_ADDBITMAP, 0, (LPARAM)&resBitmap);
+}
+
+bool ToolBar::setBitmapSize(int width, int height) {
+  int result = SendMessage(getHandle(), TB_SETBITMAPSIZE, 
+    0, MAKELONG(width, height));
+  return (result ? true : false);
+}
+
+bool ToolBar::addButton(int iBitmap, int idCommand, BYTE state, BYTE style, UINT dwData, int iString) {
+  TBBUTTON tbb;
+  tbb.iBitmap = iBitmap;
+  tbb.idCommand = idCommand;
+  tbb.fsState = state;
+  tbb.fsStyle = style;
+  tbb.dwData = dwData;
+  tbb.iString = iString;
+
+  int result = SendMessage(getHandle(), TB_ADDBUTTONS, 1, (LPARAM)&tbb);
+  if (result) {
+    SendMessage(getHandle(), TB_AUTOSIZE, 0, 0);
+  }
+  return (result ? true : false);
+}
+
+bool ToolBar::addNButton(int nButtons, LPTBBUTTON tbb) {
+  assert(nButtons > 0);
+  assert(tbb > 0);
+  int result = SendMessage(getHandle(), TB_ADDBUTTONS, nButtons, (LPARAM)tbb);
+  if (result) {
+    SendMessage(getHandle(), TB_AUTOSIZE, 0, 0);
+  }
+  return (result ? true : false);
+}
+
+bool ToolBar::deleteButton(int indexButton) {
+  assert(indexButton >= 0);
+  int result = SendMessage(getHandle(), TB_DELETEBUTTON, indexButton, 0);
+  
+  if (result) {
+    SendMessage(getHandle(), TB_AUTOSIZE, 0, 0);
+  }
+  return (result ? true : false);
+}
+
+bool ToolBar::insertButton(int indexButton, LPTBBUTTON tbb) {
+  assert(indexButton >= 0);
+  assert(tbb > 0);
+  int result = SendMessage(getHandle(), TB_INSERTBUTTON, 
+    indexButton, (LPARAM)tbb);
+
+  if (result) {
+    SendMessage(getHandle(), TB_AUTOSIZE, 0, 0);
+  }
+  return (result ? true : false);
+}
+
+int ToolBar::getButtonInfo(int idButton, TBBUTTONINFO *btnInfo) {
+  assert(idButton >= 0);
+  assert(btnInfo > 0);
+  return SendMessage(getHandle(), TB_GETBUTTONINFO, idButton, (LPARAM)btnInfo);
+}
+
+int ToolBar::getButtonsHeight() {
+  return HIWORD(SendMessage(getHandle(), TB_GETBUTTONSIZE, 0, 0));
+}
+
+int ToolBar::getButtonsWidth() {
+  return LOWORD(SendMessage(getHandle(), TB_GETBUTTONSIZE, 0, 0));
+}
+
+bool ToolBar::setButtonInfo(int idButton, TBBUTTONINFO* btnInfo) {
+  assert(idButton >= 0);
+  assert(btnInfo > 0);
+  int result = SendMessage(getHandle(), TB_SETBUTTONINFO, 
+    idButton, (LPARAM)(LPTBBUTTONINFO)btnInfo);
+  return (result ? true : false);
+}
+
+bool ToolBar::checkButton(int idButton, bool check) {
+  assert(idButton >= 0);
+  int result = SendMessage(getHandle(), TB_CHECKBUTTON, 
+    idButton, MAKELONG(check, 0));
+  return (result ? true : false);
+}
+
+bool ToolBar::enableButton(int idButton, bool enable) {
+  assert(idButton >= 0);
+  int result = SendMessage(getHandle(), TB_ENABLEBUTTON, 
+    idButton, MAKELONG(enable, 0));
+  return (result ? true : false);
+}
+
+bool ToolBar::pressButton(int idButton, bool press) {
+  assert(idButton >= 0);
+  int result = SendMessage(getHandle(), TB_PRESSBUTTON, 
+    idButton, MAKELONG(press, 0));
+  return (result ? true : false);
+}
+
+bool ToolBar::getButtonRect(int nIndex, LPRECT buttonRect) {
+  int result = SendMessage(getHandle(), TB_GETITEMRECT, 
+    nIndex, (LPARAM)buttonRect);
+  return (result ? true : false);
+}
+
+bool ToolBar::setButtonSize(int width, int height) {
+  assert(width > 0);
+  assert(height > 0);
+  int result = SendMessage(getHandle(), TB_SETBUTTONSIZE, 
+    0, MAKELONG(width, height));
+  if (result) {
+    SendMessage(getHandle(), TB_AUTOSIZE, 0, 0);
+    return true;
+  }
+  return false; 
+}
+
+void ToolBar::autoSize() {
+  DWORD style = SendMessage(getHandle(), TB_GETSTYLE,  0, 0);
+  if (style & CCS_NORESIZE) {
+    RECT r, btnRect;
+    GetClientRect(parentHwnd, &r);
+    getButtonRect(0, &btnRect);
+    int height = getButtonsHeight() + btnRect.top * 2 + 2;
+    SetWindowPos(getHandle(), HWND_TOP, 0, 0, r.right - r.left, height, 
+      SWP_NOMOVE);
+  } else {
+    SendMessage(getHandle(), TB_AUTOSIZE, 0, 0);
+  }
+}
+
+int ToolBar::getHeight() {
+  RECT r;
+  GetWindowRect(getHandle(), &r);
+  return r.bottom - r.top;
+}
+
+void ToolBar::show() {
+  ShowWindow(getHandle(), SW_SHOW);
+}
+
+void ToolBar::hide() {
+  ShowWindow(getHandle(), SW_HIDE);
+}
+
+bool ToolBar::isVisible() {
+  DWORD style = GetWindowLong(getHandle(), GWL_STYLE);
+  return (bool)(style & WS_VISIBLE);
+}
diff --git a/win/rfb_win32/ToolBar.h b/win/rfb_win32/ToolBar.h
new file mode 100644 (file)
index 0000000..2242c2a
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- ToolBar control class.
+
+#include <windows.h>
+#include <commctrl.h>
+#include <assert.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class ToolBar {
+    public:
+      ToolBar();
+      virtual ~ToolBar();
+
+      // create() creates a windows toolbar. dwStyle is a combination of 
+      // the toolbar control and button styles. It returns TRUE if successful,
+      // or FALSE otherwise.
+      bool create(int tbID, HWND parentHwnd, 
+                  DWORD dwStyle = WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT);
+
+      // -=- Button images operations
+
+      // addBitmap() adds one or more images from resources to
+      // the list of button images available for a toolbar.
+      // Returns the index of the first new image if successful,
+      // or -1 otherwise.
+      int addBitmap(int nButtons, UINT bitmapID);
+
+      // addSystemBitmap() adds the system-defined button bitmaps to the list
+      // of the toolbar button specifying by stdBitmapID. Returns the index of 
+      // the first new image if successful, or -1 otherwise.
+      int addSystemBitmap(UINT stdBitmapID);
+
+      // setBitmapSize() sets the size of the bitmapped images to be added
+      // to a toolbar. It returns TRUE if successful, or FALSE otherwise.
+      // You must call it before addBitmap().
+      bool setBitmapSize(int width, int height);
+
+      // -=- Button operations
+
+      // addButton() adds one button.
+      bool addButton(int iBitmap, int idCommand, BYTE state=TBSTATE_ENABLED, 
+                     BYTE style=TBSTYLE_BUTTON,  UINT dwData=0, int iString=0);
+
+      // addNButton() adds nButtons buttons to a toolbar.
+      bool addNButton(int nButtons, LPTBBUTTON tbb);
+
+      // deleteButton() removes a button from the toolbar.
+      bool deleteButton(int nIndex);
+
+      // insertButton() inserts a button in a toolbar control by index.
+      bool insertButton(int nIndex, LPTBBUTTON tbb);
+
+      // getButtonInfo() retrieves extended information about a toolbar's 
+      // button. It returns index of the button if successful, or -1 otherwise.
+      int getButtonInfo(int idButton, TBBUTTONINFO *btnInfo);
+
+      // getButtonsHeight() retrieves the height of the toolbar buttons.
+      int getButtonsHeight();
+
+      // getButtonsWidth() retrieves the width of the toolbar buttons.
+      int getButtonsWidth();
+
+      // setButtonInfo() sets the information for an existing button 
+      // in a toolbar.
+      bool setButtonInfo(int idButton, TBBUTTONINFO* ptbbi);
+
+      // checkButton() checks or unchecks a given button in a toolbar control.
+      bool checkButton(int idButton, bool check);
+
+      // enableButton() enables or disables the specified button 
+      // in the toolbar.
+      bool enableButton(int idButton, bool enable);
+
+      // pressButton() presses or releases the specified button in the toolbar.
+      bool pressButton(int idButton, bool press);
+
+      // getButtonRect() gets the bounding rectangle of a button in a toolbar.
+      bool getButtonRect(int nIndex, LPRECT buttonRect);
+  
+      // setButtonSize() sets the size of the buttons to be added to a toolbar.
+      // Button size must be largen the button bitmap.
+      bool setButtonSize(int width, int height);
+
+      // -=- ToolBar operations
+
+      // autoSize() resizes the toolbar window.
+      void autoSize();
+
+      // getHandle() returns handle to a toolbar window.
+      HWND getHandle() { return hwndToolBar; }
+
+      // getHeight() returns the toolbar window height.
+      int getHeight();
+
+      // show() displays the toolbar window.
+      void show();
+
+      // hide() hides the toolbar window.
+      void hide();
+
+      // isVisible() check the toolbar window on visible.
+      bool isVisible();
+
+    protected:
+      HWND hwndToolBar;
+      HWND parentHwnd;
+      int tbID;
+    };
+
+  }; // win32
+
+}; // rfb
diff --git a/win/rfb_win32/TrayIcon.h b/win/rfb_win32/TrayIcon.h
new file mode 100644 (file)
index 0000000..dc5102a
--- /dev/null
@@ -0,0 +1,89 @@
+/* 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.
+ */
+
+// -=- CView.h
+
+// An instance of the CView class is created for each VNC Viewer connection.
+
+#ifndef __RFB_WIN32_TRAY_ICON_H__
+#define __RFB_WIN32_TRAY_ICON_H__
+
+#include <windows.h>
+#include <shellapi.h>
+#include <rfb_win32/MsgWindow.h>
+#include <rdr/Exception.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class TrayIcon : public MsgWindow {
+    public:
+      TrayIcon() : MsgWindow(_T("VNCTray")) {
+#ifdef NOTIFYICONDATA_V1_SIZE
+        nid.cbSize = NOTIFYICONDATA_V1_SIZE;
+#else
+        nid.cbSize = sizeof(NOTIFYICONDATA);
+#endif
+
+        nid.hWnd = getHandle();
+        nid.uID = 0;
+        nid.hIcon = 0;
+        nid.uFlags = NIF_ICON | NIF_MESSAGE;
+        nid.uCallbackMessage = WM_USER;
+      }
+      virtual ~TrayIcon() {
+        remove();
+      }
+      bool setIcon(UINT icon) {
+        if (icon == 0) {
+          return remove();
+        } else {
+          nid.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(icon),
+            IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+          return refresh();
+        }
+      }
+      bool setToolTip(const TCHAR* text) {
+        if (text == 0) {
+          nid.uFlags &= ~NIF_TIP;
+        } else {
+          const int tipLen = sizeof(nid.szTip)/sizeof(TCHAR);
+          _tcsncpy(nid.szTip, text, tipLen);
+          nid.szTip[tipLen-1] = 0;
+          nid.uFlags |= NIF_TIP;
+        }
+        return refresh();
+      }
+      bool remove() {
+        return Shell_NotifyIcon(NIM_DELETE, &nid) != 0;
+      }
+      bool refresh() {
+        return Shell_NotifyIcon(NIM_MODIFY, &nid) || Shell_NotifyIcon(NIM_ADD, &nid);
+      }
+    protected:
+      NOTIFYICONDATA nid;
+    };
+
+  };
+
+};
+
+#endif
+
+
diff --git a/win/rfb_win32/TsSessions.cxx b/win/rfb_win32/TsSessions.cxx
new file mode 100644 (file)
index 0000000..efe7564
--- /dev/null
@@ -0,0 +1,93 @@
+/* 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 <rfb_win32/TsSessions.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb/LogWriter.h>
+#include <rdr/Exception.h>
+#include <tchar.h>
+
+#ifdef ERROR_CTX_WINSTATION_BUSY
+#define RFB_HAVE_WINSTATION_CONNECT
+#else
+#pragma message("  NOTE: Not building WinStationConnect support.")
+#endif
+
+static rfb::LogWriter vlog("TsSessions");
+
+namespace rfb {
+namespace win32 {
+
+  // Windows XP (and later) functions used to handle session Ids
+  typedef BOOLEAN (WINAPI *_WinStationConnect_proto) (HANDLE,ULONG,ULONG,PCWSTR,ULONG);
+  DynamicFn<_WinStationConnect_proto> _WinStationConnect(_T("winsta.dll"), "WinStationConnectW");
+  typedef DWORD (WINAPI *_WTSGetActiveConsoleSessionId_proto) ();
+  DynamicFn<_WTSGetActiveConsoleSessionId_proto> _WTSGetActiveConsoleSessionId(_T("kernel32.dll"), "WTSGetActiveConsoleSessionId");
+  typedef BOOL (WINAPI *_ProcessIdToSessionId_proto) (DWORD, DWORD*);
+  DynamicFn<_ProcessIdToSessionId_proto> _ProcessIdToSessionId(_T("kernel32.dll"), "ProcessIdToSessionId");
+  typedef BOOL (WINAPI *_LockWorkStation_proto)();
+  DynamicFn<_LockWorkStation_proto> _LockWorkStation(_T("user32.dll"), "LockWorkStation");
+
+
+  ProcessSessionId::ProcessSessionId(DWORD processId) {
+    id = 0;
+    if (!_ProcessIdToSessionId.isValid())
+      return;
+    if (processId == -1)
+      processId = GetCurrentProcessId();
+    if (!(*_ProcessIdToSessionId)(GetCurrentProcessId(), &id))
+      throw rdr::SystemException("ProcessIdToSessionId", GetLastError());
+  }
+
+  ProcessSessionId mySessionId;
+
+  ConsoleSessionId::ConsoleSessionId() {
+    if (_WTSGetActiveConsoleSessionId.isValid())
+      id = (*_WTSGetActiveConsoleSessionId)();
+    else
+      id = 0;
+  }
+
+  bool inConsoleSession() {
+    ConsoleSessionId console;
+    return console.id == mySessionId.id;
+  }
+
+  void setConsoleSession(DWORD sessionId) {
+#ifdef RFB_HAVE_WINSTATION_CONNECT
+    if (!_WinStationConnect.isValid())
+      throw rdr::Exception("WinSta APIs missing");
+    if (sessionId == -1)
+      sessionId = mySessionId.id;
+
+    // Try to reconnect our session to the console
+    ConsoleSessionId console;
+    vlog.info("Console session is %d", console.id);
+    if (!(*_WinStationConnect)(0, sessionId, console.id, L"", 0))
+      throw rdr::SystemException("Unable to connect session to Console", GetLastError());
+
+    // Lock the newly connected session, for security
+    if (_LockWorkStation.isValid())
+      (*_LockWorkStation)();
+#else
+    throw rdr::Exception("setConsoleSession not implemented");
+#endif
+  }
+
+};
+};
diff --git a/win/rfb_win32/TsSessions.h b/win/rfb_win32/TsSessions.h
new file mode 100644 (file)
index 0000000..b15ada7
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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.
+ */
+
+// Windows version-independent Terminal Services Session discovery
+// and manipulation API.  This code will eventually be replaced
+// by the full TS-compatibility scheme.
+
+#ifndef __RFB_WIN32_TSSESSIONS_H__
+#define __RFB_WIN32_TSSESSIONS_H__
+
+#include <windows.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    struct SessionId {
+      DWORD id;
+    };
+
+    // Session Id for a given process
+    struct ProcessSessionId : SessionId {
+      ProcessSessionId(DWORD processId = -1);
+    };
+
+    // Session Id for current process
+    extern ProcessSessionId mySessionId;
+
+    // Current console Session Id
+    struct ConsoleSessionId : SessionId {
+      ConsoleSessionId();
+    };
+
+    // Check whether the process is in the Console session at present
+    bool inConsoleSession();
+
+    // Make the specified session the Console session.
+    //   If sessionId is -1 then the process' session is
+    //   made the Console session.
+    void setConsoleSession(DWORD sessionId = -1);
+
+  };
+
+};
+
+#endif
diff --git a/win/rfb_win32/WMCursor.cxx b/win/rfb_win32/WMCursor.cxx
new file mode 100644 (file)
index 0000000..4d696cb
--- /dev/null
@@ -0,0 +1,104 @@
+/* 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.
+ */
+
+// -=- WMCursor.cxx
+
+// *** DOESN'T SEEM TO WORK WITH GetCursorInfo POS CODE BUILT-IN UNDER NT4SP6
+// *** INSTEAD, WE LOOK FOR Win2000/Win98 OR ABOVE
+
+#include <rfb_win32/WMCursor.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+
+using namespace rdr;
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("WMCursor");
+
+
+#ifdef CURSOR_SHOWING
+#define RFB_HAVE_GETCURSORINFO
+#else
+#pragma message("  NOTE: Not building GetCursorInfo support.")
+#endif
+
+#ifdef RFB_HAVE_GETCURSORINFO
+typedef BOOL (WINAPI *_GetCursorInfo_proto)(PCURSORINFO pci);
+DynamicFn<_GetCursorInfo_proto> _GetCursorInfo(_T("user32.dll"), "GetCursorInfo");
+#endif
+
+WMCursor::WMCursor() : hooks(0), use_getCursorInfo(false), cursor(0) {
+#ifdef RFB_HAVE_GETCURSORINFO
+  // Check the OS version
+  bool is_win98 = (osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
+    (osVersion.dwMajorVersion > 4) || ((osVersion.dwMajorVersion == 4) && (osVersion.dwMinorVersion > 0));
+  bool is_win2K = (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osVersion.dwMajorVersion >= 5);
+
+  // Use GetCursorInfo if OS version is sufficient
+  use_getCursorInfo = (is_win98 || is_win2K) && _GetCursorInfo.isValid();
+#endif
+  cursor = (HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+  if (!use_getCursorInfo) {
+    hooks = new WMCursorHooks();
+    if (hooks && hooks->start()) {
+      vlog.info("falling back to cursor hooking: %p", hooks);
+    } else {
+      delete hooks;
+      hooks = 0;
+      vlog.error("unable to monitor cursor shape");
+    }
+  } else {
+    vlog.info("using GetCursorInfo");
+  }
+}
+
+WMCursor::~WMCursor() {
+  vlog.debug("deleting WMCursorHooks (%p)", hooks);
+  if (hooks)
+    delete hooks;
+}
+  
+WMCursor::Info
+WMCursor::getCursorInfo() {
+  Info result;
+#ifdef RFB_HAVE_GETCURSORINFO
+  if (use_getCursorInfo) {
+    CURSORINFO info;
+    info.cbSize = sizeof(CURSORINFO);
+    if ((*_GetCursorInfo)(&info)) {
+      result.cursor = info.hCursor;
+      result.position = Point(info.ptScreenPos.x, info.ptScreenPos.y);
+      result.visible = info.flags & CURSOR_SHOWING;
+      return result;
+    }
+  }
+#endif
+  // Fall back to the old way of doing things
+  POINT pos;
+  if (hooks)
+    cursor = hooks->getCursor();
+  result.cursor = cursor;
+  result.visible = cursor != 0;
+  GetCursorPos(&pos);
+  result.position.x = pos.x;
+  result.position.y = pos.y;
+  return result;
+}
diff --git a/win/rfb_win32/WMCursor.h b/win/rfb_win32/WMCursor.h
new file mode 100644 (file)
index 0000000..41f9ee8
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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.
+ */
+
+// -=- WMCursor.h
+
+// WMCursor provides a single API through which the cursor state can be obtained
+// The underlying implementation will use either GetCursorInfo, or use the
+// wm_hooks library if GetCursorInfo is not available.
+
+#ifndef __RFB_WIN32_WM_CURSOR_H__
+#define __RFB_WIN32_WM_CURSOR_H__
+
+#include <windows.h>
+#include <rfb_win32/WMHooks.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class WMCursor {
+    public:
+      WMCursor();
+      ~WMCursor();
+
+      struct Info {
+        HCURSOR cursor;
+        Point position;
+        bool visible;
+        Info() : cursor(0), visible(false) {}
+        bool operator!=(const Info& info) {
+          return ((cursor != info.cursor) ||
+            (!position.equals(info.position)) ||
+            (visible != info.visible));
+        }
+      };
+
+      Info getCursorInfo();
+    protected:
+      WMCursorHooks* hooks;
+      bool use_getCursorInfo;
+      HCURSOR cursor;
+    };
+
+  };
+};
+
+#endif // __RFB_WIN32_WM_CURSOR_H__
diff --git a/win/rfb_win32/WMHooks.cxx b/win/rfb_win32/WMHooks.cxx
new file mode 100644 (file)
index 0000000..2d69053
--- /dev/null
@@ -0,0 +1,394 @@
+/* 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.
+ */
+
+// -=- WMHooks.cxx
+
+#include <rfb_win32/WMHooks.h>
+#include <rfb_win32/DynamicFn.h>
+#include <rfb_win32/Service.h>
+#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/IntervalTimer.h>
+#include <rfb/Threading.h>
+#include <rfb/LogWriter.h>
+
+#include <list>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("WMHooks");
+
+
+typedef UINT (*WM_Hooks_WMVAL_proto)();
+typedef BOOL (*WM_Hooks_Install_proto)(DWORD owner, DWORD thread);
+typedef BOOL (*WM_Hooks_Remove_proto)(DWORD owner);
+typedef BOOL (*WM_Hooks_EnableCursorShape_proto)(BOOL enable);
+#ifdef _DEBUG
+typedef void (*WM_Hooks_SetDiagnosticRange_proto)(UINT min, UINT max);
+DynamicFn<WM_Hooks_SetDiagnosticRange_proto> WM_Hooks_SetDiagnosticRange(_T("wm_hooks.dll"), "WM_Hooks_SetDiagnosticRange");
+#endif
+
+
+class WMHooksThread : public Thread {
+public:
+  WMHooksThread() : Thread("WMHookThread"), active(true),
+    WM_Hooks_Install(_T("wm_hooks.dll"), "WM_Hooks_Install"),
+    WM_Hooks_Remove(_T("wm_hooks.dll"), "WM_Hooks_Remove"),
+    WM_Hooks_EnableCursorShape(_T("wm_hooks.dll"), "WM_Hooks_EnableCursorShape") {
+  }
+  virtual void run();
+  virtual Thread* join();
+  DynamicFn<WM_Hooks_Install_proto> WM_Hooks_Install;;
+  DynamicFn<WM_Hooks_Remove_proto> WM_Hooks_Remove;
+  DynamicFn<WM_Hooks_EnableCursorShape_proto> WM_Hooks_EnableCursorShape;
+protected:
+  bool active;
+};
+
+WMHooksThread* hook_mgr = 0;
+std::list<WMHooks*> hooks;
+std::list<WMCursorHooks*> cursor_hooks;
+Mutex hook_mgr_lock;
+HCURSOR hook_cursor = (HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+
+
+static bool StartHookThread() {
+  if (hook_mgr)
+    return true;
+  vlog.debug("creating thread");
+  hook_mgr = new WMHooksThread();
+  if (!hook_mgr->WM_Hooks_Install.isValid() ||
+      !hook_mgr->WM_Hooks_Remove.isValid()) {
+    vlog.debug("hooks not available");
+    return false;
+  }
+  vlog.debug("installing hooks");
+  if (!(*hook_mgr->WM_Hooks_Install)(hook_mgr->getThreadId(), 0)) {
+    vlog.error("failed to initialise hooks");
+    delete hook_mgr->join();
+    hook_mgr = 0;
+    return false;
+  }
+  vlog.debug("starting thread");
+  hook_mgr->start();
+  return true;
+}
+
+static void StopHookThread() {
+  if (!hook_mgr)
+    return;
+  if (!hooks.empty() || !cursor_hooks.empty())
+    return;
+  vlog.debug("closing thread");
+  delete hook_mgr->join();
+  hook_mgr = 0;
+}
+
+
+static bool AddHook(WMHooks* hook) {
+  vlog.debug("adding hook");
+  Lock l(hook_mgr_lock);
+  if (!StartHookThread())
+    return false;
+  hooks.push_back(hook);
+  return true;
+}
+
+static bool AddCursorHook(WMCursorHooks* hook) {
+  vlog.debug("adding cursor hook");
+  Lock l(hook_mgr_lock);
+  if (!StartHookThread())
+    return false;
+  if (!hook_mgr->WM_Hooks_EnableCursorShape.isValid())
+    return false;
+  if (cursor_hooks.empty() && !(*hook_mgr->WM_Hooks_EnableCursorShape)(TRUE))
+    return false;
+  cursor_hooks.push_back(hook);
+  return true;
+}
+
+static bool RemHook(WMHooks* hook) {
+  {
+    vlog.debug("removing hook");
+    Lock l(hook_mgr_lock);
+    hooks.remove(hook);
+  }
+  StopHookThread();
+  return true;
+}
+
+static bool RemCursorHook(WMCursorHooks* hook) {
+  {
+    vlog.debug("removing cursor hook");
+    Lock l(hook_mgr_lock);
+    cursor_hooks.remove(hook);
+    if (hook_mgr->WM_Hooks_EnableCursorShape.isValid() &&
+        cursor_hooks.empty())
+      (*hook_mgr->WM_Hooks_EnableCursorShape)(FALSE);
+  }
+  StopHookThread();
+  return true;
+}
+
+static void NotifyHooksRegion(const Region& r) {
+  Lock l(hook_mgr_lock);
+  std::list<WMHooks*>::iterator i;
+  for (i=hooks.begin(); i!=hooks.end(); i++)
+    (*i)->NotifyHooksRegion(r);
+}
+
+static void NotifyHooksCursor(HCURSOR c) {
+  Lock l(hook_mgr_lock);
+  hook_cursor = c;
+}
+
+
+static UINT GetMsgVal(DynamicFn<WM_Hooks_WMVAL_proto>& fn) {
+  if (fn.isValid())
+    return (*fn)();
+  return WM_NULL;
+}
+
+void
+WMHooksThread::run() {
+  // Obtain message ids for all supported hook messages
+  DynamicFn<WM_Hooks_WMVAL_proto> WM_Hooks_WindowChanged(_T("wm_hooks.dll"), "WM_Hooks_WindowChanged");
+  DynamicFn<WM_Hooks_WMVAL_proto> WM_Hooks_WindowBorderChanged(_T("wm_hooks.dll"), "WM_Hooks_WindowBorderChanged");
+  DynamicFn<WM_Hooks_WMVAL_proto> WM_Hooks_WindowClientAreaChanged(_T("wm_hooks.dll"), "WM_Hooks_WindowClientAreaChanged");
+  DynamicFn<WM_Hooks_WMVAL_proto> WM_Hooks_RectangleChanged(_T("wm_hooks.dll"), "WM_Hooks_RectangleChanged");
+  DynamicFn<WM_Hooks_WMVAL_proto> WM_Hooks_CursorChanged(_T("wm_hooks.dll"), "WM_Hooks_CursorChanged");
+  UINT windowMsg = GetMsgVal(WM_Hooks_WindowChanged);
+  UINT clientAreaMsg = GetMsgVal(WM_Hooks_WindowClientAreaChanged);
+  UINT borderMsg = GetMsgVal(WM_Hooks_WindowBorderChanged);
+  UINT rectangleMsg = GetMsgVal(WM_Hooks_RectangleChanged);
+  UINT cursorMsg = GetMsgVal(WM_Hooks_CursorChanged);
+#ifdef _DEBUG
+  DynamicFn<WM_Hooks_WMVAL_proto> WM_Hooks_Diagnostic(_T("wm_hooks.dll"), "WM_Hooks_Diagnostic");
+  UINT diagnosticMsg = GetMsgVal(WM_Hooks_Diagnostic);
+#endif
+  MSG msg;
+  RECT wrect;
+  HWND hwnd;
+  int count = 0;
+
+  // Update delay handling
+  //   We delay updates by 40-80ms, so that the triggering application has time to
+  //   actually complete them before we notify the hook callbacks & they go off
+  //   capturing screen state.
+  const int updateDelayMs = 40;
+  MsgWindow updateDelayWnd(_T("WMHooks::updateDelay"));
+  IntervalTimer updateDelayTimer(updateDelayWnd.getHandle(), 1);
+  Region updates[2];
+  int activeRgn = 0;
+
+  vlog.debug("starting hook thread");
+
+  while (active && GetMessage(&msg, NULL, 0, 0)) {
+    count++;
+
+    if (msg.message == WM_TIMER) {
+      // Actually notify callbacks of graphical updates
+      NotifyHooksRegion(updates[1-activeRgn]);
+      if (updates[activeRgn].is_empty())
+        updateDelayTimer.stop();
+      activeRgn = 1-activeRgn;
+      updates[activeRgn].clear();
+
+    } else if (msg.message == windowMsg) {
+      // An entire window has (potentially) changed
+      hwnd = (HWND) msg.lParam;
+      if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
+        GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect)) {
+          updates[activeRgn].assign_union(Rect(wrect.left, wrect.top,
+                                               wrect.right, wrect.bottom));
+          updateDelayTimer.start(updateDelayMs);
+      }
+
+    } else if (msg.message == clientAreaMsg) {
+      // The client area of a window has (potentially) changed
+      hwnd = (HWND) msg.lParam;
+      if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
+          GetClientRect(hwnd, &wrect) && !IsRectEmpty(&wrect))
+      {
+        POINT pt = {0,0};
+        if (ClientToScreen(hwnd, &pt)) {
+          updates[activeRgn].assign_union(Rect(wrect.left+pt.x, wrect.top+pt.y,
+                                               wrect.right+pt.x, wrect.bottom+pt.y));
+          updateDelayTimer.start(updateDelayMs);
+        }
+      }
+
+    } else if (msg.message == borderMsg) {
+      hwnd = (HWND) msg.lParam;
+      if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
+          GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect))
+      {
+        Region changed(Rect(wrect.left, wrect.top, wrect.right, wrect.bottom));
+        RECT crect;
+        POINT pt = {0,0};
+        if (GetClientRect(hwnd, &crect) && ClientToScreen(hwnd, &pt) &&
+            !IsRectEmpty(&crect))
+        {
+          changed.assign_subtract(Rect(crect.left+pt.x, crect.top+pt.y,
+                                       crect.right+pt.x, crect.bottom+pt.y));
+        }
+        if (!changed.is_empty()) {
+          updates[activeRgn].assign_union(changed);
+          updateDelayTimer.start(updateDelayMs);
+        }
+      }
+    } else if (msg.message == rectangleMsg) {
+      Rect r = Rect(LOWORD(msg.wParam), HIWORD(msg.wParam),
+                    LOWORD(msg.lParam), HIWORD(msg.lParam));
+      if (!r.is_empty()) {
+        updates[activeRgn].assign_union(r);
+        updateDelayTimer.start(updateDelayMs);
+      }
+
+    } else if (msg.message == cursorMsg) {
+      NotifyHooksCursor((HCURSOR)msg.lParam);
+#ifdef _DEBUG
+    } else if (msg.message == diagnosticMsg) {
+      vlog.info("DIAG msg=%x(%d) wnd=%lx", msg.wParam, msg.wParam, msg.lParam);
+#endif
+    }
+  }
+
+  vlog.debug("stopping hook thread - processed %d events", count);
+  (*WM_Hooks_Remove)(getThreadId());
+}
+
+Thread*
+WMHooksThread::join() {
+  vlog.debug("stopping WMHooks thread");
+  active = false;
+  PostThreadMessage(thread_id, WM_QUIT, 0, 0);
+  vlog.debug("joining WMHooks thread");
+  return Thread::join();
+}
+
+// -=- WMHooks class
+
+rfb::win32::WMHooks::WMHooks() : updateEvent(0) {
+}
+
+rfb::win32::WMHooks::~WMHooks() {
+  RemHook(this);
+}
+
+bool rfb::win32::WMHooks::setEvent(HANDLE ue) {
+  if (updateEvent)
+    RemHook(this);
+  updateEvent = ue;
+  return AddHook(this);
+}
+
+bool rfb::win32::WMHooks::getUpdates(UpdateTracker* ut) {
+  if (!updatesReady) return false;
+  Lock l(hook_mgr_lock);
+  updates.copyTo(ut);
+  updates.clear();
+  updatesReady = false;
+  return true;
+}
+
+bool rfb::win32::WMHooks::areAvailable() {
+  WMHooksThread wmht;
+  return wmht.WM_Hooks_Install.isValid();
+}
+
+#ifdef _DEBUG
+void
+rfb::win32::WMHooks::setDiagnosticRange(UINT min, UINT max) {
+  if (WM_Hooks_SetDiagnosticRange.isValid())
+    (*WM_Hooks_SetDiagnosticRange)(min, max);
+}
+#endif
+
+void rfb::win32::WMHooks::NotifyHooksRegion(const Region& r) {
+  // hook_mgr_lock is already held at this point
+  updates.add_changed(r);
+  updatesReady = true;
+  SetEvent(updateEvent);
+}
+
+
+// -=- WMBlockInput class
+
+rfb::win32::WMBlockInput::WMBlockInput() : active(false) {
+}
+
+rfb::win32::WMBlockInput::~WMBlockInput() {
+  blockInputs(false);
+}
+
+typedef BOOL (*WM_Hooks_EnableRealInputs_proto)(BOOL pointer, BOOL keyboard);
+DynamicFn<WM_Hooks_EnableRealInputs_proto>* WM_Hooks_EnableRealInputs = 0;
+static bool blockRealInputs(bool block_) {
+  // NB: Requires blockMutex to be held!
+  if (block_) {
+    if (WM_Hooks_EnableRealInputs)
+      return true;
+    // Enable blocking
+    WM_Hooks_EnableRealInputs = new DynamicFn<WM_Hooks_EnableRealInputs_proto>(_T("wm_hooks.dll"), "WM_Hooks_EnableRealInputs");
+    if (WM_Hooks_EnableRealInputs->isValid() && (**WM_Hooks_EnableRealInputs)(false, false))
+      return true;
+  }
+  if (WM_Hooks_EnableRealInputs) {
+    // Clean up the DynamicFn, either if init failed, or block_ is false
+    if (WM_Hooks_EnableRealInputs->isValid())
+      (**WM_Hooks_EnableRealInputs)(true, true);
+    delete WM_Hooks_EnableRealInputs;
+    WM_Hooks_EnableRealInputs = 0;
+  }
+  return block_ == (WM_Hooks_EnableRealInputs != 0);
+}
+
+Mutex blockMutex;
+int blockCount = 0;
+
+bool rfb::win32::WMBlockInput::blockInputs(bool on) {
+  if (active == on) return true;
+  Lock l(blockMutex);
+  int newCount = on ? blockCount+1 : blockCount-1;
+  if (!blockRealInputs(newCount > 0))
+    return false;
+  blockCount = newCount;
+  active = on;
+  return true;
+}
+
+
+// -=- WMCursorHooks class
+
+rfb::win32::WMCursorHooks::WMCursorHooks() {
+}
+
+rfb::win32::WMCursorHooks::~WMCursorHooks() {
+  RemCursorHook(this);
+}
+
+bool
+rfb::win32::WMCursorHooks::start() {
+  return AddCursorHook(this);
+}
+
+HCURSOR
+rfb::win32::WMCursorHooks::getCursor() const {
+  return hook_cursor;
+}
diff --git a/win/rfb_win32/WMHooks.h b/win/rfb_win32/WMHooks.h
new file mode 100644 (file)
index 0000000..4713b41
--- /dev/null
@@ -0,0 +1,92 @@
+/* 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.
+ */
+
+// -=- WMHooks.h
+
+#ifndef __RFB_WIN32_WM_HOOKS_H__
+#define __RFB_WIN32_WM_HOOKS_H__
+
+#include <windows.h>
+#include <rfb/UpdateTracker.h>
+#include <rdr/Exception.h>
+#include <rfb_win32/Win32Util.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    // -=- WMHooks
+    //     Uses the wm_hooks DLL to intercept window messages, to get _hints_ as
+    //     to what may have changed on-screen.  Updates are notified via a Win32
+    //     event, and retrieved using the getUpdates method, which is thread-safe.
+    class WMHooks {
+    public:
+      WMHooks();
+      ~WMHooks();
+
+      // Specify the event object to notify.  Starts the hook subsystem if it is
+      // not already active, and returns false if the hooks fail to start.
+      bool setEvent(HANDLE updateEvent);
+
+      // Copies any new updates to the UpdateTracker.  Returns true if new updates
+      // were added, false otherwise.
+      bool getUpdates(UpdateTracker* ut);
+
+      // Determine whether the hooks DLL is installed on the system
+      static bool areAvailable();
+
+#ifdef _DEBUG
+      // Get notifications of any messages in the given range, to any hooked window
+      void setDiagnosticRange(UINT min, UINT max);
+#endif
+
+      // * INTERNAL NOTIFICATION FUNCTION * 
+      void NotifyHooksRegion(const Region& r);
+    protected:
+      HANDLE updateEvent;
+      bool updatesReady;
+      SimpleUpdateTracker updates;
+    };
+
+    // -=- Support for filtering out local input events while remote connections are
+    //     active.  Implemented using SetWindowsHookEx for portability.
+    class WMBlockInput {
+    public:
+      WMBlockInput();
+      ~WMBlockInput();
+      bool blockInputs(bool block);
+    protected:
+      bool active;
+    };
+
+    // - Legacy cursor handling support
+    class WMCursorHooks {
+    public:
+      WMCursorHooks();
+      ~WMCursorHooks();
+
+      bool start();
+
+      HCURSOR getCursor() const;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_WM_HOOKS_H__
diff --git a/win/rfb_win32/WMNotifier.cxx b/win/rfb_win32/WMNotifier.cxx
new file mode 100644 (file)
index 0000000..20a5445
--- /dev/null
@@ -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.
+ */
+
+// -=- WMNotifier.cxx
+
+#include <rfb_win32/WMNotifier.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/MsgWindow.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("WMMonitor");
+
+
+WMMonitor::WMMonitor() : MsgWindow(_T("WMMonitor")), notifier(0) {
+}
+
+WMMonitor::~WMMonitor() {
+}
+
+
+LRESULT
+WMMonitor::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+  case WM_DISPLAYCHANGE:
+    if (notifier) {
+      notifier->notifyDisplayEvent(Notifier::DisplaySizeChanged);
+      notifier->notifyDisplayEvent(Notifier::DisplayPixelFormatChanged);
+    }
+    break;
+       case WM_SYSCOLORCHANGE:
+  case WM_PALETTECHANGED:
+    if (notifier) {
+      notifier->notifyDisplayEvent(Notifier::DisplayColourMapChanged);
+    }
+    break;
+  };
+  return MsgWindow::processMessage(msg, wParam, lParam);
+}
diff --git a/win/rfb_win32/WMNotifier.h b/win/rfb_win32/WMNotifier.h
new file mode 100644 (file)
index 0000000..a760964
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+// -=- WMNotifier.h
+//
+// The WMNotifier is used to get callbacks indicating changes in the state
+// of the system, for instance in the size/format/palette of the display.
+// The WMNotifier contains a Win32 window, which receives notifications of
+// system events and stores them.  Whenever processEvent is called, any
+// incoming events are processed and the appropriate notifier called.
+
+#ifndef __RFB_WIN32_NOTIFIER_H__
+#define __RFB_WIN32_NOTIFIER_H__
+
+#include <rfb/SDesktop.h>
+#include <rfb/Threading.h>
+#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/DeviceFrameBuffer.h>
+#include <rfb_win32/SInput.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    // -=- Window Message Monitor implementation
+
+    class WMMonitor : MsgWindow {
+    public:
+
+      class Notifier {
+      public:
+        typedef enum {DisplaySizeChanged, DisplayColourMapChanged,
+          DisplayPixelFormatChanged} DisplayEventType;
+        virtual void notifyDisplayEvent(DisplayEventType evt) = 0;
+      };
+
+      WMMonitor();
+      virtual ~WMMonitor();
+
+      void setNotifier(Notifier* wmn) {notifier=wmn;}
+
+    protected:
+      // - Internal MsgWindow callback
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      Notifier* notifier;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_WMNOTIFIER_H__
diff --git a/win/rfb_win32/WMPoller.cxx b/win/rfb_win32/WMPoller.cxx
new file mode 100644 (file)
index 0000000..f850534
--- /dev/null
@@ -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.
+ */
+
+// -=- WMPoller.cxx
+
+#include <rfb_win32/WMPoller.h>
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Configuration.h>
+
+#include <tchar.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("WMPoller");
+
+BoolParameter rfb::win32::WMPoller::poll_console_windows("PollConsoleWindows",
+  "Server should poll console windows for updates", true);
+
+// -=- WMPoller class
+
+bool
+rfb::win32::WMPoller::processEvent() {
+  PollInfo info;
+  if (poll_console_windows && ut) {
+    ::EnumWindows(WMPoller::enumWindowProc, (LPARAM) &info);
+    ut->add_changed(info.poll_include);
+  }
+  return false;
+}
+
+bool
+rfb::win32::WMPoller::setUpdateTracker(UpdateTracker* ut_) {
+  ut = ut_;
+  return true;
+}
+
+bool
+rfb::win32::WMPoller::checkPollWindow(HWND w) {
+  TCHAR buffer[128];
+  if (!GetClassName(w, buffer, 128))
+    throw rdr::SystemException("unable to get window class:%u", GetLastError());
+  if ((_tcscmp(buffer, _T("tty")) != 0) &&
+    (_tcscmp(buffer, _T("ConsoleWindowClass")) != 0)) {
+    return false;
+  }
+  return true;
+}
+
+void
+rfb::win32::WMPoller::pollWindow(HWND w, PollInfo* i) {
+  RECT r;
+  if (IsWindowVisible(w) && GetWindowRect(w, &r)) {
+    if (IsRectEmpty(&r)) return;
+    Region wrgn(Rect(r.left, r.top, r.right, r.bottom));
+    if (checkPollWindow(w)) {
+      wrgn.assign_subtract(i->poll_exclude);
+      i->poll_include.assign_union(wrgn);
+    } else {
+      i->poll_exclude.assign_union(wrgn);
+    }
+  }
+}
+
+BOOL CALLBACK
+rfb::win32::WMPoller::enumWindowProc(HWND w, LPARAM lp) {
+  pollWindow(w, (PollInfo*)lp);
+  return TRUE;
+}
diff --git a/win/rfb_win32/WMPoller.h b/win/rfb_win32/WMPoller.h
new file mode 100644 (file)
index 0000000..851b69f
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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.
+ */
+
+// -=- WMPoller.h
+//
+// Polls the foreground window.  If the pollOnlyConsoles flag is set,
+// then checks the window class of the foreground window first and
+// only polls it if it's a console.
+// If the pollAllWindows flag is set then iterates through visible
+// windows, and polls the visible bits.  If pollOnlyConsoles is also
+// set then only visible parts of console windows will be polled.
+
+#ifndef __RFB_WIN32_WM_POLLER_H__
+#define __RFB_WIN32_WM_POLLER_H__
+
+#include <windows.h>
+#include <rfb/UpdateTracker.h>
+#include <rfb/Configuration.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class WMPoller {
+    public:
+      WMPoller() : ut(0) {}
+
+      bool processEvent();
+      bool setUpdateTracker(UpdateTracker* ut);
+
+      static BoolParameter poll_console_windows;
+    protected:
+      struct PollInfo {
+        Region poll_include;
+        Region poll_exclude;
+      };
+      static bool checkPollWindow(HWND w);
+      static void pollWindow(HWND w, PollInfo* info);
+      static BOOL CALLBACK enumWindowProc(HWND w, LPARAM lp);
+      UpdateTracker* ut;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_WM_POLLER_H__
diff --git a/win/rfb_win32/WMShatter.cxx b/win/rfb_win32/WMShatter.cxx
new file mode 100644 (file)
index 0000000..e68abfb
--- /dev/null
@@ -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.
+ */
+
+// -=- WMShatter.cxx
+
+#include <rfb_win32/WMShatter.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("WMShatter");
+
+bool
+rfb::win32::IsSafeWM(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
+  bool result = true;
+  switch (msg) {
+    // - UNSAFE MESSAGES
+  case WM_TIMER:
+    result = lParam == 0;
+    break;
+  };
+  if (!result) {
+    vlog.info("IsSafeWM: 0x%x received 0x%x(%u, %lu) - not safe", window, msg, wParam, lParam);
+  }
+  return result;
+}
+
+LRESULT
+rfb::win32::SafeDefWindowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
+  if (IsSafeWM(window, msg, wParam, lParam))
+    return DefWindowProc(window, msg, wParam, lParam);
+  return 0;
+}
+
+LRESULT
+rfb::win32::SafeDispatchMessage(const MSG* msg) {
+  if (IsSafeWM(msg->hwnd, msg->message, msg->wParam, msg->lParam))
+    return DispatchMessage(msg);
+  return 0;
+}
diff --git a/win/rfb_win32/WMShatter.h b/win/rfb_win32/WMShatter.h
new file mode 100644 (file)
index 0000000..3ea63b1
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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.
+ */
+
+// -=- WMShatter.h
+//
+// WMShatter provides the IsSafeWM routine, which returns true iff the
+// supplied window message is safe to pass to DispatchMessage, or to
+// process in the window procedure.
+//
+// This is only required, of course, to avoid so-called "shatter" attacks
+// to be made against the VNC server, which take advantage of the noddy
+// design of the Win32 window messaging system.
+//
+// The API here is designed to hopefully be future proof, so that if they
+// ever come up with a proper way to determine whether a message is safe
+// or not then it can just be reimplemented here...
+
+#ifndef __RFB_WIN32_SHATTER_H__
+#define __RFB_WIN32_SHATTER_H__
+
+#include <windows.h>
+
+namespace rfb {
+  namespace win32 {
+
+    bool IsSafeWM(HWND window, UINT msg, WPARAM wParam, LPARAM lParam);
+
+    LRESULT SafeDefWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+    LRESULT SafeDispatchMessage(const MSG* msg);
+
+  };
+};
+
+#endif // __RFB_WIN32_SHATTER_H__
diff --git a/win/rfb_win32/WMWindowCopyRect.cxx b/win/rfb_win32/WMWindowCopyRect.cxx
new file mode 100644 (file)
index 0000000..63c1da2
--- /dev/null
@@ -0,0 +1,67 @@
+/* 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.
+ */
+
+// -=- WMCopyRect.cxx
+
+#include <rfb_win32/WMWindowCopyRect.h>
+#include <rfb/LogWriter.h>
+#include <windows.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("WMCopyRect");
+
+// -=- WMHooks class
+
+rfb::win32::WMCopyRect::WMCopyRect() : ut(0), fg_window(0) {
+}
+
+bool
+rfb::win32::WMCopyRect::processEvent() {
+  // See if the foreground window has moved
+  HWND window = GetForegroundWindow();
+  if (window) {
+    RECT wrect;
+    if (IsWindow(window) && IsWindowVisible(window) && GetWindowRect(window, &wrect)) {
+      Rect winrect(wrect.left, wrect.top, wrect.right, wrect.bottom);
+      if (fg_window == window) {
+        if (!fg_window_rect.tl.equals(winrect.tl)  && ut) {
+          // Window has moved - send a copyrect event to the client
+          Point delta = Point(winrect.tl.x-fg_window_rect.tl.x, winrect.tl.y-fg_window_rect.tl.y);
+          Region copy_dest = winrect;
+          ut->add_copied(copy_dest, delta);
+          ut->add_changed(Region(fg_window_rect).subtract(copy_dest));
+        }
+      }
+      fg_window = window;
+      fg_window_rect = winrect;
+    } else {
+      fg_window = 0;
+    }
+  } else {
+    fg_window = 0;
+  }
+  return false;
+}
+
+bool
+rfb::win32::WMCopyRect::setUpdateTracker(UpdateTracker* ut_) {
+  ut = ut_;
+  return true;
+}
diff --git a/win/rfb_win32/WMWindowCopyRect.h b/win/rfb_win32/WMWindowCopyRect.h
new file mode 100644 (file)
index 0000000..5a0e876
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+// -=- WMWindowCopyRect.h
+//
+// Helper class which produces copyRect actions by monitoring the location
+// of the current foreground window.
+// Whenever processEvent is called, the foreground window's position is
+// recalculated and a copy event flushed to the supplied UpdateTracker
+// if appropriate.
+
+#ifndef __RFB_WIN32_WM_WINDOW_COPYRECT_H__
+#define __RFB_WIN32_WM_WINDOW_COPYRECT_H__
+
+#include <rfb/UpdateTracker.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class WMCopyRect {
+    public:
+      WMCopyRect();
+
+      bool processEvent();
+      bool setUpdateTracker(UpdateTracker* ut);
+
+    protected:
+      UpdateTracker* ut;
+      void* fg_window;
+      Rect fg_window_rect;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_WM_WINDOW_COPYRECT_H__
diff --git a/win/rfb_win32/Win32Util.cxx b/win/rfb_win32/Win32Util.cxx
new file mode 100644 (file)
index 0000000..ef8039a
--- /dev/null
@@ -0,0 +1,114 @@
+/* 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.
+ */
+
+// Win32Util.cxx
+
+#include <rfb_win32/ModuleFileName.h>
+#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/Handle.h>
+#include <rdr/HexOutStream.h>
+#include <rdr/Exception.h>
+
+namespace rfb {
+namespace win32 {
+
+
+FileVersionInfo::FileVersionInfo(const TCHAR* filename) {
+  // Get executable name
+  ModuleFileName exeName;
+  if (!filename)
+    filename = exeName.buf;
+
+  // Attempt to open the file, to cause Access Denied, etc, errors
+  // to be correctly reported, since the GetFileVersionInfoXXX calls lie...
+  {
+    Handle file(CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0));
+         if (file.h == INVALID_HANDLE_VALUE)
+      throw rdr::SystemException("Failed to open file", GetLastError());
+  }
+
+  // Get version info size
+  DWORD handle;
+  int size = GetFileVersionInfoSize((TCHAR*)filename, &handle);
+  if (!size)
+    throw rdr::SystemException("GetVersionInfoSize failed", GetLastError());
+
+  // Get version info
+  buf = new TCHAR[size];
+  if (!GetFileVersionInfo((TCHAR*)filename, handle, size, buf))
+    throw rdr::SystemException("GetVersionInfo failed", GetLastError());
+}
+
+const TCHAR* FileVersionInfo::getVerString(const TCHAR* name, DWORD langId) {
+  char langIdBuf[sizeof(langId)];
+  for (int i=sizeof(langIdBuf)-1; i>=0; i--) {
+    langIdBuf[i] = (char) (langId & 0xff);
+    langId = langId >> 8;
+  }
+
+  TCharArray langIdStr = rdr::HexOutStream::binToHexStr(langIdBuf, sizeof(langId));
+  TCharArray infoName(_tcslen(_T("StringFileInfo")) + 4 + _tcslen(name) + _tcslen(langIdStr.buf));
+  _stprintf(infoName.buf, _T("\\StringFileInfo\\%s\\%s"), langIdStr.buf, name);
+
+  // Locate the required version string within the version info
+  TCHAR* buffer = 0;
+  UINT length = 0;
+  if (!VerQueryValue(buf, infoName.buf, (void**)&buffer, &length)) {
+    printf("unable to find %s version string", CStr(infoName.buf));
+    throw rdr::Exception("VerQueryValue failed");
+  }
+  return buffer;
+}
+
+
+bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file) {
+  return tstrSplit(path, '\\', dir, file, true);
+}
+
+
+void centerWindow(HWND handle, HWND parent) {
+  RECT r;
+  MonitorInfo mi(parent ? parent : handle);
+  if (!parent || !IsWindowVisible(parent) || !GetWindowRect(parent, &r))
+    r=mi.rcWork;
+  centerWindow(handle, r);
+  mi.clipTo(handle);
+}
+
+void centerWindow(HWND handle, const RECT& r) {
+  RECT wr;
+  if (!GetWindowRect(handle, &wr)) return;
+  int w = wr.right-wr.left;
+  int h = wr.bottom-wr.top;
+  int x = (r.left + r.right - w)/2;
+  int y = (r.top + r.bottom - h)/2;
+  UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE;
+  SetWindowPos(handle, 0, x, y, 0, 0, flags);
+}
+
+void resizeWindow(HWND handle, int width, int height) {
+  RECT r;
+  GetWindowRect(handle, &r);
+  SetWindowPos(handle, 0, 0, 0, width, height, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
+  centerWindow(handle, r);
+}
+
+
+};
+};
diff --git a/win/rfb_win32/Win32Util.h b/win/rfb_win32/Win32Util.h
new file mode 100644 (file)
index 0000000..8cc1a2b
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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.
+ */
+
+// -=- Win32Util.h
+
+// Miscellaneous but useful Win32 API utility functions & classes.
+// In particular, a set of classes which wrap GDI objects,
+// and some to handle palettes.
+
+#ifndef __RFB_WIN32_GDIUTIL_H__
+#define __RFB_WIN32_GDIUTIL_H__
+
+#include <rfb_win32/TCharArray.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    struct FileVersionInfo : public TCharArray {
+      FileVersionInfo(const TCHAR* filename=0);
+      const TCHAR* getVerString(const TCHAR* name, DWORD langId = 0x080904b0);
+    };
+
+    bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file);
+
+    // Center the window to a rectangle, or to a parent window.
+    // Optionally, resize the window to lay within the rect or parent window
+    // If the parent window is NULL then the working area if the window's
+    // current monitor is used instead.
+    void centerWindow(HWND handle, const RECT& r);
+    void centerWindow(HWND handle, HWND parent);
+
+    // resizeWindow resizes a window about its center
+    void resizeWindow(HWND handle, int width, int height);
+
+  };
+
+};
+
+#endif
diff --git a/win/rfb_win32/keymap.h b/win/rfb_win32/keymap.h
new file mode 100644 (file)
index 0000000..a340d09
--- /dev/null
@@ -0,0 +1,149 @@
+/* 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.
+ */
+
+// keymap.h - this file is shared between SInput.cxx and CKeyboard.cxx
+//
+// Mapping of X keysyms to and from Windows VK codes.  Ordering here must be
+// such that when we look up a Windows VK code we get the preferred X keysym.
+// Going the other way there is no problem because an X keysym always maps to
+// exactly one Windows VK code.  This map only contain keys which are not the
+// normal keys for printable ASCII characters.  For example it does not contain
+// VK_SPACE (note that things like VK_ADD are for the plus key on the keypad,
+// not on the main keyboard).
+
+struct keymap_t {
+  rdr::U32 keysym;
+  rdr::U8 vk;
+  bool extended;
+};
+
+static keymap_t keymap[] = {
+
+  { XK_BackSpace,        VK_BACK, 0 },
+  { XK_Tab,              VK_TAB, 0 },
+  { XK_Clear,            VK_CLEAR, 0 },
+  { XK_Return,           VK_RETURN, 0 },
+  { XK_Pause,            VK_PAUSE, 0 },
+  { XK_Escape,           VK_ESCAPE, 0 },
+  { XK_Delete,           VK_DELETE, 1 },
+
+  // Cursor control & motion
+
+  { XK_Home,             VK_HOME, 1 },
+  { XK_Left,             VK_LEFT, 1 },
+  { XK_Up,               VK_UP, 1 },
+  { XK_Right,            VK_RIGHT, 1 },
+  { XK_Down,             VK_DOWN, 1 },
+  { XK_Page_Up,          VK_PRIOR, 1 },
+  { XK_Page_Down,        VK_NEXT, 1 },
+  { XK_End,              VK_END, 1 },
+
+  // Misc functions
+
+  { XK_Select,           VK_SELECT, 0 },
+  { XK_Print,            VK_SNAPSHOT, 0 },
+  { XK_Execute,          VK_EXECUTE, 0 },
+  { XK_Insert,           VK_INSERT, 1 },
+  { XK_Help,             VK_HELP, 0 },
+  { XK_Break,            VK_CANCEL, 1 },
+
+  // Auxilliary Functions - must come before XK_KP_F1, etc
+
+  { XK_F1,               VK_F1, 0 },
+  { XK_F2,               VK_F2, 0 },
+  { XK_F3,               VK_F3, 0 },
+  { XK_F4,               VK_F4, 0 },
+  { XK_F5,               VK_F5, 0 },
+  { XK_F6,               VK_F6, 0 },
+  { XK_F7,               VK_F7, 0 },
+  { XK_F8,               VK_F8, 0 },
+  { XK_F9,               VK_F9, 0 },
+  { XK_F10,              VK_F10, 0 },
+  { XK_F11,              VK_F11, 0 },
+  { XK_F12,              VK_F12, 0 },
+  { XK_F13,              VK_F13, 0 },
+  { XK_F14,              VK_F14, 0 },
+  { XK_F15,              VK_F15, 0 },
+  { XK_F16,              VK_F16, 0 },
+  { XK_F17,              VK_F17, 0 },
+  { XK_F18,              VK_F18, 0 },
+  { XK_F19,              VK_F19, 0 },
+  { XK_F20,              VK_F20, 0 },
+  { XK_F21,              VK_F21, 0 },
+  { XK_F22,              VK_F22, 0 },
+  { XK_F23,              VK_F23, 0 },
+  { XK_F24,              VK_F24, 0 },
+
+  // Keypad Functions, keypad numbers
+
+  { XK_KP_Tab,           VK_TAB, 0 },
+  { XK_KP_Enter,         VK_RETURN, 1 },
+  { XK_KP_F1,            VK_F1, 0 },
+  { XK_KP_F2,            VK_F2, 0 },
+  { XK_KP_F3,            VK_F3, 0 },
+  { XK_KP_F4,            VK_F4, 0 },
+  { XK_KP_Home,          VK_HOME, 0 },
+  { XK_KP_Left,          VK_LEFT, 0 },
+  { XK_KP_Up,            VK_UP, 0 },
+  { XK_KP_Right,         VK_RIGHT, 0 },
+  { XK_KP_Down,          VK_DOWN, 0 },
+  { XK_KP_End,           VK_END, 0 },
+  { XK_KP_Page_Up,       VK_PRIOR, 0 },
+  { XK_KP_Page_Down,     VK_NEXT, 0 },
+  { XK_KP_Begin,         VK_CLEAR, 0 },
+  { XK_KP_Insert,        VK_INSERT, 0 },
+  { XK_KP_Delete,        VK_DELETE, 0 },
+  { XK_KP_Multiply,      VK_MULTIPLY, 0 },
+  { XK_KP_Add,           VK_ADD, 0 },
+  { XK_KP_Separator,     VK_SEPARATOR, 0 },
+  { XK_KP_Subtract,      VK_SUBTRACT, 0 },
+  { XK_KP_Decimal,       VK_DECIMAL, 0 },
+  { XK_KP_Divide,        VK_DIVIDE, 1 },
+
+  { XK_KP_0,             VK_NUMPAD0, 0 },
+  { XK_KP_1,             VK_NUMPAD1, 0 },
+  { XK_KP_2,             VK_NUMPAD2, 0 },
+  { XK_KP_3,             VK_NUMPAD3, 0 },
+  { XK_KP_4,             VK_NUMPAD4, 0 },
+  { XK_KP_5,             VK_NUMPAD5, 0 },
+  { XK_KP_6,             VK_NUMPAD6, 0 },
+  { XK_KP_7,             VK_NUMPAD7, 0 },
+  { XK_KP_8,             VK_NUMPAD8, 0 },
+  { XK_KP_9,             VK_NUMPAD9, 0 },
+
+  // Modifiers
+    
+  { XK_Shift_L,          VK_SHIFT, 0 },
+  { XK_Shift_R,          VK_SHIFT, 0 },
+  { XK_Control_L,        VK_CONTROL, 0 },
+  { XK_Control_R,        VK_CONTROL, 1 },
+  { XK_Alt_L,            VK_MENU, 0 },
+  { XK_Alt_R,            VK_MENU, 1 },
+
+  // Left & Right Windows keys & Windows Menu Key
+
+  { XK_Super_L,          VK_LWIN, 0 },
+  { XK_Super_R,          VK_RWIN, 0 },
+  { XK_Menu,             VK_APPS, 0 },
+
+  // Japanese stuff - almost certainly wrong...
+
+  { XK_Kanji,            VK_KANJI, 0 },
+  { XK_Kana_Shift,       VK_KANA, 0 },
+
+};
diff --git a/win/rfb_win32/rfb_win32.dsp b/win/rfb_win32/rfb_win32.dsp
new file mode 100644 (file)
index 0000000..acfb5aa
--- /dev/null
@@ -0,0 +1,513 @@
+# Microsoft Developer Studio Project File - Name="rfb_win32" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=rfb_win32 - Win32 Debug Unicode\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rfb_win32.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rfb_win32.mak" CFG="rfb_win32 - Win32 Debug Unicode"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "rfb_win32 - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "rfb_win32 - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "rfb_win32 - Win32 Debug Unicode" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "rfb_win32 - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release"\r
+# PROP Intermediate_Dir "..\Release\rfb_win32"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "WIN32" /YX /FD /c\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "rfb_win32 - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug"\r
+# PROP Intermediate_Dir "..\Debug\rfb_win32"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "WIN32" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "rfb_win32 - Win32 Debug Unicode"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "rfb_win32___Win32_Debug_Unicode"\r
+# PROP BASE Intermediate_Dir "rfb_win32___Win32_Debug_Unicode"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug_Unicode"\r
+# PROP Intermediate_Dir "..\Debug_Unicode\rfb_win32"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_LIB" /D "WIN32" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "rfb_win32 - Win32 Release"\r
+# Name "rfb_win32 - Win32 Debug"\r
+# Name "rfb_win32 - Win32 Debug Unicode"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\AboutDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CKeyboard.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CleanDesktop.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Clipboard.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CPointer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CurrentUser.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DeviceContext.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DeviceFrameBuffer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Dialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DIBSectionBuffer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DynamicFn.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\EventManager.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FolderManager.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\LaunchProcess.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ListViewControl.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\LowLevelKeyEvents.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\MonitorInfo.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\MsgWindow.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\OSVersion.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ProgressControl.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\RegConfig.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Registry.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ScaledDIBSectionBuffer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplay.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplayCorePolling.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplayCoreWMHooks.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Security.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Service.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SFileTransferManagerWin32.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SFileTransferWin32.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SInput.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SocketManager.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\TCharArray.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Threading.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ToolBar.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\TsSessions.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Win32Util.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMCursor.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMHooks.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMNotifier.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMPoller.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMShatter.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMWindowCopyRect.cxx\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\AboutDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\BitmapInfo.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CKeyboard.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CleanDesktop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Clipboard.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CompatibleBitmap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ComputerName.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CPointer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CurrentUser.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DeviceContext.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DeviceFrameBuffer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Dialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DIBSectionBuffer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DynamicFn.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\EventManager.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FolderManager.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Handle.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\IconInfo.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\IntervalTimer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\keymap.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\LaunchProcess.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ListViewControl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\LocalMem.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\LogicalPalette.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\LowLevelKeyEvents.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ModuleFileName.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\MonitorInfo.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\MsgBox.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\MsgWindow.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\OSVersion.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ProgressControl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\RegConfig.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Registry.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ScaledDIBSectionBuffer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplay.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplayCoreDriver.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplayCorePolling.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SDisplayCoreWMHooks.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Security.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Service.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SFileTransferManagerWin32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SFileTransferWin32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SInput.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SocketManager.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\TCharArray.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Threading.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ToolBar.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\TrayIcon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\TsSessions.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Win32Util.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMCursor.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMHooks.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMNotifier.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMPoller.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMShatter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\WMWindowCopyRect.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/rfbplayer/ChoosePixelFormatDialog.h b/win/rfbplayer/ChoosePixelFormatDialog.h
new file mode 100644 (file)
index 0000000..ada820b
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- ChoosePixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class ChoosePixelFormatDialog : public rfb::win32::Dialog {
+public:
+  ChoosePixelFormatDialog(PixelFormatList *_supportedPF) 
+  : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), combo(0) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_PIXELFORMAT), parent);
+  }
+  const long getPFIndex() const {return pfIndex;}
+  bool isBigEndian() {return isItemChecked(IDC_BIG_ENDIAN);}
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+    SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+    for (int i = 0; i < supportedPF->count(); i++) {
+      SendMessage(combo, CB_ADDSTRING, 
+        0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+    }
+    SendMessage(combo, CB_SETCURSEL, pfIndex + 1, 0);
+    setItemChecked(IDC_BIG_ENDIAN, bigEndian);
+  }
+  virtual bool onOk() {
+    pfIndex = SendMessage(combo, CB_GETCURSEL, 0, 0) - 1;
+    bigEndian = isItemChecked(IDC_BIG_ENDIAN);
+    return true;
+  }
+  virtual bool onCancel() {
+    return false;
+  }
+  static long pfIndex;
+  static bool bigEndian;
+  PixelFormatList *supportedPF;
+  HWND combo;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/EditPixelFormatDialog.h b/win/rfbplayer/EditPixelFormatDialog.h
new file mode 100644 (file)
index 0000000..0765285
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- EditPixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+#define MAX_STR_LEN 256
+
+class EditPixelFormatDialog : public rfb::win32::Dialog {
+public:
+  EditPixelFormatDialog(PixelFormatList *_supportedPF, char *_format_name,
+                        PixelFormat *_pf) 
+  : Dialog(GetModuleHandle(0)), format_name(_format_name), 
+  supportedPF(_supportedPF), pf(_pf) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_UPF_EDIT), parent);
+  }
+
+protected:
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    HWND bppCombo = GetDlgItem(handle, IDC_BPP_COMBO);
+    SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("8"));
+    SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("16"));
+    SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("32"));
+    SendMessage(bppCombo, CB_SETCURSEL, min(2, (pf->bpp - 8) / 8), 0);
+
+    HWND bigendianCombo = GetDlgItem(handle, IDC_BIGENDIAN_COMBO);
+    SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("No"));
+    SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Yes"));
+    SendMessage(bigendianCombo, CB_SETCURSEL, pf->bigEndian, 0);
+
+    setItemString(IDC_NAME_EDIT, format_name);
+    setItemInt(IDC_DEPTH_EDIT, pf->depth);
+    setItemInt(IDC_REDMAX_EDIT, pf->redMax);
+    setItemInt(IDC_GREENMAX_EDIT, pf->greenMax);
+    setItemInt(IDC_BLUEMAX_EDIT, pf->blueMax);
+    setItemInt(IDC_REDSHIFT_EDIT, pf->redShift);
+    setItemInt(IDC_GREENSHIFT_EDIT, pf->greenShift);
+    setItemInt(IDC_BLUESHIFT_EDIT, pf->blueShift);
+  }
+  virtual bool onOk() {
+    // Check for the errors
+    char err_msg[256] = "\0";
+    if (((getItemString(IDC_NAME_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_DEPTH_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_REDMAX_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_GREENMAX_EDIT))[0] == '\0') ||
+        ((getItemString(IDC_BLUEMAX_EDIT))[0] == '\0') ||
+        ((getItemString(IDC_REDSHIFT_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_GREENSHIFT_EDIT))[0] == '\0') || 
+        ((getItemString(IDC_BLUESHIFT_EDIT))[0] == '\0')) {
+      strcpy(err_msg, "Please fill the all fields in the dialog.");
+    }
+    int newIndex = supportedPF->getIndexByPFName(getItemString(IDC_NAME_EDIT));
+    if ((supportedPF->getIndexByPFName(format_name) != newIndex) && 
+        (newIndex != -1)) {
+      strcpy(err_msg, "The pixel format with that name is already exist.");
+    }
+    if (getItemInt(IDC_DEPTH_EDIT) <= 0) {
+      strcpy(err_msg, "The pixel depth must be larger than 0.");
+    }
+    if (err_msg[0] != 0) {
+      MessageBox(handle, err_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+      return false;
+    }
+    // Fill the pixel format structure
+    strCopy(format_name, getItemString(IDC_NAME_EDIT), MAX_STR_LEN);
+    pf->bpp = getItemInt(IDC_BPP_COMBO);
+    pf->depth = getItemInt(IDC_DEPTH_EDIT);
+    pf->bigEndian = (SendMessage(GetDlgItem(handle, IDC_BIGENDIAN_COMBO), 
+      CB_GETCURSEL, 0, 0)) ? true : false;
+    pf->trueColour = true;
+    pf->redMax = getItemInt(IDC_REDMAX_EDIT);
+    pf->greenMax = getItemInt(IDC_GREENMAX_EDIT);
+    pf->blueMax = getItemInt(IDC_BLUEMAX_EDIT);
+    pf->redShift = getItemInt(IDC_REDSHIFT_EDIT);
+    pf->greenShift = getItemInt(IDC_GREENSHIFT_EDIT);
+    pf->blueShift = getItemInt(IDC_BLUESHIFT_EDIT);
+    return true;
+  }
+
+  char *format_name;
+  PixelFormatList *supportedPF;
+  PixelFormat *pf;
+};
diff --git a/win/rfbplayer/FbsInputStream.cxx b/win/rfbplayer/FbsInputStream.cxx
new file mode 100644 (file)
index 0000000..6381a16
--- /dev/null
@@ -0,0 +1,251 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- FbsInputStream class
+
+#include <windows.h>
+
+#include <rfb/Exception.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+FbsInputStream::FbsInputStream(char* FileName) {
+  bufferSize = 0;
+  ptr = end = start = NULL;
+
+  timeOffset = 0;
+  seekOffset = -1;
+  startTime  = GetTickCount();
+
+  playbackSpeed = 1.0;
+  seekBackwards = false;
+  paused        = false;
+
+  interruptDelay = false;
+
+  fbsFile = fopen(FileName, "rb");
+  if (fbsFile == NULL) {
+    char *msg = new char[12 + sizeof(FileName)];
+    strcpy(msg, "Can't open ");
+    strcat(msg, FileName);
+    throw rfb::Exception(msg);
+  }
+
+  U8 b[12];
+  readNByte(b, 12);
+
+  if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
+      b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
+           b[8]  < '0' || b[8]  > '9' || b[9]  < '0' || b[9] > '9'  ||
+           b[10] < '0' || b[10] > '9' || b[11] != '\n') {
+    throw rfb::Exception("Incorrect protocol version");
+  }
+}
+
+FbsInputStream::~FbsInputStream() {
+  if (start != NULL) 
+    delete [] start;
+  ptr = end = start = NULL;
+  fclose(fbsFile);
+}
+
+int FbsInputStream::pos() {
+  return ptr - start;
+}
+
+//
+// Close FbsInputStream and free data buffer
+//
+
+void FbsInputStream::close() {
+  fclose(fbsFile);
+
+  startTime = -1;
+  timeOffset = 0;
+  seekOffset = -1;
+  seekBackwards = false;
+  paused = false;
+  playbackSpeed = 1.0;
+
+  if (start != NULL)
+    delete [] start;
+  ptr = end = start = NULL;
+  bufferSize = 0;
+}
+
+//
+// Fill data buffer from the session file (InStream::overrun() override)
+//
+
+int FbsInputStream::overrun(int itemSize, int nItems, bool wait=true) {
+  // Just wait unless we are performing playback OR seeking.
+  waitWhilePaused(); 
+  
+  // Perform backwardSeek (throws the special exception)
+  if (seekBackwards) {
+    throw rfb::Exception("[REWIND]");
+  }
+
+  // Save a tail of data
+  U8 *tmp;
+  int n = end - ptr;
+  if (n) {
+    tmp = new U8[n];
+    memmove(tmp, ptr, n);
+  }
+
+  bufferSize = (int)readUnsigned32();
+  if (bufferSize >= 0) {
+    if (start != NULL)
+      delete [] start;
+    int realSize = (bufferSize + 3) & 0xFFFFFFFC; // padding to multiple of 32-bits
+    ptr = start = new U8[realSize + n];
+    end = ptr + bufferSize + n;
+    if (n) {
+      memmove(start, tmp, n);
+      delete [] tmp;
+    }
+    readNByte(start + n, realSize);
+    timeOffset = (long)(readUnsigned32() / playbackSpeed);
+
+    if (itemSize * nItems > bufferSize)
+      nItems = bufferSize / itemSize;
+  }
+
+  if (bufferSize < 0 || timeOffset < 0) {
+    if (start != NULL)
+      delete [] start;
+    ptr = end = start = NULL;
+    bufferSize = 0;
+    return 0;
+  }
+
+  if (seekOffset >= 0) {
+    if (timeOffset >= seekOffset) {
+      startTime = GetTickCount() - seekOffset;
+      seekOffset = -1;
+    } else {
+           return nItems;
+    }
+  }
+
+  while (!interruptDelay) {
+    long timeDiff = startTime + timeOffset - GetTickCount();
+    if (timeDiff <= 0) {
+           break;
+    }
+    Sleep(min(20, timeDiff));
+    waitWhilePaused();
+  }
+  interruptDelay = false;
+
+  return nItems;
+}
+
+int FbsInputStream::readUnsigned32() {
+  U8 buf[4];
+  if (!readNByte(buf, 4))
+    return -1;
+
+  return ((long)(buf[0] & 0xFF) << 24 |
+           (buf[1] & 0xFF) << 16 |
+               (buf[2] & 0xFF) << 8  |
+               (buf[3] & 0xFF)); 
+}
+
+//
+// Read n-bytes from the session file
+//
+
+bool FbsInputStream::readNByte(U8 b[], int n) {
+  int off = 0;
+  
+  while (off != n) {
+    int count = fread(b, 1, n - off, fbsFile);
+    if (count < n) {
+      if (ferror(fbsFile)) 
+        throw rfb::Exception("Read error from session file");
+      if (feof(fbsFile))
+        throw rfb::Exception("[End Of File]");
+    }
+    off += count;
+  }
+  return true;
+}
+
+void FbsInputStream::waitWhilePaused() {
+  while (paused && !isSeeking()) {
+    // A small delay helps to decrease the cpu usage
+    Sleep(20);
+  }
+}
+
+void FbsInputStream::interruptFrameDelay() {
+  interruptDelay = true;
+}
+
+//
+// Methods providing additional functionality.
+//
+
+long FbsInputStream::getTimeOffset() {
+  //long off = max(seekOffset, timeOffset);
+  return (long)(timeOffset * playbackSpeed);
+}
+
+void FbsInputStream::setTimeOffset(long pos) {
+  seekOffset = (long)(pos / playbackSpeed);
+  if (seekOffset < timeOffset) {
+    seekBackwards = true;
+  }
+}
+
+void FbsInputStream::setSpeed(double newSpeed) {
+  long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
+  startTime += timeOffset - newOffset;
+  timeOffset = newOffset;
+  if (isSeeking()) {
+    seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
+  }
+  playbackSpeed = newSpeed;
+}
+
+double FbsInputStream::getSpeed() {
+  return playbackSpeed;
+}
+
+bool FbsInputStream::isSeeking() {
+  return (seekOffset >= 0);
+}
+
+long FbsInputStream::getSeekOffset() {
+  return (long)(seekOffset * playbackSpeed);
+}
+
+bool FbsInputStream::isPaused() {
+  return paused;
+}
+
+void FbsInputStream::pausePlayback() {
+  paused = true;
+}
+
+void FbsInputStream::resumePlayback() {
+  paused = false;
+  startTime = GetTickCount() - timeOffset;
+}
diff --git a/win/rfbplayer/FbsInputStream.h b/win/rfbplayer/FbsInputStream.h
new file mode 100644 (file)
index 0000000..9649273
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- FbsInputStream.h
+
+#include <rdr/InStream.h>
+
+using namespace rdr;
+
+class FbsInputStream : public InStream {
+  public:
+    FbsInputStream(char *FileName);
+    ~FbsInputStream();
+
+    // Methods are used to contol the Rfb Stream
+    long getTimeOffset();
+    void setTimeOffset(long pos);
+    double getSpeed();
+    void setSpeed(double newSpeed);
+    bool isSeeking();
+    long getSeekOffset();
+    bool isPaused();
+    void pausePlayback();
+    void resumePlayback();
+    void interruptFrameDelay();
+    void close();
+    int  pos();
+
+  private:
+    U8 *start;
+    int bufferSize;
+    long startTime;
+    long timeOffset;
+    long seekOffset;
+    double playbackSpeed;
+    bool seekBackwards;
+    bool paused;
+    bool interruptDelay;
+
+    FILE  *fbsFile;
+
+    // overrun() - overrides InStream::overrun().
+    // It is implemented to fill the data buffer from the session file.
+    // It ensures there are at least itemSize bytes of buffer data.  Returns
+    // the number of items in the buffer (up to a maximum of nItems).  itemSize
+    // is supposed to be "small" (a few bytes).
+
+    int overrun(int itemSize, int nItems, bool wait);
+
+    int readUnsigned32();
+    bool readNByte(U8 *b, int n);
+    void waitWhilePaused();
+};
diff --git a/win/rfbplayer/GotoPosDialog.h b/win/rfbplayer/GotoPosDialog.h
new file mode 100644 (file)
index 0000000..ddbbe53
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- GotoPosDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class GotoPosDialog : public rfb::win32::Dialog {
+public:
+  GotoPosDialog() : Dialog(GetModuleHandle(0)) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_GOTO), parent);
+  }
+  const long getPos() const {return pos;}
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    setItemString(IDC_GOTO_EDIT, rfb::TStr("0"));
+  }
+  virtual bool onOk() {
+    pos = atol(rfb::CStr(getItemString(IDC_GOTO_EDIT)));
+    return true;
+  }
+
+  long pos;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/InfoDialog.h b/win/rfbplayer/InfoDialog.h
new file mode 100644 (file)
index 0000000..bbe9b26
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- InfoDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class InfoDialog : public rfb::win32::Dialog {
+public:
+  InfoDialog(char *_info_message, char *_title = "Information") 
+  : Dialog(GetModuleHandle(0)), info_message(_info_message), title(_title) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent = 0) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_INFO), parent);
+  }
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    SetWindowText(handle, title);
+    setItemString(IDC_INFO_EDIT, info_message);
+  }
+  char *info_message;
+  char *title;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/OptionsDialog.h b/win/rfbplayer/OptionsDialog.h
new file mode 100644 (file)
index 0000000..8c3a87d
--- /dev/null
@@ -0,0 +1,112 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- OptionsDialog.h
+
+#include <rfbplayer/PlayerOptions.h>
+#include <rfbplayer/UserPixelFormatsDialog.h>
+
+class OptionsDialog : public rfb::win32::Dialog {
+public:
+  OptionsDialog(PlayerOptions *_options, PixelFormatList *_supportedPF) 
+  : Dialog(GetModuleHandle(0)), options(_options), combo(0),
+  supportedPF(_supportedPF) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_OPTIONS), parent);
+  }
+protected:
+
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+    SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+    for (int i = 0; i < supportedPF->count(); i++) {
+      SendMessage(combo, CB_ADDSTRING, 
+        0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+    }
+    SendMessage(combo, CB_SETCURSEL, options->pixelFormatIndex + 1, 0);
+    setItemChecked(IDC_ACCEPT_BELL, options->acceptBell);
+    setItemChecked(IDC_ACCEPT_CUT_TEXT, options->acceptCutText);
+    setItemChecked(IDC_AUTOPLAY, options->autoPlay);
+    setItemChecked(IDC_BIG_ENDIAN, options->bigEndianFlag);
+    if (options->askPixelFormat) {
+      setItemChecked(IDC_ASK_PF, true);
+      enableItem(IDC_PIXELFORMAT, false);
+      enableItem(IDC_BIG_ENDIAN, false);
+    }
+  }
+  virtual bool onOk() {
+    options->askPixelFormat = isItemChecked(IDC_ASK_PF);
+    options->acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+    options->acceptCutText = isItemChecked(IDC_ACCEPT_CUT_TEXT);
+    options->autoPlay = isItemChecked(IDC_AUTOPLAY);
+    options->bigEndianFlag = isItemChecked(IDC_BIG_ENDIAN);
+    if (!options->askPixelFormat) {
+      options->pixelFormatIndex = int(SendMessage(combo, CB_GETCURSEL, 0, 0)) - 1;
+      if (options->pixelFormatIndex < 0) {
+        options->autoDetectPF = true;
+      } else {
+        options->setPF(&((*supportedPF)[options->pixelFormatIndex])->PF);
+        options->pixelFormat.bigEndian = options->bigEndianFlag;
+        options->autoDetectPF = false;
+      }
+    }
+    options->writeToRegistry();
+    return true;
+  }
+  virtual bool onCommand(int item, int cmd) { 
+    if (item == IDC_ASK_PF) {
+      enableItem(IDC_PIXELFORMAT, !isItemChecked(IDC_ASK_PF));
+      enableItem(IDC_BIG_ENDIAN, !isItemChecked(IDC_ASK_PF));
+    }
+    if (item == IDC_DEFAULT) {
+      SendMessage(combo, CB_SETCURSEL, DEFAULT_PF_INDEX + 1, 0);
+      enableItem(IDC_PIXELFORMAT, !DEFAULT_ASK_PF);
+      enableItem(IDC_BIG_ENDIAN, !DEFAULT_ASK_PF);
+      setItemChecked(IDC_ASK_PF, DEFAULT_ASK_PF);
+      setItemChecked(IDC_ACCEPT_BELL, DEFAULT_ACCEPT_BELL);
+      setItemChecked(IDC_ACCEPT_CUT_TEXT, DEFAULT_ACCEPT_CUT_TEXT);
+      setItemChecked(IDC_AUTOPLAY, DEFAULT_AUTOPLAY);
+      setItemChecked(IDC_BIG_ENDIAN, DEFAULT_BIG_ENDIAN);
+    }
+    if (item == IDC_EDIT_UPF) {
+      UserPixelFormatsDialog UpfListDialog(supportedPF);
+      if (UpfListDialog.showDialog(handle)) {
+        int index = SendMessage(combo, CB_GETCURSEL, 0, 0);
+        SendMessage(combo, CB_RESETCONTENT, 0, 0);
+        SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+        for (int i = 0; i < supportedPF->count(); i++) {
+          SendMessage(combo, CB_ADDSTRING, 
+            0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+        }
+        if ( index > (SendMessage(combo, CB_GETCOUNT, 0, 0) - 1)) {
+          index = SendMessage(combo, CB_GETCOUNT, 0, 0) - 1;
+        }
+        SendMessage(combo, CB_SETCURSEL, index, 0);
+        options->pixelFormatIndex = index - 1;
+      }
+    }
+    return false;
+  }
+
+  HWND combo;
+  PlayerOptions *options;
+  PixelFormatList *supportedPF;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.cxx b/win/rfbplayer/PixelFormatList.cxx
new file mode 100644 (file)
index 0000000..25996f6
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- PixelFormatList class
+
+#include <rfbplayer/PixelFormatList.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+PixelFormatList::PixelFormatList() {
+  PixelFormatListElement PFElem;
+  
+  // -=- Add the default pixel formats to list
+  // PF_BGR233
+  PFElem.setName("8-bits depth (BGR233)");
+  PFElem.setPF(&PixelFormat(8,8,0,1,7,7,3,0,3,6));
+  PFList.push_back(PFElem);
+  // PF_RGB555
+  PFElem.setName("15-bits depth (RGB555)");
+  PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,10,5,0));
+  PFList.push_back(PFElem);
+  // PF_BGR555
+  PFElem.setName("15-bits depth (BGR555)");
+  PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,0,5,10));
+  PFList.push_back(PFElem);
+  // PF_RGB565
+  PFElem.setName("16-bits depth (RGB565)");
+  PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,11,5,0));
+  PFList.push_back(PFElem);
+  // PF_BGR565
+  PFElem.setName("16-bits depth (BGR565)");
+  PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,0,5,11));
+  PFList.push_back(PFElem);
+  // PF_RGB888
+  PFElem.setName("24-bits depth (RGB888)");
+  PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,16,8,0));
+  PFList.push_back(PFElem);
+  // PF_BGR888
+  PFElem.setName("24-bits depth (BGR888)");
+  PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,0,8,16));
+  PFList.push_back(PFElem);
+
+  PF_DEFAULT_COUNT = PFList.size();
+}
+
+PixelFormatListElement *PixelFormatList::operator[](int index) {
+  return &(*getIterator(index));
+}
+
+void PixelFormatList::add(char *format_name, PixelFormat PF) {
+  PixelFormatListElement PFElem;
+  PFElem.setName(format_name);
+  PFElem.setPF(&PF);
+  PFList.push_back(PFElem);
+}
+
+void PixelFormatList::insert(int index, char *format_name, PixelFormat PF) {
+  if (isDefaultPF(index)) 
+    rdr::Exception("PixelFormatList:can't insert to the default pixel format place");
+
+  PixelFormatListElement PFElem;
+  PFElem.setName(format_name);
+  PFElem.setPF(&PF);
+  PFList.insert(getIterator(index), PFElem);
+}
+
+void PixelFormatList::remove(int index) {
+  if (isDefaultPF(index)) 
+    rdr::Exception("PixelFormatList:can't remove the default pixel format");
+  PFList.erase(getIterator(index));
+}
+
+list <PixelFormatListElement>::iterator PixelFormatList::getIterator(int index) {
+  if ((index >= PFList.size()) || (index < 0))
+    rdr::Exception("PixelFormatList:out of range");
+
+  int i = 0;
+  list <PixelFormatListElement>::iterator iter;
+  for (iter = PFList.begin(); iter != PFList.end(); iter++) {
+    if (i++ == index) break;
+  }
+  return iter;
+}
+
+bool PixelFormatList::isDefaultPF(int index) {
+  if (index < PF_DEFAULT_COUNT) return true;
+  return false;
+}
+
+void PixelFormatList::readUserDefinedPF(HKEY root, const char *keypath) {
+  RegKey regKey;
+  regKey.createKey(root, keypath);
+  int count = regKey.getInt(_T("PixelFormatCount"), 0);
+  if (count > 0) {
+    // Erase all user defined pixel formats
+    int upf_count = getUserPFCount();
+    if (upf_count > 0) {
+      for(int i = 0; i < upf_count; i++) {
+        remove(PF_DEFAULT_COUNT);
+      }
+    }
+    // Add the user defined pixel formats from the registry
+    for(int i = 0; i < count; i++) {
+      char upf_name[20] = "\0";
+      sprintf(upf_name, "%s%i", "Upf", i);
+      int size = sizeof(PixelFormatListElement);
+      PixelFormatListElement *pPFElem = 0;// = &PFElem;
+      regKey.getBinary(upf_name, (void**)&pPFElem, &size);
+      PFList.push_back(*pPFElem);
+      if (pPFElem) delete pPFElem;
+    }
+  }
+}
+
+void PixelFormatList::writeUserDefinedPF(HKEY root, const char *keypath) {
+  RegKey regKey;
+
+  // Delete all user defined pixel formats from the regisry
+  regKey.createKey(root, keypath);//_T("Software\\TightVnc\\RfbPlayer\\UserDefinedPF"));
+  int count = regKey.getInt(_T("PixelFormatCount"), 0);
+  for (int i = 0; i < count; i++) {
+    char upf_name[20] = "\0";
+    sprintf(upf_name, "%s%i", "Upf", i);
+    regKey.deleteValue(upf_name);
+  }
+  regKey.setInt(_T("PixelFormatCount"), 0);
+
+  // Write new user defined pixel formats to the registry
+  regKey.setInt(_T("PixelFormatCount"), getUserPFCount());
+  for (i = 0; i < getUserPFCount(); i++) {
+    char upf_name[20] = "\0";
+    sprintf(upf_name, "%s%i", "Upf", i);
+    regKey.setBinary(upf_name, (void *)operator[](i+getDefaultPFCount()), 
+      sizeof(PixelFormatListElement));
+  }
+}
+
+int PixelFormatList::getIndexByPFName(const char *format_name) {
+  for (int i = 0; i < PixelFormatList::count(); i++) {
+    if (_stricmp(operator[](i)->format_name, format_name) == 0) return i;
+  }
+  return -1;
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.h b/win/rfbplayer/PixelFormatList.h
new file mode 100644 (file)
index 0000000..cd7c50a
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- PixelFormatList.h
+
+// Definition of the PixelFormatList class, responsible for 
+// controlling the list of supported pixel formats.
+
+#include <list>
+
+#include <rfb/Exception.h>
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+// Definition indexes of the default pixel formats
+#define PF_BGR233 0
+#define PF_RGB555 1
+#define PF_BGR555 2
+#define PF_RGB565 3
+#define PF_BGR565 4
+#define PF_RGB888 5
+#define PF_BGR888 6
+
+using namespace rfb;
+using namespace std;
+
+// PixelFormatListElement class, it is 
+// an item of the PixelFormatList list.
+
+class PixelFormatListElement {
+public:
+  PixelFormatListElement() {
+    format_name[0] = 0;
+  }
+  char format_name[256];
+  PixelFormat PF;
+  void setName(const char *name) {
+    format_name[0] = '\0';
+    strcpy(format_name, name);
+    format_name[strlen(name)] = '\0';
+  }
+  void setPF(PixelFormat *_PF) {
+    memcpy(&PF, _PF, sizeof(PixelFormat));
+  }
+};
+
+class PixelFormatList {
+public:
+  PixelFormatList();
+
+  PixelFormatListElement* operator[](int index);
+  void add(char *format_name, PixelFormat PF);
+  void insert(int index, char *format_name, PixelFormat PF);
+  void remove(int index);
+
+  void readUserDefinedPF(HKEY root, const char *keypath);
+  void writeUserDefinedPF(HKEY root, const char *keypath);
+  
+  int count() { return PFList.size(); }
+  int getDefaultPFCount() { return  PF_DEFAULT_COUNT; }
+  int getUserPFCount() { return max(0, count() - PF_DEFAULT_COUNT); }
+  int getIndexByPFName(const char *format_name);
+  bool isDefaultPF(int index);
+
+protected:
+  list <PixelFormatListElement>::iterator getIterator(int index);
+  list <PixelFormatListElement> PFList;
+  int PF_DEFAULT_COUNT;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.cxx b/win/rfbplayer/PlayerOptions.cxx
new file mode 100644 (file)
index 0000000..5384c6e
--- /dev/null
@@ -0,0 +1,152 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- PlayerOptions class
+
+#include <rfbplayer/PlayerOptions.h>
+
+using namespace rfb::win32;
+
+PlayerOptions::PlayerOptions() { 
+  writeDefaults();
+};
+
+void PlayerOptions::readFromRegistry() {
+  try {
+    PixelFormat *pPF = 0;
+    int pfSize = sizeof(PixelFormat);
+    RegKey regKey;
+    regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+    autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+    autoDetectPF = regKey.getBool(_T("AutoDetectPixelFormat"), DEFAULT_AUTOPF);
+    bigEndianFlag = regKey.getBool(_T("BigEndianFlag"), DEFAULT_BIG_ENDIAN);
+    pixelFormatIndex = regKey.getInt(_T("PixelFormatIndex"), DEFAULT_PF_INDEX);
+    regKey.getBinary(_T("PixelFormat"), (void**)&pPF, &pfSize, 
+      &PixelFormat(32,24,0,1,255,255,255,16,8,0), sizeof(PixelFormat));
+    setPF(pPF);
+    acceptBell = regKey.getBool(_T("AcceptBell"), DEFAULT_ACCEPT_BELL);
+    acceptCutText = regKey.getBool(_T("AcceptCutText"), DEFAULT_ACCEPT_CUT_TEXT);
+    autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+    askPixelFormat = regKey.getBool(_T("AskPixelFormat"), DEFAULT_ASK_PF);
+    if (pPF) delete pPF;
+  } catch (rdr::Exception e) {
+    MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+  }
+}
+
+void PlayerOptions::writeToRegistry() {
+  try {
+    RegKey regKey;
+    regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+    regKey.setBool(_T("AutoPlay"), autoPlay);
+    regKey.setBool(_T("AutoDetectPixelFormat"), autoDetectPF);
+    regKey.setBool(_T("BigEndianFlag"), bigEndianFlag);
+    regKey.setInt(_T("PixelFormatIndex"), pixelFormatIndex);
+    regKey.setBinary(_T("PixelFormat"), &pixelFormat, sizeof(PixelFormat));
+    regKey.setBool(_T("AcceptBell"), acceptBell);
+    regKey.setBool(_T("AcceptCutText"), acceptCutText);
+    regKey.setBool(_T("AutoPlay"), autoPlay);
+    regKey.setBool(_T("AskPixelFormat"), askPixelFormat);
+  } catch (rdr::Exception e) {
+    MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+  }
+}
+
+void PlayerOptions::writeDefaults() {
+  initTime = DEFAULT_INIT_TIME;
+  playbackSpeed = DEFAULT_SPEED;
+  autoDetectPF = DEFAULT_AUTOPF;
+  bigEndianFlag = DEFAULT_BIG_ENDIAN;
+  pixelFormatIndex = DEFAULT_PF_INDEX;
+  pixelFormat = PixelFormat(32,24,0,1,255,255,255,16,8,0);
+  frameScale = DEFAULT_FRAME_SCALE;
+  autoPlay = DEFAULT_AUTOPLAY;
+  fullScreen = DEFAULT_FULL_SCREEN;
+  acceptBell = DEFAULT_ACCEPT_BELL; 
+  acceptCutText = DEFAULT_ACCEPT_CUT_TEXT;
+  loopPlayback = DEFAULT_LOOP_PLAYBACK;
+  askPixelFormat = DEFAULT_ASK_PF; 
+  commandLineParam = false;
+}
+
+void PlayerOptions::setPF(PixelFormat *newPF) {
+  memcpy(&pixelFormat, newPF, sizeof(PixelFormat));
+}
+
+bool PlayerOptions::setPF(int rgb_order, int rm, int gm, int bm, bool big_endian) {
+  PixelFormat newPF;
+  
+  // Calculate the colour bits per pixel
+  int bpp = rm + gm + bm;
+  if (bpp < 0) {
+    return false;
+  } else if (bpp <= 8 ) {
+    newPF.bpp = 8;
+  } else if (bpp <= 16) {
+    newPF.bpp = 16;
+  } else if (bpp <= 32) {
+    newPF.bpp = 32;
+  } else {
+    return false;
+  }
+  newPF.depth = bpp;
+
+  // Calculate the r, g and b bits shifts
+  switch (rgb_order) {
+  case RGB_ORDER:
+    newPF.redShift = gm + bm;
+    newPF.greenShift = bm;
+    newPF.blueShift = 0;
+    break;
+  case RBG_ORDER:
+    newPF.redShift = bm + gm;
+    newPF.blueShift = gm;
+    newPF.greenShift = 0;
+    break;
+  case GRB_ORDER:
+    newPF.greenShift = rm + bm;
+    newPF.redShift = bm;
+    newPF.blueShift = 0;
+    break;
+  case GBR_ORDER:
+    newPF.greenShift = bm + rm;
+    newPF.blueShift = rm;
+    newPF.redShift = 0;
+    break;
+  case BGR_ORDER:
+    newPF.blueShift = gm + rm;
+    newPF.greenShift = rm;
+    newPF.redShift = 0;
+    break;
+  case BRG_ORDER:
+    newPF.blueShift = rm + gm;
+    newPF.redShift = gm;
+    newPF.greenShift = 0;
+    break;
+  default:
+    return false;
+  }
+
+  newPF.trueColour = true;
+  newPF.bigEndian = big_endian;
+  newPF.redMax = (1 << rm) - 1;
+  newPF.greenMax = (1 << gm) - 1;
+  newPF.blueMax = (1 << bm) - 1;
+  setPF(&newPF);
+  return true;
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.h b/win/rfbplayer/PlayerOptions.h
new file mode 100644 (file)
index 0000000..83618a7
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- PlayerOptions.h
+
+// Definition of the PlayerOptions class, responsible for 
+// storing & retrieving the RfbPlayer's options.
+
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+#define PF_MODES 3
+
+// The R, G and B values order in the pixel
+#define RGB_ORDER 0
+#define RBG_ORDER 1
+#define GRB_ORDER 2
+#define GBR_ORDER 3
+#define BGR_ORDER 4
+#define BRG_ORDER 5
+
+// Default options values
+//#define DEFAULT_PF 0
+#define DEFAULT_PF_INDEX -1
+#define DEFAULT_AUTOPF TRUE
+#define DEFAULT_INIT_TIME -1
+#define DEFAULT_SPEED 1.0
+#define DEFAULT_FRAME_SCALE 100
+#define DEFAULT_ACCEPT_BELL FALSE
+#define DEFAULT_ACCEPT_CUT_TEXT FALSE
+#define DEFAULT_BIG_ENDIAN FALSE
+#define DEFAULT_LOOP_PLAYBACK FALSE
+#define DEFAULT_ASK_PF FALSE
+#define DEFAULT_AUTOPLAY FALSE
+#define DEFAULT_FULL_SCREEN FALSE
+
+using namespace rfb;
+
+class PlayerOptions {
+public:
+  PlayerOptions();
+  void readFromRegistry();
+  void writeToRegistry();
+  void writeDefaults();
+  void setPF(PixelFormat *pf);
+  bool setPF(int rgb_order, int rm, int gm, int bm, bool big_endian=false);
+  long initTime;
+  double playbackSpeed;
+  bool autoPlay;
+  bool fullScreen;
+  bool autoDetectPF;
+  bool bigEndianFlag;
+  long pixelFormatIndex;
+  PixelFormat pixelFormat;
+  bool acceptBell;
+  bool acceptCutText;
+  bool loopPlayback;
+  bool askPixelFormat;
+  long frameScale;
+  bool commandLineParam;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.cxx b/win/rfbplayer/PlayerToolBar.cxx
new file mode 100644 (file)
index 0000000..3056f28
--- /dev/null
@@ -0,0 +1,248 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- PlayerToolBar.cxx
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/resource.h>
+
+PlayerToolBar::PlayerToolBar() 
+: ToolBar(), hFont(0), timeStatic(0), speedEdit(0), posTrackBar(0),
+  speedUpDown(0), sliderDragging(false), sliderStepMs(0)
+{
+}
+
+void PlayerToolBar::create(RfbPlayer *player_, HWND parentHwnd_) {
+  HDC hdc;
+  SIZE sz;
+  RECT tRect;
+  NONCLIENTMETRICS nonClientMetrics;
+
+  player = player_;
+
+  // Get the default font for the main menu
+  nonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);
+  if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nonClientMetrics, 0))
+    MessageBox(0, "Can't access to the system font.", 
+               "RfbPlayer", MB_OK | MB_ICONERROR);
+  nonClientMetrics.lfMenuFont.lfHeight = 16;
+  hFont = CreateFontIndirect(&nonClientMetrics.lfMenuFont);
+
+  // Create the toolbar panel
+  ToolBar::create(ID_TOOLBAR, parentHwnd_,
+                  WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NORESIZE);
+  addBitmap(4, IDB_TOOLBAR);
+
+  // Create the control buttons
+  addButton(0, ID_PLAY);
+  addButton(1, ID_PAUSE);
+  addButton(2, ID_STOP);
+  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+  // Create the static control for the time output
+  timeStatic = CreateWindowEx(0, "Static", "00m:00s (00m:00s)", 
+    WS_CHILD | WS_VISIBLE, 0, 0, 20, 20, getHandle(), (HMENU)ID_TIME_STATIC, 
+    GetModuleHandle(0), 0);
+  SendMessage(timeStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+  hdc = GetDC(timeStatic);
+  SelectObject(hdc, hFont);
+  GetTextExtentPoint32(hdc, "00m:00s (00m:00s)", 16, &sz);
+  addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(4, &tRect);
+  MoveWindow(timeStatic, tRect.left, tRect.top+2, tRect.right-tRect.left, 
+    tRect.bottom-tRect.top, FALSE);
+    
+  // Create the trackbar control for the time position
+  addButton(200, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(6, &tRect);
+  posTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, "Trackbar Control", 
+    WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE,
+    tRect.left, tRect.top, tRect.right-tRect.left, tRect.bottom-tRect.top,
+    parentHwnd, (HMENU)ID_POS_TRACKBAR, GetModuleHandle(0), 0);
+  // It's need to send notify messages to toolbar parent window
+  SetParent(posTrackBar, getHandle());
+  addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+  // Create the label with "Speed:" caption
+  HWND speedStatic = CreateWindowEx(0, "Static", "Speed:", WS_CHILD | WS_VISIBLE, 
+    0, 0, 5, 5, getHandle(), (HMENU)ID_SPEED_STATIC, GetModuleHandle(0), 0);
+  SendMessage(speedStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+  hdc = GetDC(speedStatic);
+  SelectObject(hdc, hFont);
+  GetTextExtentPoint32(hdc, "Speed:", 6, &sz);
+  addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(8, &tRect);
+  MoveWindow(speedStatic, tRect.left, tRect.top+2, tRect.right-tRect.left, 
+    tRect.bottom-tRect.top, FALSE);
+
+  // Create the edit control and the spin for the speed managing
+  addButton(60, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+  getButtonRect(9, &tRect);
+  speedEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "1.00", 
+    WS_CHILD | WS_VISIBLE | ES_RIGHT, tRect.left, tRect.top, 
+    tRect.right-tRect.left, tRect.bottom-tRect.top, parentHwnd,
+    (HMENU)ID_SPEED_EDIT, GetModuleHandle(0), 0);
+  SendMessage(speedEdit, WM_SETFONT,(WPARAM) hFont, TRUE);
+  // It's need to send notify messages to toolbar parent window
+  SetParent(speedEdit, getHandle());
+
+  speedUpDown = CreateUpDownControl(WS_CHILD | WS_VISIBLE  
+    | WS_BORDER | UDS_ALIGNRIGHT, 0, 0, 0, 0, getHandle(),
+    ID_SPEED_UPDOWN, GetModuleHandle(0), speedEdit, 20, 1, 2);
+
+  // Resize the toolbar window
+  autoSize();
+}
+
+void PlayerToolBar::init(long sessionTimeMs_) {
+  sessionTimeMs = sessionTimeMs_;
+
+  setSessionTimeStr(sessionTimeMs);
+  SendMessage(posTrackBar, TBM_SETRANGE, 
+    TRUE, MAKELONG(0, min(sessionTimeMs / 1000, MAX_POS_TRACKBAR_RANGE)));
+  if (sessionTimeMs == 0) {
+    sliderStepMs = 1;
+  } else {
+    sliderStepMs = sessionTimeMs / SendMessage(posTrackBar, TBM_GETRANGEMAX, 0, 0);
+  }
+  updatePos(0);
+}
+
+void PlayerToolBar::enable() {
+  enableButton(ID_PLAY, true);
+  enableButton(ID_PAUSE, true);
+  enableButton(ID_STOP, true);
+  enableButton(ID_FULLSCREEN, true);
+  EnableWindow(posTrackBar, true);
+  EnableWindow(speedEdit, true);
+  EnableWindow(speedUpDown, true);
+}
+
+void PlayerToolBar::disable() {
+  enableButton(ID_PLAY, false);
+  enableButton(ID_PAUSE, false);
+  enableButton(ID_STOP, false);
+  enableButton(ID_FULLSCREEN, false);
+  EnableWindow(posTrackBar, false);
+  EnableWindow(speedEdit, false);
+  EnableWindow(speedUpDown, false);
+}
+
+LRESULT PlayerToolBar::processWM_COMMAND(WPARAM wParam, LPARAM lParam) {
+  switch (LOWORD(wParam)) {
+
+  case ID_RETURN:
+    // Update the speed if return pressed in speedEdit
+    if (getSpeedEditHwnd() == GetFocus()) {
+      char speedStr[20], *stopStr;
+      GetWindowText(getSpeedEditHwnd(), speedStr, sizeof(speedStr));
+      double speed = strtod(speedStr, &stopStr);
+      if (speed > 0) {
+        speed = min(MAX_SPEED, speed);
+      } else {
+        speed = player->getSpeed();
+      }
+      player->setSpeed(speed);
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_HSCROLL(WPARAM wParam, LPARAM lParam) {
+  long Pos = SendMessage(posTrackBar, TBM_GETPOS, 0, 0);
+  Pos *= sliderStepMs;
+
+  switch (LOWORD(wParam)) { 
+  case TB_PAGEUP:
+  case TB_PAGEDOWN:
+  case TB_LINEUP:
+  case TB_LINEDOWN:
+  case TB_THUMBTRACK:
+    sliderDragging = true;
+    updatePos(Pos);
+    return FALSE;
+  case TB_THUMBPOSITION:
+  case TB_ENDTRACK: 
+    player->setPos(Pos);
+    player->setPaused(player->isPaused());;
+    updatePos(Pos);
+    sliderDragging = false;
+    return FALSE;
+  default:
+    break;
+  }
+  
+  return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+  switch (((NMHDR*)lParam)->code) {
+  case UDN_DELTAPOS:
+    if ((int)wParam == ID_SPEED_UPDOWN) {
+      char speedStr[20] = "\0";
+      DWORD speedRange = SendMessage(speedUpDown, UDM_GETRANGE, 0, 0);
+      LPNM_UPDOWN upDown = (LPNM_UPDOWN)lParam;
+      double speed;
+
+      // The out of range checking
+      if (upDown->iDelta > 0) {
+        speed = min(upDown->iPos + upDown->iDelta, LOWORD(speedRange)) * 0.5;
+      } else {
+        // It's need to round the UpDown position
+        if ((upDown->iPos * 0.5) != player->getSpeed()) {
+          upDown->iDelta = 0;
+        }
+        speed = max(upDown->iPos + upDown->iDelta, HIWORD(speedRange)) * 0.5;
+      }
+      player->setSpeed(speed);
+    }
+  }
+
+  // We always return TRUE to prevent the change in the updown contol 
+  // position. The control's position changes in the RfbPlayer::setSpeed().
+  return TRUE;
+}
+
+void PlayerToolBar::updatePos(long newPos) {
+  // Update time pos in static control
+  char timePos[30] = "\0";
+  long time = newPos / 1000;
+  sprintf(timePos, "%.2um:%.2us (%s)", time/60, time%60, fullSessionTimeStr);
+  SetWindowText(timeStatic, timePos);
+
+  // Update the position of slider
+  if (!sliderDragging) {
+    double error = SendMessage(posTrackBar, TBM_GETPOS, 0, 0) * 
+      sliderStepMs / double(newPos);
+    if (!((error > 1 - CALCULATION_ERROR) && (error <= 1 + CALCULATION_ERROR))) {
+      SendMessage(posTrackBar, TBM_SETPOS, TRUE, newPos / sliderStepMs);
+    }
+  }
+}
+
+void PlayerToolBar::setSessionTimeStr(long sessionTimeMs) {
+  sprintf(fullSessionTimeStr, "%.2um:%.2us", 
+    sessionTimeMs / 1000 / 60, sessionTimeMs / 1000 % 60);
+}
+
+void PlayerToolBar::setTimePos(long pos) {
+  SendMessage(posTrackBar, TBM_SETPOS, TRUE, pos);
+}
\ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.h b/win/rfbplayer/PlayerToolBar.h
new file mode 100644 (file)
index 0000000..17ab82e
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- PlayerToolBar.h
+
+// ToolBar for the RfbPlayer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+#define ID_TOOLBAR 500
+#define ID_PLAY 510
+#define ID_PAUSE 520
+#define ID_TIME_STATIC 530
+#define ID_SPEED_STATIC 540
+#define ID_SPEED_EDIT 550
+#define ID_POS_TRACKBAR 560
+#define ID_SPEED_UPDOWN 570
+
+#define MAX_SPEED 10.00
+#define CALCULATION_ERROR MAX_SPEED / 1000
+#define MAX_POS_TRACKBAR_RANGE 50
+
+class RfbPlayer;
+
+class PlayerToolBar : public ToolBar {
+public:
+  PlayerToolBar();
+  ~PlayerToolBar() {}
+
+  void create(RfbPlayer *player, HWND parentHwnd);
+
+  void init(long sessionTimeMs);
+
+  void enable();
+  void disable();
+
+  LRESULT processWM_COMMAND(WPARAM wParam, LPARAM lParam);
+  LRESULT processWM_HSCROLL(WPARAM wParam, LPARAM lParam);
+  LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+  HWND getSpeedEditHwnd() { return speedEdit; }
+  HWND getSpeedUpDownHwnd() { return speedUpDown; }
+
+  bool isPosSliderDragging() { return sliderDragging; };
+  void updatePos(long newPos);
+  void setSessionTimeStr(long sessionTimeMs);
+  void setTimePos(long newPos);
+
+protected:
+  RfbPlayer *player;
+  HFONT hFont;
+  HWND timeStatic;
+  HWND speedEdit;
+  HWND posTrackBar;
+  HWND speedUpDown;
+  char fullSessionTimeStr[20];
+  long sessionTimeMs;
+  bool sliderDragging;
+  long sliderStepMs;
+};
diff --git a/win/rfbplayer/RfbProto.cxx b/win/rfbplayer/RfbProto.cxx
new file mode 100644 (file)
index 0000000..5a7ff7f
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- RFB Protocol
+
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+static LogWriter vlog("RfbProto");
+
+//
+// Constructor
+//
+
+RfbProto::RfbProto(char *fileName) {
+  is = NULL;
+  reader = NULL;
+  newSession(fileName);
+}
+
+//
+// Destructor
+//
+
+RfbProto::~RfbProto() {
+  if (is) delete is;
+  is = 0;
+  if (reader) delete reader;
+  reader = 0;
+}
+
+void RfbProto::newSession(char *fileName) {
+  // Close the previous session
+  if (is) {
+    delete is;
+    is = NULL;
+    delete reader;
+    reader = NULL;
+  }
+
+  // Begin the new session
+  if (fileName != NULL) {
+    is = new FbsInputStream(fileName);
+    reader = new CMsgReaderV3(this, is);
+    initialiseProtocol();
+  }
+}
+
+void RfbProto::initialiseProtocol() {
+  state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void RfbProto::processMsg()
+{
+  switch (state_) {
+
+  case RFBSTATE_PROTOCOL_VERSION: processVersionMsg();       break;
+  case RFBSTATE_SECURITY:         processSecurityMsg();      break;
+  case RFBSTATE_INITIALISATION:   processInitMsg();          break;
+  case RFBSTATE_NORMAL:           reader->readMsg();         break;
+  default:
+    throw rfb::Exception("RfbProto::processMsg: invalid state");
+  }
+}
+
+void RfbProto::processVersionMsg()
+{
+  vlog.debug("reading protocol version");
+  memset(&cp, 0, sizeof(cp));
+  bool done;
+  if (!cp.readVersion(is, &done)) {
+    state_ = RFBSTATE_INVALID;
+    throw rfb::Exception("reading version failed: wrong file format?");
+  }
+  if (!done) return;
+
+  // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+  if (!cp.isVersion(3,3) && !cp.isVersion(3,7) && !cp.isVersion(3,8)) {
+    char msg[256];
+    sprintf(msg,"File have unsupported RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+    state_ = RFBSTATE_INVALID;
+    throw rfb::Exception(msg);
+  }
+
+  state_ = RFBSTATE_SECURITY;
+
+  vlog.info("Using RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+}
+
+void RfbProto::processSecurityMsg()
+{
+  vlog.debug("processing security types message");
+
+  int secType = secTypeInvalid;
+
+  // legacy 3.3 server may only offer "vnc authentication" or "none"
+  secType = is->readU32();
+  if (secType == secTypeInvalid) {
+    int reasonLen = is->readU32();
+    char *reason = new char[reasonLen];
+    is->readBytes(reason, reasonLen);
+    throw rfb::Exception(reason); 
+  }
+
+  if (secType != secTypeNone) {
+    throw rfb::Exception("Wrong authentication type in the session file");
+  }
+
+  state_ = RFBSTATE_INITIALISATION;
+}
+
+void RfbProto::processInitMsg() {
+  vlog.debug("reading server initialisation");
+  reader->readServerInit(); 
+}
+
+void RfbProto::serverInit()
+{
+  state_ = RFBSTATE_NORMAL;
+  vlog.debug("initialisation done");
+}
diff --git a/win/rfbplayer/RfbProto.h b/win/rfbplayer/RfbProto.h
new file mode 100644 (file)
index 0000000..316ea26
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- RfbProto.h
+
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+using namespace rfb;
+
+class RfbProto : public CMsgHandler {
+  public:
+
+    RfbProto(char *fileName);
+    ~RfbProto();
+
+    void newSession(char *filename);
+    void initialiseProtocol();
+    void interruptFrameDelay() { is->interruptFrameDelay(); };
+    const rdr::InStream* getInStream() { return is; }
+
+    virtual void processMsg();
+
+    // serverInit() is called when the ServerInit message is received.  The
+    // derived class must call on to CMsgHandler::serverInit().
+    void serverInit();
+
+    enum stateEnum {
+      RFBSTATE_PROTOCOL_VERSION,
+      RFBSTATE_SECURITY,
+      RFBSTATE_INITIALISATION,
+      RFBSTATE_NORMAL,
+      RFBSTATE_INVALID
+    };
+
+    stateEnum state() { return state_; }
+
+  protected:
+    void setState(stateEnum s) { state_ = s; }
+    virtual void framebufferUpdateEnd() {};
+
+    FbsInputStream* is;
+    CMsgReaderV3* reader;
+    stateEnum state_;
+
+  private:
+    void processVersionMsg();
+    void processSecurityMsg();
+    void processInitMsg();
+};
diff --git a/win/rfbplayer/SessionInfoDialog.h b/win/rfbplayer/SessionInfoDialog.h
new file mode 100644 (file)
index 0000000..2c036db
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- SessionInfoDialog.h
+
+#include <math.h>
+
+#include <rfb/ConnParams.h>
+
+#include <rfb_win32/Dialog.h>
+
+#define log2(n) log(n) / 0.693147180559945
+
+int max3(int v1, int v2, int v3) {
+  return max(v1, max(v2, v3));
+}
+
+class SessionInfoDialog : public rfb::win32::Dialog {
+public:
+  SessionInfoDialog(ConnParams *_cp, int _currentEncoding) 
+    : Dialog(GetModuleHandle(0)), cp(_cp), currentEncoding(_currentEncoding) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent = 0) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_SESSION_INFO), parent);
+  }
+protected:
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    char strValue[255] = "\0";
+    setItemString(IDC_DESKTOP_NAME, cp->name());
+    
+    sprintf(strValue, "%ix%i", cp->width, cp->height);
+    setItemString(IDC_DESKTOP_SIZE, strValue);
+    
+    int r = cp->pf().redShift, g = cp->pf().greenShift, b = cp->pf().blueShift;
+    int i = 3;
+    char buffer[10];
+    sprintf(strValue, "depth %i(%ibpp), ", cp->pf().depth, cp->pf().bpp);
+    while (i) {
+      if (r == max3(r, g, b)) {
+        strcat(strValue, "r");
+        _itoa(ceil(log2(cp->pf().redMax)), buffer, 10);
+        strcat(strValue, buffer);
+        r = -1; 
+        i--;
+        continue;
+      } else if (g == max3(r, g, b)) {
+        strcat(strValue, "g");
+        _itoa(ceil(log2(cp->pf().greenMax)), buffer, 10);
+        strcat(strValue, buffer);
+        g = -1; 
+        i--;
+        continue;
+      } else if (b == max3(r, g, b)) {
+        strcat(strValue, "b");
+        _itoa(ceil(log2(cp->pf().blueMax)), buffer, 10);
+        strcat(strValue, buffer);
+        b = -1; 
+        i--;
+        continue;
+      } else break;
+    }
+    if (cp->pf().bigEndian) strcat(strValue, ", big-endian");
+    else strcat(strValue, ", little-endian");
+    setItemString(IDC_PIXEL_FORMAT, strValue);
+
+    switch (currentEncoding) {
+    case encodingRaw:      strcpy(strValue, "Raw");      break;
+    case encodingCopyRect: strcpy(strValue, "CopyRect"); break;
+    case encodingRRE:      strcpy(strValue, "RRE");      break;
+    case encodingCoRRE:    strcpy(strValue, "CoRRE");    break;
+    case encodingHextile:  strcpy(strValue, "Hextile");  break;
+    case encodingTight:    strcpy(strValue, "Tight");    break;
+    case encodingZRLE:     strcpy(strValue, "ZRLE");     break;
+    default:               strcpy(strValue, "Unknown");
+    }
+    setItemString(IDC_CURRENT_ENCODING, strValue);
+
+    sprintf(strValue, "%i.%i", cp->majorVersion, cp->minorVersion);
+    setItemString(IDC_VERSION, strValue);
+  }
+  ConnParams *cp;
+  int currentEncoding;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/UserPixelFormatsDialog.h b/win/rfbplayer/UserPixelFormatsDialog.h
new file mode 100644 (file)
index 0000000..fe2ad22
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- UserPixelFormatsDialog.h
+
+#include <rfbplayer/EditPixelFormatDialog.h>
+
+#define UPF_REGISTRY_PATH "Software\\TightVnc\\RfbPlayer\\UserDefinedPF"
+
+class UserPixelFormatsDialog : public rfb::win32::Dialog {
+public:
+  UserPixelFormatsDialog(PixelFormatList *_supportedPF) 
+  : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), pfList(0) {}
+  // - Show the dialog and return true if OK was clicked,
+  //   false in case of error or Cancel
+  virtual bool showDialog(HWND parent) {
+    return Dialog::showDialog(MAKEINTRESOURCE(IDD_USERPF_LIST), parent);
+  }
+
+protected:
+  // Dialog methods (protected)
+  virtual void initDialog() {
+    pfList = GetDlgItem(handle, IDC_PF_LIST);
+    for (int i = supportedPF->getDefaultPFCount(); i < supportedPF->count(); i++) {
+      SendMessage(pfList, LB_ADDSTRING, 
+        0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+    }
+    SendMessage(pfList, LB_SETCURSEL, 0, 0);
+  }
+  virtual bool onCommand(int item, int cmd) { 
+    switch (item) {
+    case IDC_ADD_BUTTON:
+      { 
+        char format_name[MAX_STR_LEN] = "";
+        PixelFormat pf(32, 24, 0, 1, 0, 0, 0, 0, 0, 0);
+        EditPixelFormatDialog edit(supportedPF, format_name, &pf);
+        if (edit.showDialog(handle)) {
+          supportedPF->add(format_name, pf);
+          SendMessage(pfList, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)format_name);
+        }
+      }
+      break;
+    case IDC_REMOVE_BUTTON:
+      {
+        int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+        if (index == LB_ERR) {
+          MessageBox(handle, "You must select the pixel format for remove.", 
+                     "RfbPlayer", MB_OK | MB_ICONWARNING);
+          return false;
+        } else {
+          supportedPF->remove(supportedPF->getDefaultPFCount() + index);
+          SendMessage(pfList, LB_DELETESTRING, index, 0);
+        }
+      }
+      break;
+    case IDC_PF_LIST:
+      if (cmd != LBN_DBLCLK) break;
+    case IDC_EDIT_BUTTON:
+      {
+        int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+        if (index == LB_ERR) {
+          MessageBox(handle, "You must select the pixel format for remove.", 
+                     "RfbPlayer", MB_OK | MB_ICONWARNING);
+          return false;
+        }
+        PixelFormat *pf = 
+          &(supportedPF->operator[](index + supportedPF->getDefaultPFCount())->PF);
+        char *format_name = 
+          (supportedPF)->operator[](index + supportedPF->getDefaultPFCount())->format_name;
+        EditPixelFormatDialog edit(supportedPF, format_name, pf);
+        if (edit.showDialog(handle)) {
+          SendMessage(pfList, LB_DELETESTRING, index, 0);
+          SendMessage(pfList, LB_INSERTSTRING, index, (LPARAM)(LPCTSTR)format_name);
+          SendMessage(pfList, LB_SETCURSEL, index, 0);
+        }
+      }
+      break;
+    default:
+      break;
+    }
+    return false;
+  }
+  virtual bool onOk() {
+    supportedPF->writeUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+    return true;
+  }
+
+  HWND pfList;
+  PixelFormatList *supportedPF;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/buildTime.cxx b/win/rfbplayer/buildTime.cxx
new file mode 100644 (file)
index 0000000..bab2e13
--- /dev/null
@@ -0,0 +1 @@
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
\ No newline at end of file
diff --git a/win/rfbplayer/resource.h b/win/rfbplayer/resource.h
new file mode 100644 (file)
index 0000000..90a057f
--- /dev/null
@@ -0,0 +1,81 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by rfbplayer.rc
+//
+#define IDI_ICON                        105
+#define IDR_MENU                        128
+#define IDR_ACCELERATOR                 131
+#define IDB_TOOLBAR                     132
+#define IDD_GOTO                        133
+#define IDD_PIXELFORMAT                 134
+#define IDD_OPTIONS                     137
+#define IDD_ABOUT                       138
+#define IDD_USERPF_LIST                 139
+#define IDD_UPF_EDIT                    140
+#define IDD_INFO                        141
+#define IDD_SESSION_INFO                142
+#define IDC_GOTO_EDIT                   1003
+#define IDC_PIXELFORMAT                 1004
+#define IDC_ASK_PF                      1006
+#define IDC_DEFAULT                     1008
+#define IDC_VERSION                     1008
+#define IDC_ACCEPT_BELL                 1009
+#define IDC_BUILDTIME                   1009
+#define IDC_ACCEPT_CUT_TEXT             1010
+#define IDC_AUTO_STORE_PARAM            1011
+#define IDC_AUTOPLAY                    1012
+#define IDC_BIG_ENDIAN                  1013
+#define IDC_EDIT_UPF                    1015
+#define IDC_PF_LIST                     1016
+#define IDC_BPP_COMBO                   1016
+#define IDC_ADD_BUTTON                  1017
+#define IDC_NAME_EDIT                   1017
+#define IDC_REMOVE_BUTTON               1018
+#define IDC_EDIT_BUTTON                 1019
+#define IDC_COPYRIGHT                   1021
+#define IDC_DEPTH_EDIT                  1021
+#define IDC_DESCRIPTION                 1022
+#define IDC_BIGENDIAN_COMBO             1022
+#define IDC_REDMAX_EDIT                 1023
+#define IDC_GREENMAX_EDIT               1024
+#define IDC_BLUEMAX_EDIT                1025
+#define IDC_REDSHIFT_EDIT               1026
+#define IDC_DESKTOP_NAME                1026
+#define IDC_GREENSHIFT_EDIT             1027
+#define IDC_DESKTOP_SIZE                1027
+#define IDC_BLUESHIFT_EDIT              1028
+#define IDC_CURRENT_ENCODING            1029
+#define IDC_PIXEL_FORMAT                1030
+#define IDC_INFO_EDIT                   1076
+#define ID_OPENFILE                     40011
+#define ID_CLOSEFILE                    40012
+#define ID_EXIT                         40013
+#define ID_FULLSCREEN                   40014
+#define ID_ZOOM_50                      40015
+#define ID_ZOOM_100                     40016
+#define ID_ZOOM_200                     40017
+#define ID_PLAYPAUSE                    40018
+#define ID_STOP                         40019
+#define ID_GOTO                         40020
+#define ID_LOOP                         40022
+#define ID_COPYTOCLIPBOARD              40023
+#define ID_FRAMEEXTRACT                 40024
+#define ID_HELP_HOMEPAGE                40025
+#define ID_HOMEPAGE                     40025
+#define ID_HELP_COMMANDLINESWITCHES     40026
+#define ID_HELP_ABOUT                   40027
+#define ID_ABOUT                        40027
+#define ID_OPTIONS                      40029
+#define ID_RETURN                       40044
+#define ID_SESSION_INFO                 40045
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        143
+#define _APS_NEXT_COMMAND_VALUE         40046
+#define _APS_NEXT_CONTROL_VALUE         1031
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/win/rfbplayer/rfbSessionReader.h b/win/rfbplayer/rfbSessionReader.h
new file mode 100644 (file)
index 0000000..31985bc
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- rfbSessionReader.h
+
+#include <rfb/Threading.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+class rfbSessionReader : public Thread {
+public:
+  rfbSessionReader(RfbProto *_rfbSession) {
+    rfbSession = _rfbSession;
+    fStop = false;
+    rfbSession->interruptFrameDelay();
+  };
+  
+  ~rfbSessionReader() {
+  }
+
+  virtual Thread* join() {
+    ((FbsInputStream*)(rfbSession->getInStream()))->resumePlayback();
+    fStop = true;
+    return Thread::join();
+  }
+
+  virtual void rfbSessionReader::run() {
+    // Process the rfb messages
+    while (!fStop) {
+      try {
+        rfbSession->processMsg();
+      } catch (rdr::Exception e) {
+        MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+        break;
+      }
+    }
+  }
+
+protected:
+  bool fStop;
+  RfbProto *rfbSession;
+};
\ No newline at end of file
diff --git a/win/rfbplayer/rfbplayer.cxx b/win/rfbplayer/rfbplayer.cxx
new file mode 100644 (file)
index 0000000..b304aec
--- /dev/null
@@ -0,0 +1,1294 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- RFB Player for Win32
+#include <windows.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#include <rfb/LogWriter.h>
+
+#include <rfb_win32/AboutDialog.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/Win32Util.h>
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/ChoosePixelFormatDialog.h>
+#include <rfbplayer/GotoPosDialog.h>
+#include <rfbplayer/InfoDialog.h>
+#include <rfbplayer/SessionInfoDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+// -=- Variables & consts
+
+static LogWriter vlog("RfbPlayer");
+
+TStr rfb::win32::AppName("RfbPlayer");
+extern const char* buildTime;
+HFONT hFont = 0;
+
+char wrong_cmd_msg[] = 
+ "Wrong command-line parameters!\n"
+ "Use for help: rfbplayer -help";
+
+char usage_msg[] = 
+ "usage: rfbplayer <options> <filename>\r\n"
+ "Command-line options:\r\n"
+ "  -help         \t- Provide usage information.\r\n"
+ "  -pf <mode>    \t- Forces the pixel format for the session.\r\n"
+ "                \t  <mode>=r<r_bits>g<g_bits>b<b_bits>[le|be],\r\n"
+ "                \t  r_bits - size the red component, in bits,\r\n"
+ "                \t  g_bits - size the green component, in bits,\r\n"
+ "                \t  b_bits - size the blue component, in bits,\r\n"
+ "                \t  le - little endian byte order (default),\r\n"
+ "                \t  be - big endian byte order.\r\n"
+ "                \t  The r, g, b component is in any order.\r\n"
+ "                \t  Default: auto detect the pixel format.\r\n"
+ "  -upf <name>   \t- Forces the user defined pixel format for\r\n"
+ "                \t  the session. If <name> is empty then application\r\n"
+ "                \t  shows the list of user defined pixel formats.\r\n"
+ "                \t  Don't use this option with -pf.\r\n"
+ "  -speed <value>\t- Sets playback speed, where 1 is normal speed,\r\n"
+ "                \t  is double speed, 0.5 is half speed. Default: 1.0.\r\n"
+ "  -pos <ms>     \t- Sets initial time position in the session file,\r\n"
+ "                \t  in milliseconds. Default: 0.\r\n"
+ "  -autoplay     \t- Runs the player in the playback mode.\r\n"
+ "  -loop         \t- Replays the rfb session.";
+
+// -=- RfbPlayer's defines and consts
+
+#define strcasecmp _stricmp
+#define DEFAULT_PLAYER_WIDTH 640
+#define DEFAULT_PLAYER_HEIGHT 480 
+
+//
+// -=- AboutDialog global values
+//
+
+const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
+const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
+const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
+const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
+const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
+
+//
+// -=- RfbPlayerClass
+
+//
+// Window class used as the basis for RfbPlayer instance
+//
+
+class RfbPlayerClass {
+public:
+  RfbPlayerClass();
+  ~RfbPlayerClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK RfbPlayerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  LRESULT result;
+
+  if (msg == WM_CREATE)
+    SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+  else if (msg == WM_DESTROY) {
+    RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+    SetWindowLong(hwnd, GWL_USERDATA, 0);
+  }
+  RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %u", hwnd, msg);
+    return DefWindowProc(hwnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processMainMessage(hwnd, msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+};
+
+RfbPlayerClass::RfbPlayerClass() : classAtom(0) {
+  WNDCLASS wndClass;
+  wndClass.style = 0;
+  wndClass.lpfnWndProc = RfbPlayerProc;
+  wndClass.cbClsExtra = 0;
+  wndClass.cbWndExtra = 0;
+  wndClass.hInstance = instance = GetModuleHandle(0);
+  wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0),
+    MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+  if (!wndClass.hIcon)
+    printf("unable to load icon:%ld", GetLastError());
+  wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+  wndClass.hbrBackground = HBRUSH(COLOR_WINDOW);
+  wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
+  wndClass.lpszClassName = _T("RfbPlayerClass");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register RfbPlayer window class",
+                               GetLastError());
+  }
+}
+
+RfbPlayerClass::~RfbPlayerClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+RfbPlayerClass baseClass;
+
+//
+// -=- RfbFrameClass
+
+//
+// Window class used to displaying the rfb data
+//
+
+class RfbFrameClass {
+public:
+  RfbFrameClass();
+  ~RfbFrameClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  LRESULT result;
+
+  if (msg == WM_CREATE)
+    SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+  else if (msg == WM_DESTROY)
+    SetWindowLong(hwnd, GWL_USERDATA, 0);
+  RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %u", hwnd, msg);
+    return DefWindowProc(hwnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processFrameMessage(hwnd, msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+}
+
+RfbFrameClass::RfbFrameClass() : classAtom(0) {
+  WNDCLASS wndClass;
+  wndClass.style = 0;
+  wndClass.lpfnWndProc = FrameProc;
+  wndClass.cbClsExtra = 0;
+  wndClass.cbWndExtra = 0;
+  wndClass.hInstance = instance = GetModuleHandle(0);
+  wndClass.hIcon = 0;
+  wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+  wndClass.hbrBackground = 0;
+  wndClass.lpszMenuName = 0;
+  wndClass.lpszClassName = _T("RfbPlayerClass1");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register RfbPlayer window class",
+                               GetLastError());
+  }
+}
+
+RfbFrameClass::~RfbFrameClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+RfbFrameClass frameClass;
+
+//
+// -=- RfbPlayer instance implementation
+//
+
+RfbPlayer::RfbPlayer(char *_fileName, PlayerOptions *_options)
+: RfbProto(_fileName), fileName(_fileName), buffer(0), client_size(0, 0, 32, 32),
+  window_size(0, 0, 32, 32), cutText(0), seekMode(false), lastPos(0), 
+  rfbReader(0), sessionTimeMs(0), sliderStepMs(0), imageDataStartTime(0), 
+  rewindFlag(false), stopped(false), currentEncoding(-1) {
+
+  // Save the player options
+  memcpy(&options, _options, sizeof(options));
+
+  // Reset the full session time
+  strcpy(fullSessionTime, "00m:00s");
+
+  // Load the user defined pixel formats from the registry
+  supportedPF.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+
+  // Create the main window
+  const TCHAR* name = _T("RfbPlayer");
+  int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+  int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+  mainHwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW,
+    x, y, DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT, 0, 0, baseClass.instance, this);
+  if (!mainHwnd) {
+    throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+  }
+  vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), getMainHandle());
+
+  // Create the backing buffer
+  buffer = new win32::DIBSectionBuffer(getFrameHandle());
+  setVisible(true);
+
+  // If run with command-line parameters,
+  // open the session file with default settings, otherwise
+  // restore player settings from the registry
+  if (fileName) {
+    openSessionFile(fileName);
+    if (options.initTime > 0) setPos(options.initTime);
+    setSpeed(options.playbackSpeed);
+  } else {
+    options.readFromRegistry();
+    disableTBandMenuItems();
+    setTitle("None");
+  }
+  init();
+}
+
+RfbPlayer::~RfbPlayer() {
+  vlog.debug("~RfbPlayer");
+  if (rfbReader) {
+    delete rfbReader->join();
+    rfbReader = 0;
+  }
+  if (mainHwnd) {
+    setVisible(false);
+    DestroyWindow(mainHwnd);
+    mainHwnd = 0;
+  }
+  if (buffer) delete buffer;
+  if (cutText) delete [] cutText;
+  if (fileName) delete [] fileName;
+  if (hFont) DeleteObject(hFont);
+  vlog.debug("~RfbPlayer done"); 
+}
+
+LRESULT 
+RfbPlayer::processMainMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+
+  switch (msg) {
+
+    // -=- Process standard window messages
+  
+  case WM_CREATE:
+    {
+      tb.create(this, hwnd);
+
+      // Create the frame window
+      frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+        0, WS_CHILD | WS_VISIBLE, 0, tb.getHeight(), 10, tb.getHeight() + 10,
+        hwnd, 0, frameClass.instance, this);
+
+      hMenu = GetMenu(hwnd);
+
+      return 0;
+    }
+  
+    // Process the main menu and toolbar's messages
+
+  case WM_COMMAND:
+
+    switch (LOWORD(wParam)) {
+    case ID_OPENFILE:
+      {
+        char curDir[_MAX_DIR];
+        static char filename[_MAX_PATH];
+        OPENFILENAME ofn;
+        memset((void *) &ofn, 0, sizeof(OPENFILENAME));
+        GetCurrentDirectory(sizeof(curDir), curDir);
+       
+        ofn.lStructSize = sizeof(OPENFILENAME);
+        ofn.hwndOwner = getMainHandle();
+        ofn.lpstrFile = filename;
+        ofn.nMaxFile = sizeof(filename);
+        ofn.lpstrInitialDir = curDir;
+        ofn.lpstrFilter = "Rfb Session files (*.rfb, *.fbs)\0*.rfb;*.fbs\0" \
+                          "All files (*.*)\0*.*\0";
+        ofn.lpstrDefExt = "rfb";
+        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+        if (GetOpenFileName(&ofn)) {
+          openSessionFile(filename);
+        }
+      }
+      break;
+    case ID_CLOSEFILE:
+      closeSessionFile();
+      break;
+    case ID_SESSION_INFO:
+      {
+        SessionInfoDialog sessionInfo(&cp, currentEncoding);
+        sessionInfo.showDialog(getMainHandle());
+      }
+      break;
+    case ID_PLAY:
+      setPaused(false);
+      break;
+    case ID_PAUSE:
+      setPaused(true);
+      break;
+    case ID_STOP:
+      stopPlayback();
+      break;
+    case ID_PLAYPAUSE:
+      if (rfbReader) {
+        if (isPaused()) {
+          setPaused(false);
+        } else {
+         setPaused(true);
+        }
+      }
+      break;
+    case ID_GOTO:
+      {
+        GotoPosDialog gotoPosDlg;
+        if (gotoPosDlg.showDialog(getMainHandle())) {
+          long gotoTime = min(gotoPosDlg.getPos(), sessionTimeMs);
+          setPos(gotoTime);
+          tb.updatePos(gotoTime);
+          setPaused(isPaused());;
+        }
+      }
+      break;
+    case ID_LOOP:
+      options.loopPlayback = !options.loopPlayback;
+      if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+      else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+      break;
+    case ID_RETURN:
+      tb.processWM_COMMAND(wParam, lParam);
+      break;
+    case ID_OPTIONS:
+      {
+        OptionsDialog optionsDialog(&options, &supportedPF);
+        optionsDialog.showDialog(getMainHandle());
+      }
+      break;
+    case ID_EXIT:
+      PostQuitMessage(0);
+      break;
+    case ID_HOMEPAGE:
+      ShellExecute(getMainHandle(), _T("open"), _T("http://www.tightvnc.com/"),
+        NULL, NULL, SW_SHOWDEFAULT);
+      break;
+    case ID_HELP_COMMANDLINESWITCHES:
+      {
+        InfoDialog usageDialog(usage_msg);
+        usageDialog.showDialog(getMainHandle());
+      }
+      break;
+    case ID_ABOUT:
+      AboutDialog::instance.showDialog();
+      break;
+    }
+    break;
+
+    // Update frame's window size and add scrollbars if required
+
+  case WM_SIZE:
+    {
+    
+      Point old_offset = bufferToClient(Point(0, 0));
+
+      // Update the cached sizing information
+      RECT r;
+      GetClientRect(getMainHandle(), &r);
+      MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right - r.left,
+                 r.bottom - r.top - tb.getHeight(), TRUE);
+
+      GetWindowRect(getFrameHandle(), &r);
+      window_size = Rect(r.left, r.top, r.right, r.bottom);
+      GetClientRect(getFrameHandle(), &r);
+      client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+      // Determine whether scrollbars are required
+      calculateScrollBars();
+         
+      // Resize the ToolBar
+      tb.autoSize();
+
+      // Redraw if required
+      if (!old_offset.equals(bufferToClient(Point(0, 0))))
+        InvalidateRect(getFrameHandle(), 0, TRUE);
+    } 
+    break;
+
+  case WM_HSCROLL:
+    tb.processWM_HSCROLL(wParam, lParam);
+    break;
+  
+  case WM_NOTIFY:
+    return tb.processWM_NOTIFY(wParam, lParam);
+
+  case WM_CLOSE:
+    vlog.debug("WM_CLOSE %x", getMainHandle());
+    PostQuitMessage(0);
+    break;
+  }
+
+  return rfb::win32::SafeDefWindowProc(getMainHandle(), msg, wParam, lParam);
+}
+
+LRESULT RfbPlayer::processFrameMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+
+  case WM_PAINT:
+    {
+      if (isSeeking() || rewindFlag) {
+        seekMode = true;
+        return 0;
+      } else {
+        if (seekMode) {
+          seekMode = false;
+          InvalidateRect(getFrameHandle(), 0, true);
+          UpdateWindow(getFrameHandle());
+          return 0;
+        }
+      }
+
+      PAINTSTRUCT ps;
+      HDC paintDC = BeginPaint(getFrameHandle(), &ps);
+      if (!paintDC)
+        throw SystemException("unable to BeginPaint", GetLastError());
+      Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+      if (!pr.is_empty()) {
+
+        if (buffer->bitmap) {
+
+          // Get device context
+          BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+          // Blit the border if required
+          Rect bufpos = bufferToClient(buffer->getRect());
+          if (!pr.enclosed_by(bufpos)) {
+            vlog.debug("draw border");
+            HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+            RECT r;
+            SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+            SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+            SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+            SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+          }
+
+          // Do the blit
+          Point buf_pos = clientToBuffer(pr.tl);
+          if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+            bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+            throw SystemException("unable to BitBlt to window", GetLastError());
+
+        } else {
+          // Blit a load of black
+          if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+            0, 0, 0, BLACKNESS))
+            throw SystemException("unable to BitBlt to blank window", GetLastError());
+        }
+      }
+      EndPaint(getFrameHandle(), &ps); 
+    }
+    return 0;
+    
+    // Process play/pause by the left mouse button
+  case WM_LBUTTONDOWN:
+    SendMessage(getMainHandle(), WM_COMMAND, ID_PLAYPAUSE, 0);
+    return 0;
+
+  case WM_VSCROLL:
+  case WM_HSCROLL:
+    {
+      Point delta;
+      int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+      switch (LOWORD(wParam)) {
+      case SB_PAGEUP: newpos -= 50; break;
+      case SB_PAGEDOWN: newpos += 50; break;
+      case SB_LINEUP: newpos -= 5; break;
+      case SB_LINEDOWN: newpos += 5; break;
+      case SB_THUMBTRACK:
+      case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+      default: vlog.info("received unknown scroll message");
+      };
+
+      if (msg == WM_HSCROLL)
+        setViewportOffset(Point(newpos, scrolloffset.y));
+      else
+        setViewportOffset(Point(scrolloffset.x, newpos));
+
+      SCROLLINFO si;
+      si.cbSize = sizeof(si);
+      si.fMask  = SIF_POS;
+      si.nPos   = newpos;
+      SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
+    }
+    break;
+  }
+
+  return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void RfbPlayer::disableTBandMenuItems() {
+  // Disable the menu items
+  EnableMenuItem(hMenu, ID_CLOSEFILE, MF_GRAYED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_SESSION_INFO, MF_GRAYED | MF_BYCOMMAND);
+  ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_GRAYED | MF_BYCOMMAND);
+  ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_GRAYED | MF_BYPOSITION);
+  EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_GRAYED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_GOTO, MF_GRAYED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_LOOP, MF_GRAYED | MF_BYCOMMAND);
+  ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_GRAYED | MF_BYCOMMAND);
+  ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_GRAYED | MF_BYCOMMAND);
+  
+  // Disable the toolbar buttons and child controls
+  tb.disable();
+}
+
+void RfbPlayer::enableTBandMenuItems() {
+  // Enable the menu items
+  EnableMenuItem(hMenu, ID_CLOSEFILE, MF_ENABLED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_SESSION_INFO, MF_ENABLED | MF_BYCOMMAND);
+  ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_ENABLED | MF_BYCOMMAND);
+  ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_ENABLED | MF_BYPOSITION);
+  EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_ENABLED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_GOTO, MF_ENABLED | MF_BYCOMMAND);
+  EnableMenuItem(hMenu, ID_LOOP, MF_ENABLED | MF_BYCOMMAND);
+  ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_ENABLED | MF_BYCOMMAND);
+  ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_ENABLED | MF_BYCOMMAND);
+  
+  // Enable the toolbar buttons and child controls
+  tb.enable();
+}
+
+void RfbPlayer::setVisible(bool visible) {
+  ShowWindow(getMainHandle(), visible ? SW_SHOW : SW_HIDE);
+  if (visible) {
+    // When the window becomes visible, make it active
+    SetForegroundWindow(getMainHandle());
+    SetActiveWindow(getMainHandle());
+  }
+}
+
+void RfbPlayer::setTitle(const char *title) {
+  char _title[256];
+  strcpy(_title, AppName);
+  strcat(_title, " - ");
+  strcat(_title, title);
+  SetWindowText(getMainHandle(), _title);
+}
+
+void RfbPlayer::setFrameSize(int width, int height) {
+  // Calculate and set required size for main window
+  RECT r = {0, 0, width, height};
+  AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), TRUE, 
+    GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+  r.bottom += tb.getHeight(); // Include RfbPlayr's controls area
+  AdjustWindowRect(&r, GetWindowLong(getMainHandle(), GWL_STYLE), FALSE);
+  int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2);
+  int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2);
+  SetWindowPos(getMainHandle(), 0, x, y, r.right-r.left, r.bottom-r.top,
+    SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+
+  // Enable/disable scrollbars as appropriate
+  calculateScrollBars(); 
+}
+
+void RfbPlayer::calculateScrollBars() {
+  // Calculate the required size of window
+  DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
+  DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+  DWORD old_style;
+  RECT r;
+  SetRect(&r, 0, 0, buffer->width(), buffer->height());
+  AdjustWindowRectEx(&r, style, FALSE, GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+  Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+  // Work out whether scroll bars are required
+  do {
+    old_style = style;
+
+    if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+      style |= WS_HSCROLL;
+      reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+    }
+    if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+      style |= WS_VSCROLL;
+      reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+    }
+  } while (style != old_style);
+  
+  // Tell Windows to update the window style & cached settings
+  if (style != current_style) {
+    SetWindowLong(getFrameHandle(), GWL_STYLE, style);
+    SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+  }
+
+  // Update the scroll settings
+  SCROLLINFO si;
+  if (style & WS_VSCROLL) {
+    si.cbSize = sizeof(si);
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
+    si.nMin   = 0;
+    si.nMax   = buffer->height();
+    si.nPage  = buffer->height() - (reqd_size.height() - window_size.height());
+    maxscrolloffset.y = max(0, si.nMax-si.nPage);
+    scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+    si.nPos   = scrolloffset.y;
+    SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE);
+  }
+  if (style & WS_HSCROLL) {
+    si.cbSize = sizeof(si);
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
+    si.nMin   = 0;
+    si.nMax   = buffer->width();
+    si.nPage  = buffer->width() - (reqd_size.width() - window_size.width());
+    maxscrolloffset.x = max(0, si.nMax-si.nPage);
+    scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+    si.nPos   = scrolloffset.x;
+    SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE);
+  }
+
+  // Update the cached client size
+  GetClientRect(getFrameHandle(), &r);
+  client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+bool RfbPlayer::setViewportOffset(const Point& tl) {
+/* ***
+  Point np = Point(max(0, min(maxscrolloffset.x, tl.x)),
+    max(0, min(maxscrolloffset.y, tl.y)));
+    */
+  Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+    max(0, min(tl.y, buffer->height()-client_size.height())));
+  Point delta = np.translate(scrolloffset.negate());
+  if (!np.equals(scrolloffset)) {
+    scrolloffset = np;
+    ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+    UpdateWindow(getFrameHandle());
+    return true;
+  }
+  return false;
+}
+
+void RfbPlayer::close(const char* reason) {
+  setVisible(false);
+  if (reason) {
+    vlog.info("closing - %s", reason);
+    MessageBox(NULL, TStr(reason), "RfbPlayer", MB_ICONINFORMATION | MB_OK);
+  }
+  SendMessage(getFrameHandle(), WM_CLOSE, 0, 0);
+}
+
+void RfbPlayer::blankBuffer() {
+  fillRect(buffer->getRect(), 0);
+}
+
+void RfbPlayer::rewind() {
+  bool paused = isPaused();
+  blankBuffer();
+  newSession(fileName);
+  skipHandshaking();
+  is->setSpeed(options.playbackSpeed);
+  if (paused) is->pausePlayback();
+  else is->resumePlayback();
+}
+
+void RfbPlayer::processMsg() {
+  // Perform return if waitWhilePaused processed because 
+  // rfbReader thread could receive the signal to close
+  if (waitWhilePaused()) return;
+  
+  static long update_time = GetTickCount();
+  try {
+    if ((!isSeeking()) && ((GetTickCount() - update_time) > 250)
+      && (!tb.isPosSliderDragging())) {
+      // Update pos in the toolbar 4 times in 1 second
+      tb.updatePos(getTimeOffset());
+      update_time = GetTickCount();
+    }
+    RfbProto::processMsg();
+  } catch (rdr::Exception e) {
+    if (strcmp(e.str(), "[End Of File]") == 0) {
+      rewind();
+      setPaused(!options.loopPlayback);
+      tb.updatePos(getTimeOffset());
+      return;
+    }
+    // It's a special exception to perform backward seeking.
+    // We only rewind the stream and seek the offset
+    if (strcmp(e.str(), "[REWIND]") == 0) {
+      rewindFlag = true; 
+      long seekOffset = max(getSeekOffset(), imageDataStartTime);
+      rewind();
+      if (!stopped) setPos(seekOffset);
+      else stopped = false;
+      tb.updatePos(seekOffset);
+      rewindFlag = false;
+      return;
+    }
+    // It's a special exception which is used to terminate the playback
+    if (strcmp(e.str(), "[TERMINATE]") == 0) {
+      sessionTerminateThread *terminate = new sessionTerminateThread(this);
+      terminate->start();
+    } else {
+      // Show the exception message and close the session playback
+      is->pausePlayback();
+      char message[256] = "\0";
+      strcat(message, e.str());
+      strcat(message, "\nMaybe you force wrong the pixel format for this session");
+      MessageBox(getMainHandle(), message, "RFB Player", MB_OK | MB_ICONERROR);
+      sessionTerminateThread *terminate = new sessionTerminateThread(this);
+      terminate->start();
+      return;
+    }
+  }
+}
+
+long ChoosePixelFormatDialog::pfIndex = DEFAULT_PF_INDEX;
+bool ChoosePixelFormatDialog::bigEndian = false;
+
+void RfbPlayer::serverInit() {
+  RfbProto::serverInit();
+
+  // Save the image data start time
+  imageDataStartTime = is->getTimeOffset();
+
+  // Resize the backing buffer
+  buffer->setSize(cp.width, cp.height);
+
+  // Check on the true colour mode
+  if (!(cp.pf()).trueColour)
+    throw rdr::Exception("This version plays only true color session!");
+
+  // Set the session pixel format
+  if (options.askPixelFormat) {
+    ChoosePixelFormatDialog choosePixelFormatDialog(&supportedPF);
+    if (choosePixelFormatDialog.showDialog(getMainHandle())) {
+      long pixelFormatIndex = choosePixelFormatDialog.getPFIndex();
+      if (pixelFormatIndex < 0) {
+        options.autoDetectPF = true;
+        options.setPF((PixelFormat *)&cp.pf());
+      } else {
+        options.autoDetectPF = false;
+        options.setPF(&supportedPF[pixelFormatIndex]->PF);
+        options.pixelFormat.bigEndian = choosePixelFormatDialog.isBigEndian();
+      }
+    } else {
+      is->pausePlayback();
+      throw rdr::Exception("[TERMINATE]");
+    }
+  } else {
+    if (!options.commandLineParam) {
+      if (options.autoDetectPF) {
+        options.setPF((PixelFormat *)&cp.pf());
+      } else {
+        options.setPF(&supportedPF[options.pixelFormatIndex]->PF);
+        options.pixelFormat.bigEndian = options.bigEndianFlag;
+      }
+    } else if (options.autoDetectPF) {
+      options.setPF((PixelFormat *)&cp.pf());
+    }
+  }
+  cp.setPF(options.pixelFormat);
+  buffer->setPF(options.pixelFormat);
+
+  // If the window is not maximised then resize it
+  if (!(GetWindowLong(getMainHandle(), GWL_STYLE) & WS_MAXIMIZE))
+    setFrameSize(cp.width, cp.height);
+
+  // Set the window title and show it
+  setTitle(cp.name());
+
+  // Calculate the full session time and update posTrackBar control in toolbar
+  sessionTimeMs = calculateSessionTime(fileName);
+  tb.init(sessionTimeMs);
+  tb.updatePos(getTimeOffset());
+
+  setPaused(!options.autoPlay);
+  // Restore the parameters from registry,
+  // which was replaced by command-line parameters.
+  if (options.commandLineParam) {
+    options.readFromRegistry();
+    options.commandLineParam = false;
+  }
+}
+
+void RfbPlayer::setColourMapEntries(int first, int count, U16* rgbs) {
+  vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+  throw rdr::Exception("Can't handle SetColourMapEntries message");
+/*  int i;
+  for (i=0;i<count;i++) {
+    buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+  }
+  // *** change to 0, 256?
+  refreshWindowPalette(first, count);
+  palette_changed = true;
+  InvalidateRect(getFrameHandle(), 0, FALSE);*/
+} 
+
+void RfbPlayer::bell() {
+  if (options.acceptBell)
+    MessageBeep(-1);
+}
+
+void RfbPlayer::serverCutText(const char* str, int len) {
+  if (cutText != NULL)
+    delete [] cutText;
+  cutText = new char[len + 1];
+  memcpy(cutText, str, len);
+  cutText[len] = '\0';
+}
+
+void RfbPlayer::frameBufferUpdateEnd() {
+};
+
+void RfbPlayer::beginRect(const Rect& r, unsigned int encoding) {
+  currentEncoding = encoding;
+}
+
+void RfbPlayer::endRect(const Rect& r, unsigned int encoding) {
+}
+
+
+void RfbPlayer::fillRect(const Rect& r, Pixel pix) {
+  buffer->fillRect(r, pix);
+  invalidateBufferRect(r);
+}
+
+void RfbPlayer::imageRect(const Rect& r, void* pixels) {
+  buffer->imageRect(r, pixels);
+  invalidateBufferRect(r);
+}
+
+void RfbPlayer::copyRect(const Rect& r, int srcX, int srcY) {
+  buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+  invalidateBufferRect(r);
+} 
+
+bool RfbPlayer::invalidateBufferRect(const Rect& crect) {
+  Rect rect = bufferToClient(crect);
+  if (rect.intersect(client_size).is_empty()) return false;
+  RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+  InvalidateRect(getFrameHandle(), &invalid, FALSE);
+  return true;
+}
+
+bool RfbPlayer::waitWhilePaused() {
+  bool result = false;
+  while(isPaused() && !isSeeking()) {
+    Sleep(20);
+    result = true;
+  }
+  return result;
+}
+
+long RfbPlayer::calculateSessionTime(char *filename) {
+  FbsInputStream sessionFile(filename);
+  sessionFile.setTimeOffset(100000000);
+  try {
+    while (TRUE) {
+      sessionFile.skip(1024);
+    }
+  } catch (rdr::Exception e) {
+    if (strcmp(e.str(), "[End Of File]") == 0) {
+      return sessionFile.getTimeOffset();
+    } else {
+      MessageBox(getMainHandle(), e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+      return 0;
+    }
+  }
+  return 0;
+}
+
+void RfbPlayer::init() {
+  if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+  else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+}
+
+void RfbPlayer::closeSessionFile() {
+  DWORD dwStyle;
+  RECT r;
+
+  // Uncheck all toolbar buttons
+  if (tb.getHandle()) {
+    tb.checkButton(ID_PLAY, false);
+    tb.checkButton(ID_PAUSE, false);
+    tb.checkButton(ID_STOP, false);
+  }
+
+  // Stop playback and update the player state
+  disableTBandMenuItems();
+  if (rfbReader) {
+    delete rfbReader->join();
+    rfbReader = 0;
+    delete [] fileName;
+    fileName = 0;
+  }
+  blankBuffer();
+  setTitle("None");
+  options.playbackSpeed = 1.0;
+  tb.init(0);
+    
+  // Change the player window size and frame size to default
+  if ((dwStyle = GetWindowLong(getMainHandle(), GWL_STYLE)) & WS_MAXIMIZE) {
+    dwStyle &= ~WS_MAXIMIZE;
+    SetWindowLong(getMainHandle(), GWL_STYLE, dwStyle);
+  }
+  int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+  int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+  SetWindowPos(getMainHandle(), 0, x, y, 
+    DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT, 
+    SWP_NOZORDER | SWP_FRAMECHANGED);
+  buffer->setSize(32, 32);
+  calculateScrollBars();
+  
+  // Update the cached sizing information and repaint the frame window
+  GetWindowRect(getFrameHandle(), &r);
+  window_size = Rect(r.left, r.top, r.right, r.bottom);
+  GetClientRect(getFrameHandle(), &r);
+  client_size = Rect(r.left, r.top, r.right, r.bottom);
+  InvalidateRect(getFrameHandle(), 0, TRUE);
+  UpdateWindow(getFrameHandle());
+}
+
+void RfbPlayer::openSessionFile(char *_fileName) {
+  fileName = strDup(_fileName);
+
+  // Close the previous reading thread
+  if (rfbReader) {
+    delete rfbReader->join();
+    rfbReader = 0;
+  }
+  blankBuffer();
+  newSession(fileName);
+  setSpeed(options.playbackSpeed);
+  rfbReader = new rfbSessionReader(this);
+  rfbReader->start();
+  tb.setTimePos(0);
+  enableTBandMenuItems();
+}
+
+void RfbPlayer::setPaused(bool paused) {
+  if (paused) {
+    is->pausePlayback();
+    tb.checkButton(ID_PAUSE, true);
+    tb.checkButton(ID_PLAY, false);
+    tb.checkButton(ID_STOP, false);
+  } else {
+    if (is) is->resumePlayback();
+    tb.checkButton(ID_PLAY, true);
+    tb.checkButton(ID_STOP, false);
+    tb.checkButton(ID_PAUSE, false);
+  }
+  tb.enableButton(ID_PAUSE, true);
+  EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::stopPlayback() {
+  stopped = true;
+  setPos(0);
+  if (is) { 
+    is->pausePlayback();
+    is->interruptFrameDelay();
+  }
+  tb.checkButton(ID_STOP, true);
+  tb.checkButton(ID_PLAY, false);
+  tb.checkButton(ID_PAUSE, false);
+  tb.enableButton(ID_PAUSE, false);
+  tb.setTimePos(0);
+  EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::setSpeed(double speed) {
+  if (speed > 0) {
+    char speedStr[20] = "\0";
+    double newSpeed = min(speed, MAX_SPEED);
+    is->setSpeed(newSpeed);
+    options.playbackSpeed = newSpeed;
+    SendMessage(tb.getSpeedUpDownHwnd(), UDM_SETPOS, 
+      0, MAKELONG((short)(newSpeed / 0.5), 0));
+    sprintf(speedStr, "%.2f", newSpeed);
+    SetWindowText(tb.getSpeedEditHwnd(), speedStr);
+  }
+}
+
+double RfbPlayer::getSpeed() {
+  return is->getSpeed();
+}
+
+void RfbPlayer::setPos(long pos) {
+  is->setTimeOffset(max(pos, imageDataStartTime));
+}
+
+long RfbPlayer::getSeekOffset() {
+  return is->getSeekOffset();
+}
+
+bool RfbPlayer::isSeeking() {
+  if (is) return is->isSeeking();
+  else return false;
+}
+
+bool RfbPlayer::isSeekMode() {
+  return seekMode;
+}
+
+bool RfbPlayer::isPaused() {
+  return is->isPaused();
+}
+
+long RfbPlayer::getTimeOffset() {
+  return max(is->getTimeOffset(), is->getSeekOffset());
+}
+
+void RfbPlayer::skipHandshaking() {
+  int skipBytes = 12 + 4 + 24 + strlen(cp.name());
+  is->skip(skipBytes);
+  state_ = RFBSTATE_NORMAL;
+}
+
+void programInfo() {
+  win32::FileVersionInfo inf;
+  _tprintf(_T("%s - %s, Version %s\n"),
+    inf.getVerString(_T("ProductName")),
+    inf.getVerString(_T("FileDescription")),
+    inf.getVerString(_T("FileVersion")));
+  printf("%s\n", buildTime);
+  _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
+}
+
+void programUsage() {
+  InfoDialog usageDialog(usage_msg);
+  usageDialog.showDialog();
+}
+
+char *fileName = 0;
+
+// playerOptions is the player options with default parameters values,
+// it is used only for run the player with command-line parameters
+PlayerOptions playerOptions;
+bool print_usage = false;
+bool print_upf_list = false;
+
+bool processParams(int argc, char* argv[]) {
+  playerOptions.commandLineParam = true;
+  for (int i = 1; i < argc; i++) {
+    if ((strcasecmp(argv[i], "-help") == 0) ||
+        (strcasecmp(argv[i], "--help") == 0) ||
+        (strcasecmp(argv[i], "/help") == 0) ||
+        (strcasecmp(argv[i], "-h") == 0) ||
+        (strcasecmp(argv[i], "/h") == 0) ||
+        (strcasecmp(argv[i], "/?") == 0) ||
+        (strcasecmp(argv[i], "-?") == 0)) {
+      print_usage = true;
+      return true;
+    }
+
+    if ((strcasecmp(argv[i], "-pf") == 0) ||
+        (strcasecmp(argv[i], "/pf") == 0) && (i < argc-1)) {
+      char *pf = argv[++i];
+      char rgb_order[4] = "\0";
+      int order = RGB_ORDER;
+      int r = -1, g = -1, b = -1;
+      bool big_endian = false;
+      if (strlen(pf) < 6) return false;
+      while (strlen(pf)) {
+        if ((pf[0] == 'r') || (pf[0] == 'R')) {
+          if (r >=0 ) return false;
+          r = atoi(++pf);
+          strcat(rgb_order, "r");
+          continue;
+        }
+        if ((pf[0] == 'g') || (pf[0] == 'G')) {
+          if (g >=0 ) return false;
+          g = atoi(++pf);
+          strcat(rgb_order, "g");
+          continue;
+        }
+        if (((pf[0] == 'b') || (pf[0] == 'B')) && 
+             (pf[1] != 'e') && (pf[1] != 'E')) {
+          if (b >=0 ) return false;
+          b = atoi(++pf);
+          strcat(rgb_order, "b");
+          continue;
+        }
+        if ((pf[0] == 'l') || (pf[0] == 'L') || 
+            (pf[0] == 'b') || (pf[0] == 'B')) {
+          if (strcasecmp(pf, "le") == 0) break;
+          if (strcasecmp(pf, "be") == 0) { big_endian = true; break;}
+          return false;
+        }
+        pf++;
+      }
+      if ((r < 0) || (g < 0) || (b < 0) || (r + g + b > 32)) return false;
+      if (strcasecmp(rgb_order, "rgb") == 0) { order = RGB_ORDER; }
+      else if (strcasecmp(rgb_order, "rbg") == 0) { order = RBG_ORDER; }
+      else if (strcasecmp(rgb_order, "grb") == 0) { order = GRB_ORDER; }
+      else if (strcasecmp(rgb_order, "gbr") == 0) { order = GBR_ORDER; }
+      else if (strcasecmp(rgb_order, "bgr") == 0) { order = BGR_ORDER; }
+      else if (strcasecmp(rgb_order, "brg") == 0) { order = BRG_ORDER; }
+      else return false;
+      playerOptions.autoDetectPF = false;
+      playerOptions.setPF(order, r, g, b, big_endian);
+      continue;
+    }
+
+    if ((strcasecmp(argv[i], "-upf") == 0) ||
+        (strcasecmp(argv[i], "/upf") == 0) && (i < argc-1)) {
+      if ((i == argc - 1) || (argv[++i][0] == '-')) {
+        print_upf_list = true;
+        return true;
+      }
+      PixelFormatList userPfList;
+      userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+      int index = userPfList.getIndexByPFName(argv[i]);
+      if (index > 0) {
+        playerOptions.autoDetectPF = false;
+        playerOptions.setPF(&userPfList[index]->PF);
+      } else {
+        return false;
+      }
+      continue;
+    }
+
+    if ((strcasecmp(argv[i], "-speed") == 0) ||
+        (strcasecmp(argv[i], "/speed") == 0) && (i < argc-1)) {
+      double playbackSpeed = atof(argv[++i]);
+      if (playbackSpeed <= 0) {
+        return false;
+      }
+      playerOptions.playbackSpeed = playbackSpeed;
+      continue;
+    }
+
+    if ((strcasecmp(argv[i], "-pos") == 0) ||
+        (strcasecmp(argv[i], "/pos") == 0) && (i < argc-1)) {
+      long initTime = atol(argv[++i]);
+      if (initTime <= 0)
+        return false;
+      playerOptions.initTime = initTime;
+      continue;
+    }
+
+    if ((strcasecmp(argv[i], "-autoplay") == 0) ||
+        (strcasecmp(argv[i], "/autoplay") == 0) && (i < argc-1)) {
+      playerOptions.autoPlay = true;
+      continue;
+    }
+
+    if ((strcasecmp(argv[i], "-loop") == 0) ||
+        (strcasecmp(argv[i], "/loop") == 0) && (i < argc-1)) {
+      playerOptions.loopPlayback = true;
+      continue;
+    }
+
+    if (i != argc - 1)
+      return false;
+  }
+
+  fileName = strDup(argv[argc-1]);
+  if (fileName[0] == '-') return false;
+  else return true;
+}
+
+//
+// -=- WinMain
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+  
+  // - Process the command-line
+
+  int argc = __argc;
+  char** argv = __argv;
+  if ((argc > 1) && (!processParams(argc, argv))) {
+    MessageBox(0, wrong_cmd_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+    return 0;
+  }
+  
+  if (print_usage) {
+    programUsage();
+    return 0;
+  }
+  // Show the user defined pixel formats if required
+  if (print_upf_list) {
+    int list_size = 256;
+    char *upf_list = new char[list_size];
+    PixelFormatList userPfList;
+    userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+    strcpy(upf_list, "The list of the user defined pixel formats:\r\n");
+    for (int i = userPfList.getDefaultPFCount(); i < userPfList.count(); i++) {
+      if ((list_size - strlen(upf_list) - 1) < 
+          (strlen(userPfList[i]->format_name) + 2)) {
+        char *tmpStr = new char[list_size = 
+          list_size + strlen(userPfList[i]->format_name) + 2];
+        strcpy(tmpStr, upf_list);
+        delete [] upf_list;
+        upf_list = new char[list_size];
+        strcpy(upf_list, tmpStr);
+        delete [] tmpStr;
+      }
+      strcat(upf_list, userPfList[i]->format_name);
+      strcat(upf_list, "\r\n");
+    }
+    InfoDialog upfInfoDialog(upf_list);
+    upfInfoDialog.showDialog();
+    delete [] upf_list;
+    return 0;
+  }
+
+  // Create the player
+  RfbPlayer *player = NULL;
+  try {
+    player = new RfbPlayer(fileName, &playerOptions);
+  } catch (rdr::Exception e) {
+    MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+    delete player;
+    return 0;
+  }
+
+  // Run the player
+  HACCEL hAccel = LoadAccelerators(inst, MAKEINTRESOURCE(IDR_ACCELERATOR));
+  MSG msg;
+  while (GetMessage(&msg, NULL, 0, 0) > 0) {
+    if(!TranslateAccelerator(player->getMainHandle(), hAccel, &msg)) {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+  }
+
+  // Destroy the player
+  try{
+    if (player) delete player;
+  } catch (rdr::Exception e) {
+    MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+  }
+
+  return 0;
+};
diff --git a/win/rfbplayer/rfbplayer.dsp b/win/rfbplayer/rfbplayer.dsp
new file mode 100644 (file)
index 0000000..9068536
--- /dev/null
@@ -0,0 +1,207 @@
+# Microsoft Developer Studio Project File - Name="rfbplayer" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+CFG=rfbplayer - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rfbplayer.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rfbplayer.mak" CFG="rfbplayer - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "rfbplayer - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "rfbplayer - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "rfbplayer - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release"\r
+# PROP Intermediate_Dir "..\Release\rfbplayer"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c\r
+# 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\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x419 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386\r
+# ADD LINK32 user32.lib gdi32.lib Advapi32.lib comctl32.lib shell32.lib comdlg32.lib version.lib /nologo /subsystem:windows /machine:I386\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\rfbplayer /MTd buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "rfbplayer - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug"\r
+# PROP Intermediate_Dir "..\Debug\rfbplayer"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c\r
+# 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\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x419 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# 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\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\rfbplayer /MTd buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "rfbplayer - Win32 Release"\r
+# Name "rfbplayer - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\buildTime.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FbsInputStream.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PixelFormatList.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PlayerOptions.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PlayerToolBar.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\rfbplayer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\rfbplayer.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\RfbProto.cxx\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\ChoosePixelFormatDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\EditPixelFormatDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FbsInputStream.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\GotoPosDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\InfoDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\OptionsDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PixelFormatList.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PlayerOptions.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PlayerToolBar.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\rfbplayer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\RfbProto.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\rfbSessionReader.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\SessionInfoDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\UserPixelFormatsDialog.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# Begin Source File\r
+\r
+SOURCE=.\rfbplayer.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\toolbar.bmp\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/rfbplayer/rfbplayer.h b/win/rfbplayer/rfbplayer.h
new file mode 100644 (file)
index 0000000..c5c5da8
--- /dev/null
@@ -0,0 +1,195 @@
+/* Copyright (C) 2004 TightVNC Team.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// -=- RfbPlayer.h
+
+#include <windows.h>
+
+#include <rfb_win32/DIBSectionBuffer.h>
+
+#include <rfbplayer/resource.h>
+#include <rfbplayer/PixelFormatList.h>
+#include <rfbplayer/PlayerToolBar.h>
+#include <rfbplayer/OptionsDialog.h>
+#include <rfbplayer/rfbSessionReader.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+class PlayerToolBar;
+
+class RfbPlayer : public RfbProto {
+  public:
+    RfbPlayer(char *fileName, PlayerOptions *options);
+    ~RfbPlayer();
+
+    // -=- Window Message handling
+
+    LRESULT processMainMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+    LRESULT processFrameMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+    // -=- Window interface
+
+    HWND getMainHandle() const {return mainHwnd;}
+    HWND getFrameHandle() const {return frameHwnd;}
+    void disableTBandMenuItems();
+    void enableTBandMenuItems();
+    void setFrameSize(int width, int height);
+    void setVisible(bool visible);
+    void setTitle(const char *title);
+    void calculateScrollBars();
+    void close(const char* reason=0);
+    void init();
+
+    // -=- Coordinate conversions
+
+    inline Point bufferToClient(const Point& p) {
+      Point pos = p;
+      if (client_size.width() > buffer->width())
+        pos.x += (client_size.width() - buffer->width()) / 2;
+      else if (client_size.width() < buffer->width())
+        pos.x -= scrolloffset.x;
+      if (client_size.height() > buffer->height())
+        pos.y += (client_size.height() - buffer->height()) / 2;
+      else if (client_size.height() < buffer->height())
+        pos.y -= scrolloffset.y;
+      return pos;
+    }
+    inline Rect bufferToClient(const Rect& r) {
+      return Rect(bufferToClient(r.tl), bufferToClient(r.br));
+    }
+
+    inline Point clientToBuffer(const Point& p) {
+      Point pos = p;
+      if (client_size.width() > buffer->width())
+        pos.x -= (client_size.width() - buffer->width()) / 2;
+      else if (client_size.width() < buffer->width())
+        pos.x += scrolloffset.x;
+      if (client_size.height() > buffer->height())
+        pos.y -= (client_size.height() - buffer->height()) / 2;
+      else if (client_size.height() < buffer->height())
+        pos.y += scrolloffset.y;
+      return pos;
+    }
+    inline Rect clientToBuffer(const Rect& r) {
+      return Rect(clientToBuffer(r.tl), clientToBuffer(r.br));
+    }
+
+    bool setViewportOffset(const Point& tl);
+
+    // -=- RfbProto interface overrides
+
+    virtual void processMsg();
+    virtual void serverInit();
+    virtual void frameBufferUpdateEnd();
+    virtual void setColourMapEntries(int first, int count, U16* rgbs);
+    virtual void serverCutText(const char* str, int len);
+    virtual void bell();
+
+    virtual void beginRect(const Rect& r, unsigned int encoding);
+    virtual void endRect(const Rect& r, unsigned int encoding);
+    virtual void fillRect(const Rect& r, Pixel pix);
+    virtual void imageRect(const Rect& r, void* pixels);
+    virtual void copyRect(const Rect& r, int srcX, int srcY);
+
+    // -=- Player functions
+
+    // calculateSessionTime() calculates the full session time in sec
+    long calculateSessionTime(char *fileName);
+
+    // closeSessionFile() closes the session file and blanks the frame buffer
+    void closeSessionFile();
+
+    // openSessionFile() opens the new session file and starts play it
+    void openSessionFile(char *fileName);
+
+    // skipHandshaking() - is implemented to skip the initial handshaking when
+    // perform backward seeking OR replaying.
+    void skipHandshaking();
+
+    void blankBuffer();
+    void rewind();
+    void setPaused(bool paused);
+    void stopPlayback();
+    long getTimeOffset();
+    bool isSeekMode();
+    bool isSeeking();
+    bool isPaused();
+    long getSeekOffset();
+    void setPos(long pos);
+    void setSpeed(double speed);
+    double getSpeed();
+
+  protected:
+    bool seekMode;
+    bool stopped;
+    long lastPos;
+    long sliderStepMs;
+    char fullSessionTime[20];
+    int time_pos_m;
+    int time_pos_s;
+    char *fileName;
+    
+    // rfbReader is a class which used to reading the rfb data from the file
+    rfbSessionReader *rfbReader;
+
+    // Returns true if part of the supplied rect is visible, false otherwise
+    bool invalidateBufferRect(const Rect& crect);
+
+    bool waitWhilePaused();
+
+    // rewindFlag is a flag wich disable the update of the frame buffer window 
+    // while the rewind is performing.
+    bool rewindFlag;
+    
+    // Local window state
+    HWND mainHwnd;
+    HWND frameHwnd;
+    HMENU hMenu;
+    Rect window_size;
+    Rect client_size;
+    Point scrolloffset;
+    Point maxscrolloffset;
+    char *cutText;
+    win32::DIBSectionBuffer* buffer;
+    PlayerToolBar tb;
+
+    // The player's parameters
+    PlayerOptions options;
+    PixelFormatList supportedPF;
+    long imageDataStartTime;
+    long sessionTimeMs;
+    int currentEncoding;
+};
+
+// -=- sessionTerminateThread class
+
+// It is a special thread class, wich is allow the rfbSessionReader class
+// terminate itself.
+
+class sessionTerminateThread : public rfb::Thread {
+public:
+  sessionTerminateThread(RfbPlayer *_player) : player(_player) {
+    setDeleteAfterRun();
+  }
+  virtual void run() {
+    player->closeSessionFile();
+  }
+protected:
+  RfbPlayer *player;
+};
diff --git a/win/rfbplayer/rfbplayer.ico b/win/rfbplayer/rfbplayer.ico
new file mode 100644 (file)
index 0000000..c9136bf
Binary files /dev/null and b/win/rfbplayer/rfbplayer.ico differ
diff --git a/win/rfbplayer/rfbplayer.rc b/win/rfbplayer/rfbplayer.rc
new file mode 100644 (file)
index 0000000..169d850
--- /dev/null
@@ -0,0 +1,466 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON                ICON    DISCARDABLE     "rfbplayer.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "080904b0"
+        BEGIN
+            VALUE "Comments", "\0"
+            VALUE "CompanyName", "TightVNC Team\0"
+            VALUE "FileDescription", "RFB Session Player for Win32\0"
+            VALUE "FileVersion", "1, 0, 0, 1\0"
+            VALUE "InternalName", "rfbplayer\0"
+            VALUE "LegalCopyright", "Copyright (C) 2004-2005 TightVNC Team.\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "rfbplayer.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "Rfb Session Player 1.0\0"
+            VALUE "ProductVersion", "1, 0, 0, 1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x809, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE 
+BEGIN
+    POPUP "File"
+    BEGIN
+        MENUITEM "Open File...\tCtrl+O",        ID_OPENFILE
+        MENUITEM "Close File...\tCtrl+Q",       ID_CLOSEFILE
+        MENUITEM SEPARATOR
+        MENUITEM "Info...\tCtrl+I",             ID_SESSION_INFO
+        MENUITEM SEPARATOR
+        MENUITEM "Exit\tAlt+X",                 ID_EXIT
+    END
+    POPUP "Play"
+    BEGIN
+        MENUITEM "Play/Pause\tSpace",           ID_PLAYPAUSE
+        MENUITEM "Stop\tC",                     ID_STOP
+        MENUITEM "Go To...\tCtrl+G",            ID_GOTO
+        MENUITEM SEPARATOR
+        MENUITEM "Loop\tCtrl+L",                ID_LOOP
+        MENUITEM SEPARATOR
+        MENUITEM "Options...\tO",               ID_OPTIONS
+    END
+    POPUP "Help"
+    BEGIN
+        MENUITEM "Home Page",                   ID_HOMEPAGE
+        MENUITEM "Command Line Switches",       ID_HELP_COMMANDLINESWITCHES
+        MENUITEM SEPARATOR
+        MENUITEM "About RfbPlayer...",          ID_ABOUT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR ACCELERATORS DISCARDABLE 
+BEGIN
+    "C",            ID_STOP,                VIRTKEY, NOINVERT
+    "C",            ID_COPYTOCLIPBOARD,     VIRTKEY, CONTROL, NOINVERT
+    "C",            ID_FRAMEEXTRACT,        VIRTKEY, ALT, NOINVERT
+    "G",            ID_GOTO,                VIRTKEY, CONTROL, NOINVERT
+    "I",            ID_SESSION_INFO,        VIRTKEY, CONTROL, NOINVERT
+    "L",            ID_LOOP,                VIRTKEY, CONTROL, NOINVERT
+    "O",            ID_OPTIONS,             VIRTKEY, NOINVERT
+    "O",            ID_OPENFILE,            VIRTKEY, CONTROL, NOINVERT
+    "P",            ID_OPTIONS,             VIRTKEY, CONTROL, NOINVERT
+    "Q",            ID_CLOSEFILE,           VIRTKEY, CONTROL, NOINVERT
+    VK_F5,          ID_ZOOM_50,             VIRTKEY, NOINVERT
+    VK_F6,          ID_ZOOM_100,            VIRTKEY, NOINVERT
+    VK_F7,          ID_ZOOM_200,            VIRTKEY, NOINVERT
+    VK_RETURN,      ID_RETURN,              VIRTKEY, NOINVERT
+    VK_RETURN,      ID_FULLSCREEN,          VIRTKEY, ALT, NOINVERT
+    VK_SPACE,       ID_PLAYPAUSE,           VIRTKEY, NOINVERT
+    "X",            ID_EXIT,                VIRTKEY, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TOOLBAR             BITMAP  DISCARDABLE     "toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_GOTO DIALOG DISCARDABLE  0, 0, 153, 54
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Go to position"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_GOTO_EDIT,40,9,106,14,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "OK",IDOK,40,33,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,95,33,51,14
+    LTEXT           "Pos (ms):",IDC_STATIC,7,9,33,15,SS_CENTERIMAGE
+END
+
+IDD_PIXELFORMAT DIALOG DISCARDABLE  0, 0, 144, 78
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Pixel Format"
+FONT 8, "MS Sans Serif"
+BEGIN
+    COMBOBOX        IDC_PIXELFORMAT,7,20,130,98,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    DEFPUSHBUTTON   "OK",IDOK,20,57,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,75,57,50,14
+    LTEXT           "Choose the pixel format:",IDC_STATIC,7,7,130,13
+    CONTROL         "Big endian flag",IDC_BIG_ENDIAN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,40,63,12
+END
+
+IDD_OPTIONS DIALOG DISCARDABLE  0, 0, 187, 180
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Options"
+FONT 8, "MS Sans Serif"
+BEGIN
+    COMBOBOX        IDC_PIXELFORMAT,15,30,157,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Big endian flag",IDC_BIG_ENDIAN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,52,60,10
+    CONTROL         "Ask the pixel format before playing",IDC_ASK_PF,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,67,157,10
+    CONTROL         "Accept the bells",IDC_ACCEPT_BELL,"Button",
+                    BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,105,157,15
+    CONTROL         "Accept the cut text",IDC_ACCEPT_CUT_TEXT,"Button",
+                    BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,120,157,15
+    CONTROL         "Start play the session when it is opened",IDC_AUTOPLAY,
+                    "Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,135,
+                    157,9
+    DEFPUSHBUTTON   "OK",IDOK,20,161,50,13
+    PUSHBUTTON      "Cancel",IDCANCEL,75,161,50,13
+    PUSHBUTTON      "Default",IDC_DEFAULT,130,161,50,13
+    PUSHBUTTON      "Edit User PF",IDC_EDIT_UPF,110,52,62,14
+    GROUPBOX        "Pixel format",IDC_STATIC,7,6,173,79
+    LTEXT           "Forces the pixel format for the rfb session:",
+                    IDC_STATIC,15,17,157,13
+    GROUPBOX        "Other",IDC_STATIC,7,90,173,65
+END
+
+IDD_ABOUT DIALOG DISCARDABLE  0, 0, 251, 95
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Rfb Session Player for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,195,70,47,15
+    ICON            IDI_ICON,IDC_STATIC,7,10,20,20
+    LTEXT           ">appname<",IDC_DESCRIPTION,40,10,125,15
+    LTEXT           ">version<",IDC_VERSION,165,10,77,15
+    LTEXT           ">buildtime<",IDC_BUILDTIME,40,25,202,15
+    LTEXT           ">copyright<",IDC_COPYRIGHT,40,40,202,15
+    LTEXT           "See http://www.tightvnc.com for more information on TightVNC.",
+                    IDC_STATIC,40,55,202,15
+END
+
+IDD_USERPF_LIST DIALOG DISCARDABLE  0, 0, 207, 162
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Add / Remove the user pixel formats"
+FONT 8, "MS Sans Serif"
+BEGIN
+    LISTBOX         IDC_PF_LIST,7,7,136,148,LBS_NOINTEGRALHEIGHT | 
+                    WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Add",IDC_ADD_BUTTON,150,7,50,14
+    PUSHBUTTON      "Remove",IDC_REMOVE_BUTTON,150,26,50,14
+    PUSHBUTTON      "Edit",IDC_EDIT_BUTTON,150,45,50,14
+    PUSHBUTTON      "Close",IDOK,150,64,50,14
+END
+
+IDD_UPF_EDIT DIALOG DISCARDABLE  0, 0, 204, 126
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit the user pixel format"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_NAME_EDIT,68,7,129,13,ES_AUTOHSCROLL
+    COMBOBOX        IDC_BPP_COMBO,68,23,39,45,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    EDITTEXT        IDC_DEPTH_EDIT,157,22,40,13,ES_AUTOHSCROLL | ES_NUMBER
+    COMBOBOX        IDC_BIGENDIAN_COMBO,68,38,39,45,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    EDITTEXT        IDC_REDMAX_EDIT,68,54,39,13,ES_AUTOHSCROLL | ES_NUMBER
+    EDITTEXT        IDC_GREENMAX_EDIT,68,70,39,13,ES_AUTOHSCROLL | ES_NUMBER
+    EDITTEXT        IDC_BLUEMAX_EDIT,68,86,39,13,ES_AUTOHSCROLL | ES_NUMBER
+    EDITTEXT        IDC_REDSHIFT_EDIT,157,54,39,13,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    EDITTEXT        IDC_GREENSHIFT_EDIT,157,70,40,13,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    EDITTEXT        IDC_BLUESHIFT_EDIT,157,86,40,13,ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    PUSHBUTTON      "OK",IDOK,93,105,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,147,105,50,14
+    LTEXT           "Pixel format name:",IDC_STATIC,7,7,57,13,SS_CENTERIMAGE
+    LTEXT           "Bit per pixel:",IDC_STATIC,7,23,38,12,SS_CENTERIMAGE
+    LTEXT           "Big endian flag :",IDC_STATIC,7,38,53,13,SS_CENTERIMAGE
+    LTEXT           "Red max :",IDC_STATIC,7,54,33,13,SS_CENTERIMAGE
+    LTEXT           "Green max :",IDC_STATIC,7,70,38,13,SS_CENTERIMAGE
+    LTEXT           "Blue max :",IDC_STATIC,7,86,38,13,SS_CENTERIMAGE
+    LTEXT           "Depth:",IDC_STATIC,112,23,21,12,SS_CENTERIMAGE
+    LTEXT           "Red shifts :",IDC_STATIC,112,54,36,13,SS_CENTERIMAGE
+    LTEXT           "Green shifts :",IDC_STATIC,112,70,43,13,SS_CENTERIMAGE
+    LTEXT           "Blue shifts :",IDC_STATIC,112,86,43,13,SS_CENTERIMAGE
+END
+
+IDD_INFO DIALOG DISCARDABLE  0, 0, 295, 207
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Information"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "&OK",IDOK,122,186,50,14
+    EDITTEXT        IDC_INFO_EDIT,7,7,281,172,ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | 
+                    WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_SESSION_INFO DIALOG DISCARDABLE  0, 0, 239, 106
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RFB Session Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,182,85,50,14
+    LTEXT           "Desktop Name:",IDC_STATIC,7,10,73,15
+    LTEXT           "Desktop Size:",IDC_STATIC,7,25,73,15
+    LTEXT           "Pixel Format:",IDC_STATIC,7,40,73,15
+    LTEXT           "Current Encoding:",IDC_STATIC,7,55,73,15
+    LTEXT           "RFB Protocol Version:",IDC_STATIC,7,70,73,15
+    LTEXT           "",IDC_DESKTOP_NAME,80,10,152,15
+    LTEXT           "",IDC_DESKTOP_SIZE,80,25,152,15
+    LTEXT           "",IDC_CURRENT_ENCODING,80,55,152,15
+    LTEXT           "",IDC_VERSION,80,70,152,15
+    LTEXT           "",IDC_PIXEL_FORMAT,80,40,152,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_GOTO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 146
+        VERTGUIDE, 40
+        VERTGUIDE, 90
+        VERTGUIDE, 95
+        TOPMARGIN, 9
+        BOTTOMMARGIN, 47
+        HORZGUIDE, 9
+        HORZGUIDE, 24
+        HORZGUIDE, 35
+    END
+
+    IDD_PIXELFORMAT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 137
+        VERTGUIDE, 20
+        VERTGUIDE, 70
+        VERTGUIDE, 75
+        VERTGUIDE, 125
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 71
+        HORZGUIDE, 7
+        HORZGUIDE, 20
+        HORZGUIDE, 35
+        HORZGUIDE, 40
+        HORZGUIDE, 49
+        HORZGUIDE, 57
+    END
+
+    IDD_OPTIONS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 180
+        VERTGUIDE, 15
+        VERTGUIDE, 20
+        VERTGUIDE, 70
+        VERTGUIDE, 75
+        VERTGUIDE, 125
+        VERTGUIDE, 130
+        VERTGUIDE, 172
+        TOPMARGIN, 6
+        BOTTOMMARGIN, 174
+        HORZGUIDE, 17
+        HORZGUIDE, 30
+        HORZGUIDE, 42
+        HORZGUIDE, 52
+        HORZGUIDE, 67
+        HORZGUIDE, 85
+        HORZGUIDE, 90
+        HORZGUIDE, 105
+        HORZGUIDE, 120
+        HORZGUIDE, 135
+        HORZGUIDE, 144
+        HORZGUIDE, 150
+        HORZGUIDE, 155
+        HORZGUIDE, 161
+    END
+
+    IDD_USERPF_LIST, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 200
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 155
+        HORZGUIDE, 21
+        HORZGUIDE, 26
+        HORZGUIDE, 40
+        HORZGUIDE, 45
+        HORZGUIDE, 59
+        HORZGUIDE, 64
+    END
+
+    IDD_UPF_EDIT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 197
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 119
+    END
+
+    IDD_INFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 288
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 200
+    END
+
+    IDD_SESSION_INFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 232
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 99
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/win/rfbplayer/toolbar.bmp b/win/rfbplayer/toolbar.bmp
new file mode 100644 (file)
index 0000000..9347a73
Binary files /dev/null and b/win/rfbplayer/toolbar.bmp differ
diff --git a/win/vnc.dsw b/win/vnc.dsw
new file mode 100644 (file)
index 0000000..686cc69
--- /dev/null
@@ -0,0 +1,248 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "Xregion"=..\common\Xregion\Xregion.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "logmessages"=.\logmessages\logmessages.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "network"=..\common\network\network.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "rdr"=..\common\rdr\rdr.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "rfb"=..\common\rfb\rfb.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name rdr\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name Xregion\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "rfb_win32"=.\rfb_win32\rfb_win32.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "rfbplayer"=.\rfbplayer\rfbplayer.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name rdr\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb_win32\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name Xregion\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name zlib\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name jpeg\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "vncconfig"=.\vncconfig\vncconfig.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb_win32\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name network\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name Xregion\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "vncviewer"=.\vncviewer\vncviewer.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name zlib\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name jpeg\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb_win32\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name network\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name rdr\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name Xregion\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "winvnc"=.\winvnc\winvnc.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name network\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name rfb_win32\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name zlib\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name jpeg\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name Xregion\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "wm_hooks"=.\wm_hooks\wm_hooks.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zlib"=..\common\zlib\zlib.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "jpeg"=..\common\jpeg\jpeg.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/win/vncconfig/Authentication.h b/win/vncconfig/Authentication.h
new file mode 100644 (file)
index 0000000..f4b38f8
--- /dev/null
@@ -0,0 +1,142 @@
+/* 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 WINVNCCONF_AUTHENTICATION
+#define WINVNCCONF_AUTHENTICATION
+
+#include <vncconfig/PasswordDialog.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb/ServerCore.h>
+#include <rfb/secTypes.h>
+#include <rfb/Password.h>
+
+static rfb::BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
+  "Only prompt for a local user to accept incoming connections if there is a user logged on", false);
+
+namespace rfb {
+
+  namespace win32 {
+
+    class AuthenticationPage : public PropSheetPage {
+    public:
+      AuthenticationPage(const RegKey& rk)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_AUTHENTICATION)), regKey(rk) {}
+      void initDialog() {
+        CharArray sec_types_str(SSecurityFactoryStandard::sec_types.getData());
+        std::list<int> sec_types = parseSecTypes(sec_types_str.buf);
+
+        useNone = useVNC = false;
+        std::list<int>::iterator i;
+        for (i=sec_types.begin(); i!=sec_types.end(); i++) {
+          if ((*i) == secTypeNone) useNone = true;
+          else if ((*i) == secTypeVncAuth) useVNC = true;
+        }
+
+        HWND security = GetDlgItem(handle, IDC_ENCRYPTION);
+        SendMessage(security, CB_ADDSTRING, 0, (LPARAM)_T("Always Off"));
+        SendMessage(security, CB_SETCURSEL, 0, 0);
+        enableItem(IDC_AUTH_NT, false); enableItem(IDC_AUTH_NT_CONF, false);
+        enableItem(IDC_ENCRYPTION, false); enableItem(IDC_AUTH_RA2_CONF, false);
+
+        setItemChecked(IDC_AUTH_NONE, useNone);
+        setItemChecked(IDC_AUTH_VNC, useVNC);
+        setItemChecked(IDC_QUERY_CONNECT, rfb::Server::queryConnect);
+        setItemChecked(IDC_QUERY_LOGGED_ON, queryOnlyIfLoggedOn);
+        onCommand(IDC_AUTH_NONE, 0);
+      }
+      bool onCommand(int id, int cmd) {
+        switch (id) {
+        case IDC_AUTH_VNC_PASSWD:
+          {
+            PasswordDialog passwdDlg(regKey, registryInsecure);
+            passwdDlg.showDialog(handle);
+          }
+          return true;
+        case IDC_AUTH_NONE:
+        case IDC_AUTH_VNC:
+          enableItem(IDC_AUTH_VNC_PASSWD, isItemChecked(IDC_AUTH_VNC));
+        case IDC_QUERY_CONNECT:
+        case IDC_QUERY_LOGGED_ON:
+          setChanged((useNone != isItemChecked(IDC_AUTH_NONE)) ||
+                     (useVNC != isItemChecked(IDC_AUTH_VNC)) ||
+                     (rfb::Server::queryConnect != isItemChecked(IDC_QUERY_CONNECT)) ||
+                     (queryOnlyIfLoggedOn != isItemChecked(IDC_QUERY_LOGGED_ON)));
+          enableItem(IDC_QUERY_LOGGED_ON, enableQueryOnlyIfLoggedOn());
+          return false;
+        };
+        return false;
+      }
+      bool onOk() {
+        bool useVncChanged = useVNC != isItemChecked(IDC_AUTH_VNC);
+        useVNC = isItemChecked(IDC_AUTH_VNC);
+        useNone = isItemChecked(IDC_AUTH_NONE);
+        if (useVNC) {
+          verifyVncPassword(regKey);
+          regKey.setString(_T("SecurityTypes"), _T("VncAuth"));
+        } else {
+          if (haveVncPassword() && useVncChanged &&
+              MsgBox(0, _T("The VNC authentication method is disabled, but a password is still stored for it.\n")
+                        _T("Do you want to remove the VNC authentication password from the registry?"),
+                        MB_ICONWARNING | MB_YESNO) == IDYES) {
+            regKey.setBinary(_T("Password"), 0, 0);
+          }
+          regKey.setString(_T("SecurityTypes"), _T("None"));
+        }
+        regKey.setString(_T("ReverseSecurityTypes"), _T("None"));
+        regKey.setBool(_T("QueryConnect"), isItemChecked(IDC_QUERY_CONNECT));
+        regKey.setBool(_T("QueryOnlyIfLoggedOn"), isItemChecked(IDC_QUERY_LOGGED_ON));
+        return true;
+      }
+      void setWarnPasswdInsecure(bool warn) {
+        registryInsecure = warn;
+      }
+      bool enableQueryOnlyIfLoggedOn() {
+        return isItemChecked(IDC_QUERY_CONNECT) && osVersion.isPlatformNT && (osVersion.dwMajorVersion >= 5);
+      }
+
+
+      static bool haveVncPassword() {
+        PlainPasswd password(SSecurityFactoryStandard::vncAuthPasswd.getVncAuthPasswd());
+        return password.buf && strlen(password.buf) != 0;
+      }
+
+      static void verifyVncPassword(const RegKey& regKey) {
+        if (!haveVncPassword()) {
+          MsgBox(0, _T("The VNC authentication method is enabled, but no password is specified.\n")
+                    _T("The password dialog will now be shown."), MB_ICONINFORMATION | MB_OK);
+          PasswordDialog passwd(regKey, registryInsecure);
+          passwd.showDialog();
+        }
+      }
+
+    protected:
+      RegKey regKey;
+      static bool registryInsecure;
+      bool useNone;
+      bool useVNC;
+    };
+
+  };
+
+  bool AuthenticationPage::registryInsecure = false;
+
+};
+
+#endif
diff --git a/win/vncconfig/Connections.h b/win/vncconfig/Connections.h
new file mode 100644 (file)
index 0000000..7512cc6
--- /dev/null
@@ -0,0 +1,298 @@
+/* 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 WINVNCCONF_CONNECTIONS
+#define WINVNCCONF_CONNECTIONS
+
+#include <vector>
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/ModuleFileName.h>
+#include <rfb/Configuration.h>
+#include <rfb/Blacklist.h>
+#include <network/TcpSocket.h>
+
+static rfb::IntParameter http_port("HTTPPortNumber",
+  "TCP/IP port on which the server will serve the Java applet VNC Viewer ", 5800);
+static rfb::IntParameter port_number("PortNumber",
+  "TCP/IP port on which the server will accept connections", 5900);
+static rfb::StringParameter hosts("Hosts",
+  "Filter describing which hosts are allowed access to this server", "+");
+static rfb::BoolParameter localHost("LocalHost",
+  "Only accept connections from via the local loop-back network interface", false);
+
+namespace rfb {
+
+  namespace win32 {
+
+    class ConnHostDialog : public Dialog {
+    public:
+      ConnHostDialog() : Dialog(GetModuleHandle(0)) {}
+      bool showDialog(const TCHAR* pat) {
+        pattern.replaceBuf(tstrDup(pat));
+        return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONN_HOST));
+      }
+      void initDialog() {
+        if (_tcslen(pattern.buf) == 0)
+          pattern.replaceBuf(tstrDup("+"));
+
+        if (pattern.buf[0] == _T('+'))
+          setItemChecked(IDC_ALLOW, true);
+        else if (pattern.buf[0] == _T('?'))
+          setItemChecked(IDC_QUERY, true);
+        else
+          setItemChecked(IDC_DENY, true);
+
+        setItemString(IDC_HOST_PATTERN, &pattern.buf[1]);
+        pattern.replaceBuf(0);
+      }
+      bool onOk() {
+        TCharArray host = getItemString(IDC_HOST_PATTERN);
+        TCharArray newPat(_tcslen(host.buf)+2);
+        if (isItemChecked(IDC_ALLOW))
+          newPat.buf[0] = _T('+');
+        else if (isItemChecked(IDC_QUERY))
+          newPat.buf[0] = _T('?');
+        else
+          newPat.buf[0] = _T('-');
+        newPat.buf[1] = 0;
+        _tcscat(newPat.buf, host.buf);
+
+        network::TcpFilter::Pattern pat(network::TcpFilter::parsePattern(CStr(newPat.buf)));
+        pattern.replaceBuf(TCharArray(network::TcpFilter::patternToStr(pat)).takeBuf());
+        return true;
+      }
+      const TCHAR* getPattern() {return pattern.buf;}
+    protected:
+      TCharArray pattern;
+    };
+
+    class ConnectionsPage : public PropSheetPage {
+    public:
+      ConnectionsPage(const RegKey& rk)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_CONNECTIONS)), regKey(rk) {}
+      void initDialog() {
+        vlog.debug("set IDC_PORT %d", (int)port_number);
+        setItemInt(IDC_PORT, port_number ? port_number : 5900);
+        setItemChecked(IDC_RFB_ENABLE, port_number != 0);
+        setItemInt(IDC_IDLE_TIMEOUT, rfb::Server::idleTimeout);
+        vlog.debug("set IDC_HTTP_PORT %d", (int)http_port);
+        setItemInt(IDC_HTTP_PORT, http_port ? http_port : 5800);
+        setItemChecked(IDC_HTTP_ENABLE, http_port != 0);
+        enableItem(IDC_HTTP_PORT, http_port != 0);
+        setItemChecked(IDC_LOCALHOST, localHost);
+
+        HWND listBox = GetDlgItem(handle, IDC_HOSTS);
+        while (SendMessage(listBox, LB_GETCOUNT, 0, 0))
+          SendMessage(listBox, LB_DELETESTRING, 0, 0);
+
+        CharArray tmp;
+        tmp.buf = hosts.getData();
+        while (tmp.buf) {
+          CharArray first;
+          strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
+          if (strlen(first.buf))
+            SendMessage(listBox, LB_ADDSTRING, 0, (LPARAM)(const TCHAR*)TStr(first.buf));
+        }
+
+        onCommand(IDC_RFB_ENABLE, EN_CHANGE);
+      }
+      bool onCommand(int id, int cmd) {
+        switch (id) {
+        case IDC_HOSTS:
+          {
+            DWORD selected = SendMessage(GetDlgItem(handle, IDC_HOSTS), LB_GETCURSEL, 0, 0);
+            int count = SendMessage(GetDlgItem(handle, IDC_HOSTS), LB_GETCOUNT, 0, 0);
+            bool enable = selected != LB_ERR;
+            enableItem(IDC_HOST_REMOVE, enable);
+            enableItem(IDC_HOST_UP, enable && (selected > 0));
+            enableItem(IDC_HOST_DOWN, enable && (selected < count-1));
+            enableItem(IDC_HOST_EDIT, enable);
+            setChanged(isChanged());
+          }
+          return true;
+
+        case IDC_PORT:
+          if (cmd == EN_CHANGE) {
+            try {
+              setItemInt(IDC_HTTP_PORT, rfbPortToHTTP(getItemInt(IDC_PORT)));
+            } catch (...) {
+            }
+          }
+        case IDC_HTTP_PORT:
+        case IDC_IDLE_TIMEOUT:
+          if (cmd == EN_CHANGE)
+            setChanged(isChanged());
+          return false;
+
+        case IDC_HTTP_ENABLE:
+        case IDC_RFB_ENABLE:
+        case IDC_LOCALHOST:
+          {
+            // HTTP port
+            enableItem(IDC_HTTP_PORT, isItemChecked(IDC_HTTP_ENABLE) && isItemChecked(IDC_RFB_ENABLE));
+            enableItem(IDC_HTTP_ENABLE, isItemChecked(IDC_RFB_ENABLE));
+
+            // RFB port
+            enableItem(IDC_PORT, isItemChecked(IDC_RFB_ENABLE));
+
+            // Hosts
+            enableItem(IDC_LOCALHOST, isItemChecked(IDC_RFB_ENABLE));
+
+            bool enableHosts = !isItemChecked(IDC_LOCALHOST) && isItemChecked(IDC_RFB_ENABLE);
+            enableItem(IDC_HOSTS, enableHosts);
+            enableItem(IDC_HOST_ADD, enableHosts);
+            if (!enableHosts) {
+              enableItem(IDC_HOST_REMOVE, enableHosts);
+              enableItem(IDC_HOST_UP, enableHosts);
+              enableItem(IDC_HOST_DOWN, enableHosts);
+              enableItem(IDC_HOST_EDIT, enableHosts);
+            } else {
+              onCommand(IDC_HOSTS, EN_CHANGE);
+            }
+            setChanged(isChanged());
+            return false;
+          }
+
+        case IDC_HOST_ADD:
+          if (hostDialog.showDialog(_T("")))
+          {
+            const TCHAR* pattern = hostDialog.getPattern();
+            if (pattern)
+              SendMessage(GetDlgItem(handle, IDC_HOSTS), LB_ADDSTRING, 0, (LPARAM)pattern);
+          }
+          return true;
+
+        case IDC_HOST_EDIT:
+          {
+            HWND listBox = GetDlgItem(handle, IDC_HOSTS);
+            int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
+            TCharArray pattern(SendMessage(listBox, LB_GETTEXTLEN, item, 0)+1);
+            SendMessage(listBox, LB_GETTEXT, item, (LPARAM)pattern.buf);
+
+            if (hostDialog.showDialog(pattern.buf)) {
+              const TCHAR* newPat = hostDialog.getPattern();
+              if (newPat) {
+                item = SendMessage(listBox, LB_FINDSTRINGEXACT, item, (LPARAM)pattern.buf);
+                if (item != LB_ERR) {
+                  SendMessage(listBox, LB_DELETESTRING, item, 0); 
+                  SendMessage(listBox, LB_INSERTSTRING, item, (LPARAM)newPat);
+                  SendMessage(listBox, LB_SETCURSEL, item, 0);
+                  onCommand(IDC_HOSTS, EN_CHANGE);
+                }
+              }
+            }
+          }
+          return true;
+
+        case IDC_HOST_UP:
+          {
+            HWND listBox = GetDlgItem(handle, IDC_HOSTS);
+            int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
+            TCharArray pattern(SendMessage(listBox, LB_GETTEXTLEN, item, 0)+1);
+            SendMessage(listBox, LB_GETTEXT, item, (LPARAM)pattern.buf);
+            SendMessage(listBox, LB_DELETESTRING, item, 0);
+            SendMessage(listBox, LB_INSERTSTRING, item-1, (LPARAM)pattern.buf);
+            SendMessage(listBox, LB_SETCURSEL, item-1, 0);
+            onCommand(IDC_HOSTS, EN_CHANGE);
+          }
+          return true;
+
+        case IDC_HOST_DOWN:
+          {
+            HWND listBox = GetDlgItem(handle, IDC_HOSTS);
+            int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
+            TCharArray pattern(SendMessage(listBox, LB_GETTEXTLEN, item, 0)+1);
+            SendMessage(listBox, LB_GETTEXT, item, (LPARAM)pattern.buf);
+            SendMessage(listBox, LB_DELETESTRING, item, 0);
+            SendMessage(listBox, LB_INSERTSTRING, item+1, (LPARAM)pattern.buf);
+            SendMessage(listBox, LB_SETCURSEL, item+1, 0);
+            onCommand(IDC_HOSTS, EN_CHANGE);
+          }
+          return true;
+
+        case IDC_HOST_REMOVE:
+          {
+            HWND listBox = GetDlgItem(handle, IDC_HOSTS);
+            int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
+            SendMessage(listBox, LB_DELETESTRING, item, 0);
+            onCommand(IDC_HOSTS, EN_CHANGE);
+          }
+
+        }
+        return false;
+      }
+      bool onOk() {
+        regKey.setInt(_T("PortNumber"), isItemChecked(IDC_RFB_ENABLE) ? getItemInt(IDC_PORT) : 0);
+        regKey.setInt(_T("IdleTimeout"), getItemInt(IDC_IDLE_TIMEOUT));
+        regKey.setInt(_T("HTTPPortNumber"), isItemChecked(IDC_HTTP_ENABLE) && isItemChecked(IDC_RFB_ENABLE)
+                                            ? getItemInt(IDC_HTTP_PORT) : 0);
+        regKey.setInt(_T("LocalHost"), isItemChecked(IDC_LOCALHOST));
+        regKey.setString(_T("Hosts"), TCharArray(getHosts()).buf);
+        return true;
+      }
+      bool isChanged() {
+        try {
+          CharArray new_hosts = getHosts();
+          CharArray old_hosts = hosts.getData();
+          return (strcmp(new_hosts.buf, old_hosts.buf) != 0) ||
+              (localHost != isItemChecked(IDC_LOCALHOST)) ||
+              (port_number != getItemInt(IDC_PORT)) ||
+              (http_port != getItemInt(IDC_HTTP_PORT)) ||
+              ((http_port!=0) != (isItemChecked(IDC_HTTP_ENABLE)!=0)) ||
+              (rfb::Server::idleTimeout != getItemInt(IDC_IDLE_TIMEOUT));
+        } catch (rdr::Exception) {
+          return false;
+        }
+      }
+      char* getHosts() {
+        int bufLen = 1, i;
+        HWND listBox = GetDlgItem(handle, IDC_HOSTS);
+        for (i=0; i<SendMessage(listBox, LB_GETCOUNT, 0, 0); i++)
+          bufLen+=SendMessage(listBox, LB_GETTEXTLEN, i, 0)+1;
+        TCharArray hosts_str(bufLen);
+        hosts_str.buf[0] = 0;
+        TCHAR* outPos = hosts_str.buf;
+        for (i=0; i<SendMessage(listBox, LB_GETCOUNT, 0, 0); i++) {
+          outPos += SendMessage(listBox, LB_GETTEXT, i, (LPARAM)outPos);
+          outPos[0] = ',';
+          outPos[1] = 0;
+          outPos++;
+        }
+        return strDup(hosts_str.buf);
+      }
+      int rfbPortToHTTP(int rfbPort) {
+        int offset = -100;
+        if (http_port)
+          offset = http_port - port_number;
+        int httpPort = rfbPort + offset;
+        if (httpPort <= 0)
+          httpPort = rfbPort;
+        return httpPort;
+      }
+
+    protected:
+      RegKey regKey;
+      ConnHostDialog hostDialog;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncconfig/Desktop.h b/win/vncconfig/Desktop.h
new file mode 100644 (file)
index 0000000..164269a
--- /dev/null
@@ -0,0 +1,94 @@
+/* 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 WINVNCCONF_DESKTOP
+#define WINVNCCONF_DESKTOP
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/SDisplay.h>
+#include <rfb_win32/DynamicFn.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class DesktopPage : public PropSheetPage {
+    public:
+      DesktopPage(const RegKey& rk)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DESKTOP)), regKey(rk) {}
+      void initDialog() {
+        CharArray action = rfb::win32::SDisplay::disconnectAction.getData();
+        bool disconnectLock = stricmp(action.buf, "Lock") == 0;
+        bool disconnectLogoff = stricmp(action.buf, "Logoff") == 0;
+        typedef BOOL (WINAPI *_LockWorkStation_proto)();
+        DynamicFn<_LockWorkStation_proto> _LockWorkStation(_T("user32.dll"), "LockWorkStation");
+        if (!_LockWorkStation.isValid()) {
+          enableItem(IDC_DISCONNECT_LOCK, false);
+          if (disconnectLock) {
+            disconnectLogoff = true;
+            disconnectLock = false;
+          }
+        }
+        setItemChecked(IDC_DISCONNECT_LOGOFF, disconnectLogoff);
+        setItemChecked(IDC_DISCONNECT_LOCK, disconnectLock);
+        setItemChecked(IDC_DISCONNECT_NONE, !disconnectLock && !disconnectLogoff);
+        setItemChecked(IDC_REMOVE_WALLPAPER, rfb::win32::SDisplay::removeWallpaper);
+        setItemChecked(IDC_REMOVE_PATTERN, rfb::win32::SDisplay::removePattern);
+        setItemChecked(IDC_DISABLE_EFFECTS, rfb::win32::SDisplay::disableEffects);
+      }
+      bool onCommand(int id, int cmd) {
+        switch (id) {
+        case IDC_DISCONNECT_LOGOFF:
+        case IDC_DISCONNECT_LOCK:
+        case IDC_DISCONNECT_NONE:
+        case IDC_REMOVE_WALLPAPER:
+        case IDC_REMOVE_PATTERN:
+        case IDC_DISABLE_EFFECTS:
+          CharArray action = rfb::win32::SDisplay::disconnectAction.getData();
+          bool disconnectLock = stricmp(action.buf, "Lock") == 0;
+          bool disconnectLogoff = stricmp(action.buf, "Logoff") == 0;
+          setChanged((disconnectLogoff != isItemChecked(IDC_DISCONNECT_LOGOFF)) ||
+                     (disconnectLock != isItemChecked(IDC_DISCONNECT_LOCK)) ||
+                     (isItemChecked(IDC_REMOVE_WALLPAPER) != rfb::win32::SDisplay::removeWallpaper) ||
+                     (isItemChecked(IDC_REMOVE_PATTERN) != rfb::win32::SDisplay::removePattern) ||
+                     (isItemChecked(IDC_DISABLE_EFFECTS) != rfb::win32::SDisplay::disableEffects));
+          break;
+        }
+        return false;
+      }
+      bool onOk() {
+        const TCHAR* action = _T("None");
+        if (isItemChecked(IDC_DISCONNECT_LOGOFF))
+          action = _T("Logoff");
+        else if (isItemChecked(IDC_DISCONNECT_LOCK))
+          action = _T("Lock");
+        regKey.setString(_T("DisconnectAction"), action);
+        regKey.setBool(_T("RemoveWallpaper"), isItemChecked(IDC_REMOVE_WALLPAPER));
+        regKey.setBool(_T("RemovePattern"), isItemChecked(IDC_REMOVE_PATTERN));
+        regKey.setBool(_T("DisableEffects"), isItemChecked(IDC_DISABLE_EFFECTS));
+        return true;
+      }
+    protected:
+      RegKey regKey;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncconfig/Hooking.h b/win/vncconfig/Hooking.h
new file mode 100644 (file)
index 0000000..9be82f3
--- /dev/null
@@ -0,0 +1,88 @@
+/* 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 WINVNCCONF_HOOKING
+#define WINVNCCONF_HOOKING
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/SDisplay.h>
+#include <rfb_win32/WMPoller.h>
+#include <rfb/ServerCore.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class HookingPage : public PropSheetPage {
+    public:
+      HookingPage(const RegKey& rk)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_HOOKING)), regKey(rk) {}
+      void initDialog() {
+        setItemChecked(IDC_USEPOLLING, rfb::win32::SDisplay::updateMethod == 0);
+        setItemChecked(IDC_USEHOOKS, (rfb::win32::SDisplay::updateMethod == 1) &&
+                       rfb::win32::SDisplay::areHooksAvailable());
+        enableItem(IDC_USEHOOKS, rfb::win32::SDisplay::areHooksAvailable());
+        setItemChecked(IDC_USEDRIVER, (rfb::win32::SDisplay::updateMethod == 2) &&
+                       rfb::win32::SDisplay::isDriverAvailable());
+        enableItem(IDC_USEDRIVER, rfb::win32::SDisplay::isDriverAvailable());
+        setItemChecked(IDC_POLLCONSOLES, rfb::win32::WMPoller::poll_console_windows);
+        setItemChecked(IDC_CAPTUREBLT, osVersion.isPlatformNT &&
+                       rfb::win32::DeviceFrameBuffer::useCaptureBlt);
+        enableItem(IDC_CAPTUREBLT, osVersion.isPlatformNT);
+        onCommand(IDC_USEHOOKS, 0);
+      }
+      bool onCommand(int id, int cmd) {
+        switch (id) {
+        case IDC_USEPOLLING:
+        case IDC_USEHOOKS:
+        case IDC_USEDRIVER:
+        case IDC_POLLCONSOLES:
+        case IDC_CAPTUREBLT:
+          setChanged(((rfb::win32::SDisplay::updateMethod == 0) != isItemChecked(IDC_USEPOLLING)) ||
+            ((rfb::win32::SDisplay::updateMethod == 1) != isItemChecked(IDC_USEHOOKS)) ||
+            ((rfb::win32::SDisplay::updateMethod == 2) != isItemChecked(IDC_USEDRIVER)) ||
+            (rfb::win32::WMPoller::poll_console_windows != isItemChecked(IDC_POLLCONSOLES)) ||
+            (rfb::win32::DeviceFrameBuffer::useCaptureBlt != isItemChecked(IDC_CAPTUREBLT)));
+          enableItem(IDC_POLLCONSOLES, isItemChecked(IDC_USEHOOKS));
+          break;
+        }
+        return false;
+      }
+      bool onOk() {
+        if (isItemChecked(IDC_USEPOLLING))
+          regKey.setInt(_T("UpdateMethod"), 0);
+        if (isItemChecked(IDC_USEHOOKS))
+          regKey.setInt(_T("UpdateMethod"), 1);
+        if (isItemChecked(IDC_USEDRIVER))
+          regKey.setInt(_T("UpdateMethod"), 2);
+        regKey.setBool(_T("PollConsoleWindows"), isItemChecked(IDC_POLLCONSOLES));
+        regKey.setBool(_T("UseCaptureBlt"), isItemChecked(IDC_CAPTUREBLT));
+
+        // *** LEGACY compatibility ***
+        regKey.setBool(_T("UseHooks"), isItemChecked(IDC_USEHOOKS));
+        return true;
+      }
+    protected:
+      RegKey regKey;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncconfig/Inputs.h b/win/vncconfig/Inputs.h
new file mode 100644 (file)
index 0000000..1e0b4ba
--- /dev/null
@@ -0,0 +1,84 @@
+/* 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 WINVNCCONF_INPUTS
+#define WINVNCCONF_INPUTS
+
+#ifndef SPI_GETBLOCKSENDINPUTRESETS
+#define SPI_GETBLOCKSENDINPUTRESETS 0x1026
+#define SPI_SETBLOCKSENDINPUTRESETS 0x1027
+#endif
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb/ServerCore.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class InputsPage : public PropSheetPage {
+    public:
+      InputsPage(const RegKey& rk)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_INPUTS)),
+          regKey(rk), enableAffectSSaver(true) {}
+      void initDialog() {
+        setItemChecked(IDC_ACCEPT_KEYS, rfb::Server::acceptKeyEvents);
+        setItemChecked(IDC_ACCEPT_PTR, rfb::Server::acceptPointerEvents);
+        setItemChecked(IDC_ACCEPT_CUTTEXT, rfb::Server::acceptCutText);
+        setItemChecked(IDC_SEND_CUTTEXT, rfb::Server::sendCutText);
+        setItemChecked(IDC_DISABLE_LOCAL_INPUTS, SDisplay::disableLocalInputs);
+        enableItem(IDC_DISABLE_LOCAL_INPUTS, !osVersion.isPlatformWindows);
+        BOOL blocked = FALSE;
+        if (SystemParametersInfo(SPI_GETBLOCKSENDINPUTRESETS, 0, &blocked, 0))
+          setItemChecked(IDC_AFFECT_SCREENSAVER, !blocked);
+        else
+          enableAffectSSaver = false;
+        enableItem(IDC_AFFECT_SCREENSAVER, enableAffectSSaver);
+      }
+      bool onCommand(int id, int cmd) {
+        BOOL inputResetsBlocked;
+        SystemParametersInfo(SPI_GETBLOCKSENDINPUTRESETS, 0, &inputResetsBlocked, 0);
+        setChanged((rfb::Server::acceptKeyEvents != isItemChecked(IDC_ACCEPT_KEYS)) ||
+          (rfb::Server::acceptPointerEvents != isItemChecked(IDC_ACCEPT_PTR)) ||
+          (rfb::Server::acceptCutText != isItemChecked(IDC_ACCEPT_CUTTEXT)) ||
+          (rfb::Server::sendCutText != isItemChecked(IDC_SEND_CUTTEXT)) ||
+          (SDisplay::disableLocalInputs != isItemChecked(IDC_DISABLE_LOCAL_INPUTS)) ||
+          (enableAffectSSaver && (!inputResetsBlocked != isItemChecked(IDC_AFFECT_SCREENSAVER))));
+        return false;
+      }
+      bool onOk() {
+        regKey.setBool(_T("AcceptKeyEvents"), isItemChecked(IDC_ACCEPT_KEYS));
+        regKey.setBool(_T("AcceptPointerEvents"), isItemChecked(IDC_ACCEPT_PTR));
+        regKey.setBool(_T("AcceptCutText"), isItemChecked(IDC_ACCEPT_CUTTEXT));
+        regKey.setBool(_T("SendCutText"), isItemChecked(IDC_SEND_CUTTEXT));
+        regKey.setBool(_T("DisableLocalInputs"), isItemChecked(IDC_DISABLE_LOCAL_INPUTS));
+        if (enableAffectSSaver) {
+          BOOL blocked = !isItemChecked(IDC_AFFECT_SCREENSAVER);
+          SystemParametersInfo(SPI_SETBLOCKSENDINPUTRESETS, blocked, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
+        }
+        return true;
+      }
+    protected:
+      RegKey regKey;
+      bool enableAffectSSaver;
+    };
+
+  };
+};
+
+#endif
diff --git a/win/vncconfig/Legacy.cxx b/win/vncconfig/Legacy.cxx
new file mode 100644 (file)
index 0000000..ae5d716
--- /dev/null
@@ -0,0 +1,248 @@
+/* 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 <vncconfig/Legacy.h>
+
+#include <rfb/LogWriter.h>
+#include <rfb/Password.h>
+#include <rfb_win32/CurrentUser.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("Legacy");
+
+
+void LegacyPage::LoadPrefs()
+      {
+        // VNC 3.3.3R3 Preferences Algorithm, as described by vncProperties.cpp
+        // - Load user-specific settings, based on logged-on user name,
+        //   from HKLM/Software/ORL/WinVNC3/<user>.  If they don't exist,
+        //   try again with username "Default".
+        // - Load system-wide settings from HKLM/Software/ORL/WinVNC3.
+        // - If AllowProperties is non-zero then load the user's own
+        //   settings from HKCU/Software/ORL/WinVNC3.
+
+        // Get the name of the current user
+        TCharArray username;
+        try {
+          UserName name;
+          username.buf = name.takeBuf();
+        } catch (rdr::SystemException& e) {
+          if (e.err != ERROR_NOT_LOGGED_ON)
+            throw;
+        }
+
+        // Open and read the WinVNC3 registry key
+        allowProperties = true;
+        RegKey winvnc3;
+        try {
+          winvnc3.openKey(HKEY_LOCAL_MACHINE, _T("Software\\ORL\\WinVNC3"));
+          int debugMode = winvnc3.getInt(_T("DebugMode"), 0);
+          const char* debugTarget = 0; 
+          if (debugMode & 2) debugTarget = "file";
+          if (debugMode & 4) debugTarget = "stderr";
+          if (debugTarget) {
+            char logSetting[32];
+            sprintf(logSetting, "*:%s:%d", debugTarget, winvnc3.getInt(_T("DebugLevel"), 0));
+            regKey.setString(_T("Log"), TStr(logSetting));
+          }
+          TCharArray authHosts;
+          authHosts.buf = winvnc3.getString(_T("AuthHosts"), 0);
+          if (authHosts.buf) {
+            CharArray newHosts;
+            newHosts.buf = strDup("");
+
+            // Reformat AuthHosts to Hosts.  Wish I'd left the format the same. :( :( :(
+            try {
+              CharArray tmp = strDup(authHosts.buf);
+              while (tmp.buf) {
+
+                // Split the AuthHosts string into patterns to match
+                CharArray first;
+                rfb::strSplit(tmp.buf, ':', &first.buf, &tmp.buf);
+                if (strlen(first.buf)) {
+                  int bits = 0;
+                  CharArray pattern(1+4*4+4);
+                  pattern.buf[0] = first.buf[0];
+                  pattern.buf[1] = 0;
+
+                  // Split the pattern into IP address parts and process
+                  rfb::CharArray address;
+                  address.buf = rfb::strDup(&first.buf[1]);
+                  while (address.buf) {
+                    rfb::CharArray part;
+                    rfb::strSplit(address.buf, '.', &part.buf, &address.buf);
+                    if (bits)
+                      strcat(pattern.buf, ".");
+                    if (strlen(part.buf) > 3)
+                      throw rdr::Exception("Invalid IP address part");
+                    if (strlen(part.buf) > 0) {
+                      strcat(pattern.buf, part.buf);
+                      bits += 8;
+                    }
+                  }
+
+                  // Pad out the address specification if required
+                  int addrBits = bits;
+                  while (addrBits < 32) {
+                    if (addrBits) strcat(pattern.buf, ".");
+                    strcat(pattern.buf, "0");
+                    addrBits += 8;
+                  }
+
+                  // Append the number of bits to match
+                  char buf[4];
+                  sprintf(buf, "/%d", bits);
+                  strcat(pattern.buf, buf);
+
+                  // Append this pattern to the Hosts value
+                  int length = strlen(newHosts.buf) + strlen(pattern.buf) + 2;
+                  CharArray tmpHosts(length);
+                  strcpy(tmpHosts.buf, pattern.buf);
+                  if (strlen(newHosts.buf)) {
+                    strcat(tmpHosts.buf, ",");
+                    strcat(tmpHosts.buf, newHosts.buf);
+                  }
+                  delete [] newHosts.buf;
+                  newHosts.buf = tmpHosts.takeBuf();
+                }
+              }
+
+              // Finally, save the Hosts value
+              regKey.setString(_T("Hosts"), TStr(newHosts.buf));
+            } catch (rdr::Exception) {
+              MsgBox(0, _T("Unable to convert AuthHosts setting to Hosts format."),
+                     MB_ICONWARNING | MB_OK);
+            }
+          } else {
+            regKey.setString(_T("Hosts"), _T("+"));
+          }
+
+          regKey.setBool(_T("LocalHost"), winvnc3.getBool(_T("LoopbackOnly"), false));
+          // *** check AllowLoopback?
+
+          if (winvnc3.getBool(_T("AuthRequired"), true))
+            regKey.setString(_T("SecurityTypes"), _T("VncAuth"));
+          else
+            regKey.setString(_T("SecurityTypes"), _T("None"));
+
+          int connectPriority = winvnc3.getInt(_T("ConnectPriority"), 0);
+          regKey.setBool(_T("DisconnectClients"), connectPriority == 0);
+          regKey.setBool(_T("AlwaysShared"), connectPriority == 1);
+          regKey.setBool(_T("NeverShared"), connectPriority == 2);
+
+        } catch(rdr::Exception) {
+        }
+
+        // Open the local, default-user settings
+        allowProperties = true;
+        try {
+          RegKey userKey;
+          userKey.openKey(winvnc3, _T("Default"));
+          vlog.info("loading Default prefs");
+          LoadUserPrefs(userKey);
+        } catch(rdr::Exception& e) {
+          vlog.error("error reading Default settings:%s", e.str());
+        }
+
+        // Open the local, user-specific settings
+        if (userSettings && username.buf) {
+          try {
+            RegKey userKey;
+            userKey.openKey(winvnc3, username.buf);
+            vlog.info("loading local User prefs");
+            LoadUserPrefs(userKey);
+          } catch(rdr::Exception& e) {
+            vlog.error("error reading local User settings:%s", e.str());
+          }
+
+          // Open the user's own settings
+          if (allowProperties) {
+            try {
+              RegKey userKey;
+              userKey.openKey(HKEY_CURRENT_USER, _T("Software\\ORL\\WinVNC3"));
+              vlog.info("loading global User prefs");
+              LoadUserPrefs(userKey);
+            } catch(rdr::Exception& e) {
+              vlog.error("error reading global User settings:%s", e.str());
+            }
+          }
+        }
+
+        // Disable the Options menu item if appropriate
+        regKey.setBool(_T("DisableOptions"), !allowProperties);
+      }
+
+      void LegacyPage::LoadUserPrefs(const RegKey& key)
+      {
+        if (key.getBool(_T("HTTPConnect"), true))
+          regKey.setInt(_T("HTTPPortNumber"), key.getInt(_T("PortNumber"), 5900)-100);
+        else
+          regKey.setInt(_T("HTTPPortNumber"), 0);
+        regKey.setInt(_T("PortNumber"), key.getBool(_T("SocketConnect")) ? key.getInt(_T("PortNumber"), 5900) : 0);
+        if (key.getBool(_T("AutoPortSelect"), false)) {
+          MsgBox(0, _T("The AutoPortSelect setting is not supported by this release.")
+                    _T("The port number will default to 5900."),
+                    MB_ICONWARNING | MB_OK);
+          regKey.setInt(_T("PortNumber"), 5900);
+        }
+        regKey.setInt(_T("IdleTimeout"), key.getInt(_T("IdleTimeout"), 0));
+
+        regKey.setBool(_T("RemoveWallpaper"), key.getBool(_T("RemoveWallpaper")));
+        regKey.setBool(_T("RemovePattern"), key.getBool(_T("RemoveWallpaper")));
+        regKey.setBool(_T("DisableEffects"), key.getBool(_T("RemoveWallpaper")));
+
+        if (key.getInt(_T("QuerySetting"), 2) != 2) {
+          regKey.setBool(_T("QueryConnect"), key.getInt(_T("QuerySetting")) > 2);
+          MsgBox(0, _T("The QuerySetting option has been replaced by QueryConnect.")
+                 _T("Please see the documentation for details of the QueryConnect option."),
+                 MB_ICONWARNING | MB_OK);
+        }
+        regKey.setInt(_T("QueryTimeout"), key.getInt(_T("QueryTimeout"), 10));
+
+        ObfuscatedPasswd passwd;
+        key.getBinary(_T("Password"), (void**)&passwd.buf, &passwd.length, 0, 0);
+        regKey.setBinary(_T("Password"), passwd.buf, passwd.length);
+
+        bool enableInputs = key.getBool(_T("InputsEnabled"), true);
+        regKey.setBool(_T("AcceptKeyEvents"), enableInputs);
+        regKey.setBool(_T("AcceptPointerEvents"), enableInputs);
+        regKey.setBool(_T("AcceptCutText"), enableInputs);
+        regKey.setBool(_T("SendCutText"), enableInputs);
+
+        switch (key.getInt(_T("LockSetting"), 0)) {
+        case 0: regKey.setString(_T("DisconnectAction"), _T("None")); break;
+        case 1: regKey.setString(_T("DisconnectAction"), _T("Lock")); break;
+        case 2: regKey.setString(_T("DisconnectAction"), _T("Logoff")); break;
+        };
+
+        regKey.setBool(_T("DisableLocalInputs"), key.getBool(_T("LocalInputsDisabled"), false));
+
+        // *** ignore polling preferences
+        // PollUnderCursor, PollForeground, OnlyPollConsole, OnlyPollOnEvent
+        regKey.setBool(_T("UseHooks"), !key.getBool(_T("PollFullScreen"), false));
+
+        if (key.isValue(_T("AllowShutdown")))
+          MsgBox(0, _T("The AllowShutdown option is not supported by this release."), MB_ICONWARNING | MB_OK);
+        if (key.isValue(_T("AllowEditClients")))
+          MsgBox(0, _T("The AllowEditClients option is not supported by this release."), MB_ICONWARNING | MB_OK);
+
+        allowProperties = key.getBool(_T("AllowProperties"), allowProperties);
+      }
diff --git a/win/vncconfig/Legacy.h b/win/vncconfig/Legacy.h
new file mode 100644 (file)
index 0000000..02059a6
--- /dev/null
@@ -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.
+ */
+
+#ifndef WINVNCCONF_LEGACY
+#define WINVNCCONF_LEGACY
+
+#include <windows.h>
+#include <lmcons.h>
+#include <vncconfig/resource.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb/ServerCore.h>
+#include <rfb/secTypes.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class LegacyPage : public PropSheetPage {
+    public:
+      LegacyPage(const RegKey& rk, bool userSettings_)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_LEGACY)), regKey(rk), userSettings(userSettings_) {}
+      void initDialog() {
+        setItemChecked(IDC_PROTOCOL_3_3, rfb::Server::protocol3_3);
+      }
+      bool onCommand(int id, int cmd) {
+        switch (id) {
+        case IDC_LEGACY_IMPORT:
+          {
+            DWORD result = MsgBox(0,
+              _T("Importing your legacy VNC 3.3 settings will overwrite your existing settings.\n")
+              _T("Are you sure you wish to continue?"),
+              MB_ICONWARNING | MB_YESNO);
+            if (result == IDYES) {
+              LoadPrefs();
+              MsgBox(0, _T("Imported VNC 3.3 settings successfully."),
+                     MB_ICONINFORMATION | MB_OK);
+
+              // Sleep to allow RegConfig thread to reload settings
+              Sleep(1000);
+              propSheet->reInitPages();
+            }
+          }
+          return true;
+        case IDC_PROTOCOL_3_3:
+          setChanged(isItemChecked(IDC_PROTOCOL_3_3) != rfb::Server::protocol3_3);
+          return false;
+        };
+        return false;
+      }
+      bool onOk() {
+        regKey.setBool(_T("Protocol3.3"), isItemChecked(IDC_PROTOCOL_3_3));
+        return true;
+      }
+
+      void LoadPrefs();
+      void LoadUserPrefs(const RegKey& key);
+
+    protected:
+      bool allowProperties;
+      RegKey regKey;
+      bool userSettings;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncconfig/PasswordDialog.cxx b/win/vncconfig/PasswordDialog.cxx
new file mode 100644 (file)
index 0000000..d26d86f
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (C) 2004-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 <vncconfig/resource.h>
+#include <vncconfig/PasswordDialog.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb/Password.h>
+
+using namespace rfb;
+using namespace win32;
+
+PasswordDialog::PasswordDialog(const RegKey& rk, bool registryInsecure_)
+  : Dialog(GetModuleHandle(0)), regKey(rk), registryInsecure(registryInsecure_) {
+}
+
+bool PasswordDialog::showDialog(HWND owner) {
+  return Dialog::showDialog(MAKEINTRESOURCE(IDD_AUTH_VNC_PASSWD), owner);
+}
+
+bool PasswordDialog::onOk() {
+  TPlainPasswd password1(getItemString(IDC_PASSWORD1));
+  TPlainPasswd password2(getItemString(IDC_PASSWORD2));
+  if (_tcscmp(password1.buf, password2.buf) != 0) {
+    MsgBox(0, _T("The supplied passwords do not match"),
+           MB_ICONEXCLAMATION | MB_OK);
+    return false;
+  }
+  if (registryInsecure &&
+      (MsgBox(0, _T("Please note that your password cannot be stored securely on this system.  ")
+                 _T("Are you sure you wish to continue?"),
+              MB_YESNO | MB_ICONWARNING) == IDNO))
+    return false;
+  PlainPasswd password(strDup(password1.buf));
+  ObfuscatedPasswd obfPwd(password);
+  regKey.setBinary(_T("Password"), obfPwd.buf, obfPwd.length);
+  return true;
+}
diff --git a/win/vncconfig/PasswordDialog.h b/win/vncconfig/PasswordDialog.h
new file mode 100644 (file)
index 0000000..dd23f8e
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2004-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 WINVNCCONF_PASSWORD_DIALOG
+#define WINVNCCONF_PASSWORD_DIALOG
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class PasswordDialog : public Dialog {
+    public:
+      PasswordDialog(const RegKey& rk, bool registryInsecure_);
+      bool showDialog(HWND owner=0);
+      bool onOk();
+    protected:
+      const RegKey& regKey;
+      bool registryInsecure;
+    };
+
+  };
+};
+
+#endif
\ No newline at end of file
diff --git a/win/vncconfig/Sharing.h b/win/vncconfig/Sharing.h
new file mode 100644 (file)
index 0000000..872ae13
--- /dev/null
@@ -0,0 +1,59 @@
+/* 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 WINVNCCONF_SHARING
+#define WINVNCCONF_SHARING
+
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb/ServerCore.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class SharingPage : public PropSheetPage {
+    public:
+      SharingPage(const RegKey& rk)
+        : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_SHARING)), regKey(rk) {}
+      void initDialog() {
+        setItemChecked(IDC_DISCONNECT_CLIENTS, rfb::Server::disconnectClients);
+        setItemChecked(IDC_SHARE_NEVER, rfb::Server::neverShared);
+        setItemChecked(IDC_SHARE_ALWAYS, rfb::Server::alwaysShared);
+        setItemChecked(IDC_SHARE_CLIENT, !(rfb::Server::neverShared || rfb::Server::alwaysShared));
+      }
+      bool onCommand(int id, int cmd) {
+        setChanged((isItemChecked(IDC_DISCONNECT_CLIENTS) != rfb::Server::disconnectClients) ||
+          (isItemChecked(IDC_SHARE_NEVER) != rfb::Server::neverShared) ||
+          (isItemChecked(IDC_SHARE_ALWAYS) != rfb::Server::alwaysShared));
+        return true;
+      }
+      bool onOk() {
+        regKey.setBool(_T("DisconnectClients"), isItemChecked(IDC_DISCONNECT_CLIENTS));
+        regKey.setBool(_T("AlwaysShared"), isItemChecked(IDC_SHARE_ALWAYS));
+        regKey.setBool(_T("NeverShared"), isItemChecked(IDC_SHARE_NEVER));
+       return true;
+      }
+    protected:
+      RegKey regKey;
+    };
+
+  };
+
+};
+
+#endif
diff --git a/win/vncconfig/resource.h b/win/vncconfig/resource.h
new file mode 100644 (file)
index 0000000..ca1fbf5
--- /dev/null
@@ -0,0 +1,102 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by vncconfig.rc
+//
+#define IDR_MANIFEST                    1
+#define IDI_ICON                        101
+#define IDD_DIALOG1                     102
+#define IDD_DIALOG2                     103
+#define IDD_SECURITY                    104
+#define IDD_AUTHENTICATION              104
+#define IDD_CONNECTIONS                 105
+#define IDD_HOOKING                     106
+#define IDD_VNC_PASSWD                  107
+#define IDD_AUTH_VNC_PASSWD             107
+#define IDD_LEGACY                      108
+#define IDD_CONN_HOST                   109
+#define IDD_SHARING                     110
+#define IDD_INPUTS                      111
+#define IDR_TRAY                        112
+#define IDD_ABOUT                       113
+#define IDI_CONNECTED                   115
+#define IDD_DESKTOP                     116
+#define IDC_EDIT1                       1000
+#define IDC_PORT                        1000
+#define IDC_PASSWORD1                   1000
+#define IDC_HOST_PATTERN                1000
+#define IDC_AUTH_NONE                   1002
+#define IDC_AUTH_VNC                    1003
+#define IDC_AUTH_VNC_PASSWD             1009
+#define IDC_USEHOOKS                    1011
+#define IDC_POLLCONSOLES                1012
+#define IDC_COMPAREFB                   1013
+#define IDC_IDLE_TIMEOUT                1015
+#define IDC_HOSTS                       1016
+#define IDC_HOST_ADD                    1017
+#define IDC_HOST_REMOVE                 1018
+#define IDC_HOST_UP                     1019
+#define IDC_BUTTON4                     1020
+#define IDC_HOST_DOWN                   1020
+#define IDC_AUTH_INPUTONLY_PASSWD       1020
+#define IDC_HOST_EDIT                   1021
+#define IDC_PASSWORD2                   1022
+#define IDC_LEGACY_IMPORT               1023
+#define IDC_ALLOW                       1024
+#define IDC_DENY                        1025
+#define IDC_SHARE_ALWAYS                1030
+#define IDC_SHARE_NEVER                 1031
+#define IDC_SHARE_CLIENT                1032
+#define IDC_DISCONNECT_CLIENTS          1033
+#define IDC_ACCEPT_KEYS                 1034
+#define IDC_ACCEPT_PTR                  1035
+#define IDC_ACCEPT_CUTTEXT              1036
+#define IDC_SEND_CUTTEXT                1037
+#define IDC_PROTOCOL_3_3                1038
+#define IDC_DESCRIPTION                 1039
+#define IDC_BUILDTIME                   1040
+#define IDC_VERSION                     1041
+#define IDC_COPYRIGHT                   1042
+#define IDC_HTTP_ENABLE                 1043
+#define IDC_HTTP_PORT                   1044
+#define IDC_BL_THRESHOLD                1046
+#define IDC_BL_TIMEOUT                  1047
+#define IDC_AFFECT_SCREENSAVER          1048
+#define IDC_LOCALHOST                   1049
+#define IDC_DISABLE_LOCAL_INPUTS        1050
+#define IDC_AUTH_NT                     1051
+#define IDC_AUTH_NT_CONF                1052
+#define IDC_AUTH_RA2_CONF               1053
+#define IDC_QUERY_CONNECT               1055
+#define IDC_DISCONNECT_NONE             1056
+#define IDC_DISCONNECT_LOCK             1057
+#define IDC_DISCONNECT_LOGOFF           1058
+#define IDC_REMOVE_WALLPAPER            1059
+#define IDC_REMOVE_PATTERN              1060
+#define IDC_DISABLE_EFFECTS             1061
+#define IDC_CAPTUREBLT                  1062
+#define IDC_ENCRYPTION                  1063
+#define IDC_QUERY                       1064
+#define IDC_USEPOLLING                  1066
+#define IDC_USEDRIVER                   1068
+#define IDC_QUERY_LOGGED_ON             1069
+#define IDC_AUTH_ADMIN_PASSWD           1076
+#define IDC_AUTH_VIEWONLY_PASSWD        1077
+#define IDC_AUTH_ADMIN_ENABLE           1078
+#define IDC_AUTH_VIEWONLY_ENABLE        1079
+#define IDC_AUTH_INPUTONLY_ENABLE       1080
+#define IDC_AUTH_VNC_EXT                1081
+#define IDC_RFB_ENABLE                  1082
+#define ID_OPTIONS                      40001
+#define ID_CLOSE                        40002
+#define ID_ABOUT                        40003
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        117
+#define _APS_NEXT_COMMAND_VALUE         40004
+#define _APS_NEXT_CONTROL_VALUE         1083
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/win/vncconfig/vncconfig.cxx b/win/vncconfig/vncconfig.cxx
new file mode 100644 (file)
index 0000000..6c9e1c5
--- /dev/null
@@ -0,0 +1,191 @@
+/* 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 <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+#include "resource.h"
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/RegConfig.h>
+#include <rfb_win32/CurrentUser.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("main");
+
+
+#include <vncconfig/Authentication.h>
+#include <vncconfig/Connections.h>
+#include <vncconfig/Sharing.h>
+#include <vncconfig/Hooking.h>
+#include <vncconfig/Inputs.h>
+#include <vncconfig/Legacy.h>
+#include <vncconfig/Desktop.h>
+
+
+TStr rfb::win32::AppName("VNC Config");
+
+
+#ifdef _DEBUG
+BoolParameter captureDialogs("CaptureDialogs", "", false);
+#endif
+
+HKEY configKey = HKEY_CURRENT_USER;
+
+
+void
+processParams(int argc, char* argv[]) {
+  for (int i=1; i<argc; i++) {
+    if (strcasecmp(argv[i], "-service") == 0) {
+      configKey = HKEY_LOCAL_MACHINE;
+    } else if (strcasecmp(argv[i], "-user") == 0) {
+      configKey = HKEY_CURRENT_USER;
+    } 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;
+        }
+      }
+    }
+  }
+}
+
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, char* cmdLine, int cmdShow) {
+
+  // Configure debugging output
+#ifdef _DEBUG
+  AllocConsole();
+  freopen("CONIN$","rb",stdin);
+  freopen("CONOUT$","wb",stdout);
+  freopen("CONOUT$","wb",stderr);
+  setbuf(stderr, 0);
+  initStdIOLoggers();
+  LogWriter vlog("main");
+  logParams.setParam("*:stderr:100");
+  vlog.info("Starting vncconfig applet");
+#endif
+
+  try {
+    try {
+      // Process command-line args
+      int argc = __argc;
+      char** argv = __argv;
+      processParams(argc, argv);
+
+      /* *** Required if we wish to use IP address control
+      INITCOMMONCONTROLSEX icce;
+      icce.dwSize = sizeof(icce);
+      icce.dwICC = ICC_INTERNET_CLASSES;
+      InitCommonControlsEx(&icce);
+      */
+
+      // Create the required configuration registry key
+      RegKey rootKey;
+      rootKey.createKey(configKey, _T("Software\\TightVNC\\WinVNC4"));
+  
+      // Override whatever security it already had (NT only)
+      bool warnOnChangePassword = false;
+      try {
+        AccessEntries access;
+        Sid::Administrators adminSID;
+        Sid::SYSTEM systemSID;
+        access.addEntry(adminSID, KEY_ALL_ACCESS, GRANT_ACCESS);
+        access.addEntry(systemSID, KEY_ALL_ACCESS, GRANT_ACCESS);
+        UserSID userSID;
+        if (configKey == HKEY_CURRENT_USER)
+          access.addEntry(userSID, KEY_ALL_ACCESS, GRANT_ACCESS);
+        AccessControlList acl(CreateACL(access));
+
+        // Set the DACL, and don't allow the key to inherit its parent's DACL
+        rootKey.setDACL(acl, false);
+      } catch (rdr::SystemException& e) {
+        // Something weird happens on NT 4.0 SP5 but I can't reproduce it on other
+        // NT 4.0 service pack revisions.
+        if (e.err == ERROR_INVALID_PARAMETER) {
+          MsgBox(0, _T("Windows reported an error trying to secure the VNC Server settings for this user.  ")
+                    _T("Your settings may not be secure!"), MB_ICONWARNING | MB_OK);
+        } else if (e.err != ERROR_CALL_NOT_IMPLEMENTED &&
+                   e.err != ERROR_NOT_LOGGED_ON) {
+          // If the call is not implemented, ignore the error and continue
+          // If we are on Win9x and no user is logged on, ignore error and continue
+          throw;
+        }
+        warnOnChangePassword = true;
+      }
+
+      // Start a RegConfig thread, to load in existing settings
+      RegConfigThread config;
+      config.start(configKey, _T("Software\\TightVNC\\WinVNC4"));
+
+      // Build the dialog
+      std::list<PropSheetPage*> pages;
+      AuthenticationPage auth(rootKey); pages.push_back(&auth);
+      auth.setWarnPasswdInsecure(warnOnChangePassword);
+      ConnectionsPage conn(rootKey); pages.push_back(&conn);
+      InputsPage inputs(rootKey); pages.push_back(&inputs);
+      SharingPage sharing(rootKey); pages.push_back(&sharing);
+      DesktopPage desktop(rootKey); pages.push_back(&desktop);
+      HookingPage hooks(rootKey); pages.push_back(&hooks);
+      LegacyPage legacy(rootKey, configKey == HKEY_CURRENT_USER); pages.push_back(&legacy);
+
+      // Load the default icon to use
+      HICON icon = (HICON)LoadImage(inst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+
+      // Create the PropertySheet handler
+      TCHAR* propSheetTitle = _T("VNC Server Properties (Service-Mode)");
+      if (configKey == HKEY_CURRENT_USER)
+        propSheetTitle = _T("VNC Server Properties (User-Mode)");
+      PropSheet sheet(inst, propSheetTitle, pages, icon);
+
+#ifdef _DEBUG
+      vlog.debug("capture dialogs=%s", captureDialogs ? "true" : "false");
+      sheet.showPropSheet(0, true, false, captureDialogs);
+#else
+      sheet.showPropSheet(0, true, false);
+#endif
+    } catch (rdr::SystemException& e) {
+      switch (e.err) {
+      case ERROR_ACCESS_DENIED:
+        MsgBox(0, _T("You do not have sufficient access rights to run the VNC Configuration applet"),
+               MB_ICONSTOP | MB_OK);
+        return 1;
+      };
+      throw;
+    }
+
+  } catch (rdr::Exception& e) {
+    MsgBox(NULL, TStr(e.str()), MB_ICONEXCLAMATION | MB_OK);
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/win/vncconfig/vncconfig.dsp b/win/vncconfig/vncconfig.dsp
new file mode 100644 (file)
index 0000000..b096ded
--- /dev/null
@@ -0,0 +1,196 @@
+# Microsoft Developer Studio Project File - Name="vncconfig" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+CFG=vncconfig - Win32 Debug Unicode\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "vncconfig.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "vncconfig.mak" CFG="vncconfig - Win32 Debug Unicode"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "vncconfig - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "vncconfig - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE "vncconfig - Win32 Debug Unicode" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "vncconfig - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release"\r
+# PROP Intermediate_Dir "..\Release\vncconfig"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c\r
+# 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\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386\r
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib version.lib shell32.lib comctl32.lib ws2_32.lib ole32.lib /nologo /subsystem:windows /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "vncconfig - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "vncconfig___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "vncconfig___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug"\r
+# PROP Intermediate_Dir "..\Debug\vncconfig"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib version.lib shell32.lib comctl32.lib ws2_32.lib ole32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "vncconfig - Win32 Debug Unicode"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "vncconfig___Win32_Debug_Unicode"\r
+# PROP BASE Intermediate_Dir "vncconfig___Win32_Debug_Unicode"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug_Unicode"\r
+# PROP Intermediate_Dir "..\Debug_Unicode\vncconfig"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".." /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# 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" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib version.lib shell32.lib comctl32.lib ws2_32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib version.lib shell32.lib comctl32.lib ws2_32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "vncconfig - Win32 Release"\r
+# Name "vncconfig - Win32 Debug"\r
+# Name "vncconfig - Win32 Debug Unicode"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\Legacy.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PasswordDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncconfig.cxx\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\Authentication.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Connections.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Desktop.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Hooking.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Inputs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Legacy.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\PasswordDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\resource.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Sharing.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# Begin Source File\r
+\r
+SOURCE=.\connected.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncconfig.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncconfig.rc\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=.\vncconfig.exe.manifest\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/win/vncconfig/vncconfig.exe.manifest b/win/vncconfig/vncconfig.exe.manifest
new file mode 100644 (file)
index 0000000..77cb1b9
--- /dev/null
@@ -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.vncconfig.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/vncconfig/vncconfig.ico b/win/vncconfig/vncconfig.ico
new file mode 100644 (file)
index 0000000..1b42416
Binary files /dev/null and b/win/vncconfig/vncconfig.ico differ
diff --git a/win/vncconfig/vncconfig.rc b/win/vncconfig/vncconfig.rc
new file mode 100644 (file)
index 0000000..bf2f969
--- /dev/null
@@ -0,0 +1,496 @@
+//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     "vncconfig.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_AUTHENTICATION DIALOG DISCARDABLE  0, 0, 193, 135
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Authentication"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "No Authentication",IDC_AUTH_NONE,"Button",
+                    BS_AUTORADIOBUTTON | WS_GROUP,7,10,113,15
+    CONTROL         "VNC Password Authentication",IDC_AUTH_VNC,"Button",
+                    BS_AUTORADIOBUTTON,7,30,113,15
+    PUSHBUTTON      "Configure",IDC_AUTH_VNC_PASSWD,125,30,61,15
+    CONTROL         "NT Logon Authentication",IDC_AUTH_NT,"Button",
+                    BS_AUTORADIOBUTTON,7,50,113,15
+    PUSHBUTTON      "Configure",IDC_AUTH_NT_CONF,125,50,61,15
+    LTEXT           "Encryption:",IDC_STATIC,7,70,42,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_ENCRYPTION,49,70,71,50,CBS_DROPDOWN | WS_VSCROLL | 
+                    WS_TABSTOP
+    PUSHBUTTON      "Generate Keys",IDC_AUTH_RA2_CONF,125,70,61,15
+    CONTROL         "Prompt local user to accept connections",
+                    IDC_QUERY_CONNECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    7,95,181,15
+    CONTROL         "Only prompt when there is a user logged on",
+                    IDC_QUERY_LOGGED_ON,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,20,110,166,15
+END
+
+IDD_CONNECTIONS DIALOG DISCARDABLE  0, 0, 218, 198
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Connections"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Accept connections on port:",IDC_RFB_ENABLE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,10,138,15
+    EDITTEXT        IDC_PORT,150,10,61,15,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "Disconnect idle clients after (seconds):",IDC_STATIC,7,
+                    25,138,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_IDLE_TIMEOUT,150,25,61,15,ES_AUTOHSCROLL | ES_NUMBER
+    CONTROL         "Serve Java viewer via HTTP on port:",IDC_HTTP_ENABLE,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,138,15
+    EDITTEXT        IDC_HTTP_PORT,150,40,61,15,ES_AUTOHSCROLL | ES_NUMBER
+    GROUPBOX        "Access Control",IDC_STATIC,7,55,204,135
+    CONTROL         "Only accept connections from the local machine",
+                    IDC_LOCALHOST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,
+                    70,190,15
+    LISTBOX         IDC_HOSTS,15,90,130,95,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | 
+                    WS_TABSTOP
+    PUSHBUTTON      "&Add",IDC_HOST_ADD,150,90,55,15
+    PUSHBUTTON      "&Remove",IDC_HOST_REMOVE,150,110,55,15
+    PUSHBUTTON      "Move Up",IDC_HOST_UP,150,130,55,15
+    PUSHBUTTON      "Move Down",IDC_HOST_DOWN,150,150,55,15
+    PUSHBUTTON      "&Edit",IDC_HOST_EDIT,150,170,55,15
+END
+
+IDD_HOOKING DIALOG DISCARDABLE  0, 0, 197, 101
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Capture Method"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Poll for changes to the desktop",IDC_USEPOLLING,"Button",
+                    BS_AUTORADIOBUTTON | WS_GROUP,7,10,183,15
+    CONTROL         "Use VNC hooks to track changes",IDC_USEHOOKS,"Button",
+                    BS_AUTORADIOBUTTON,7,25,183,15
+    CONTROL         "Poll console windows for updates",IDC_POLLCONSOLES,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,40,165,15
+    CONTROL         "Use VNC Mirror driver to track changes",IDC_USEDRIVER,
+                    "Button",BS_AUTORADIOBUTTON,7,55,183,15
+    CONTROL         "Capture alpha-blended windows",IDC_CAPTUREBLT,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,70,183,15
+END
+
+IDD_AUTH_VNC_PASSWD DIALOG DISCARDABLE  0, 0, 212, 70
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "VNC Server Password"
+FONT 8, "MS Sans Serif"
+BEGIN
+    LTEXT           "New Password:",IDC_STATIC,7,10,63,15
+    EDITTEXT        IDC_PASSWORD1,75,10,130,15,ES_PASSWORD | ES_AUTOHSCROLL
+    LTEXT           "Confirm Password:",IDC_STATIC,7,30,63,14
+    EDITTEXT        IDC_PASSWORD2,75,30,130,14,ES_PASSWORD | ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "OK",IDOK,100,50,50,15
+    PUSHBUTTON      "Cancel",IDCANCEL,155,50,50,15
+END
+
+IDD_LEGACY DIALOG DISCARDABLE  0, 0, 166, 92
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Legacy"
+FONT 8, "MS Sans Serif"
+BEGIN
+    PUSHBUTTON      "&Import VNC 3.3 Settings",IDC_LEGACY_IMPORT,7,10,92,20
+    CONTROL         "Only use protocol version 3.3",IDC_PROTOCOL_3_3,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,35,152,15
+END
+
+IDD_CONN_HOST DIALOG DISCARDABLE  0, 0, 225, 57
+STYLE DS_SYSMODAL | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION
+CAPTION "Specify Host IP Address Pattern"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_HOST_PATTERN,65,5,100,15,ES_AUTOHSCROLL
+    CONTROL         "&Allow",IDC_ALLOW,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP,7,5,53,15
+    CONTROL         "&Deny",IDC_DENY,"Button",BS_AUTORADIOBUTTON,7,20,53,15
+    CONTROL         "Query",IDC_QUERY,"Button",BS_AUTORADIOBUTTON,7,35,53,15
+    DEFPUSHBUTTON   "OK",IDOK,115,35,50,15
+    PUSHBUTTON      "Cancel",IDCANCEL,170,35,50,15
+    LTEXT           "e.g. 192.168.0.0/255.255.0.0",IDC_STATIC,65,20,100,15
+END
+
+IDD_SHARING DIALOG DISCARDABLE  0, 0, 186, 95
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Sharing"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Always treat new connections as shared",
+                    IDC_SHARE_ALWAYS,"Button",BS_AUTORADIOBUTTON | WS_GROUP,
+                    7,10,172,15
+    CONTROL         "Never treat new connections as shared",IDC_SHARE_NEVER,
+                    "Button",BS_AUTORADIOBUTTON,7,25,172,15
+    CONTROL         "Use client's preferred sharing setting",
+                    IDC_SHARE_CLIENT,"Button",BS_AUTORADIOBUTTON,7,40,172,15
+    CONTROL         "Non-shared connections replace existing ones",
+                    IDC_DISCONNECT_CLIENTS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,7,55,172,15
+END
+
+IDD_INPUTS DIALOG DISCARDABLE  0, 0, 186, 119
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Inputs"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Accept pointer events from clients",IDC_ACCEPT_PTR,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,10,172,15
+    CONTROL         "Accept keyboard events from clients",IDC_ACCEPT_KEYS,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,25,172,15
+    CONTROL         "Accept clipboard updates from clients",
+                    IDC_ACCEPT_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    7,40,172,15
+    CONTROL         "Send clipboard updates to clients",IDC_SEND_CUTTEXT,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,172,15
+    CONTROL         "Allow input events to affect the screen-saver",
+                    IDC_AFFECT_SCREENSAVER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,7,70,172,15
+    CONTROL         "Disable local inputs while server is in use",
+                    IDC_DISABLE_LOCAL_INPUTS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,7,95,172,15
+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 Config for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,195,70,47,15
+    ICON            IDI_ICON,IDC_STATIC,7,7,20,20
+    LTEXT           ">appname<",IDC_DESCRIPTION,40,7,125,18
+    LTEXT           ">version<",IDC_VERSION,165,7,77,18
+    LTEXT           ">buildtime<",IDC_BUILDTIME,40,25,202,15
+    LTEXT           ">copyright<",IDC_COPYRIGHT,40,40,202,15
+    LTEXT           "See http://www.tightvnc.com for more information on TightVNC.",
+                    IDC_STATIC,40,55,202,15
+END
+
+IDD_DESKTOP DIALOG DISCARDABLE  0, 0, 185, 137
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CONTROL | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "Desktop"
+FONT 8, "MS Sans Serif"
+BEGIN
+    GROUPBOX        "While connected",IDC_STATIC,7,5,171,60
+    CONTROL         "Remove wallpaper",IDC_REMOVE_WALLPAPER,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,15,155,15
+    CONTROL         "Remove background pattern",IDC_REMOVE_PATTERN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,15,30,155,15
+    CONTROL         "Disable user interface effects",IDC_DISABLE_EFFECTS,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,46,155,14
+    GROUPBOX        "When last client disconnects",IDC_STATIC,7,70,171,60
+    CONTROL         "Do nothing",IDC_DISCONNECT_NONE,"Button",
+                    BS_AUTORADIOBUTTON,15,80,155,15
+    CONTROL         "Lock workstation",IDC_DISCONNECT_LOCK,"Button",
+                    BS_AUTORADIOBUTTON,15,95,155,15
+    CONTROL         "Logoff user",IDC_DISCONNECT_LOGOFF,"Button",
+                    BS_AUTORADIOBUTTON,15,110,155,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_AUTHENTICATION, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 186
+        VERTGUIDE, 20
+        VERTGUIDE, 49
+        VERTGUIDE, 120
+        VERTGUIDE, 125
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 128
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 30
+        HORZGUIDE, 45
+        HORZGUIDE, 50
+        HORZGUIDE, 65
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+        HORZGUIDE, 90
+        HORZGUIDE, 105
+        HORZGUIDE, 110
+        HORZGUIDE, 125
+    END
+
+    IDD_CONNECTIONS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 211
+        VERTGUIDE, 15
+        VERTGUIDE, 145
+        VERTGUIDE, 150
+        VERTGUIDE, 205
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 191
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+        HORZGUIDE, 90
+        HORZGUIDE, 105
+        HORZGUIDE, 110
+        HORZGUIDE, 125
+        HORZGUIDE, 130
+        HORZGUIDE, 145
+        HORZGUIDE, 150
+        HORZGUIDE, 165
+        HORZGUIDE, 170
+        HORZGUIDE, 185
+        HORZGUIDE, 190
+    END
+
+    IDD_HOOKING, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 190
+        VERTGUIDE, 25
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 94
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+    END
+
+    IDD_AUTH_VNC_PASSWD, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 205
+        VERTGUIDE, 70
+        VERTGUIDE, 75
+        VERTGUIDE, 90
+        VERTGUIDE, 100
+        VERTGUIDE, 150
+        VERTGUIDE, 155
+        VERTGUIDE, 205
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 65
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 30
+        HORZGUIDE, 44
+        HORZGUIDE, 50
+        HORZGUIDE, 65
+    END
+
+    IDD_LEGACY, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 159
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 85
+        HORZGUIDE, 10
+        HORZGUIDE, 30
+        HORZGUIDE, 35
+        HORZGUIDE, 50
+    END
+
+    IDD_CONN_HOST, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 220
+        VERTGUIDE, 60
+        VERTGUIDE, 65
+        VERTGUIDE, 115
+        VERTGUIDE, 165
+        VERTGUIDE, 170
+        TOPMARGIN, 5
+        BOTTOMMARGIN, 50
+        HORZGUIDE, 20
+        HORZGUIDE, 35
+    END
+
+    IDD_SHARING, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 179
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 88
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+    END
+
+    IDD_INPUTS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 179
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 112
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+        HORZGUIDE, 85
+        HORZGUIDE, 95
+        HORZGUIDE, 110
+    END
+
+    IDD_ABOUT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 242
+        VERTGUIDE, 40
+        VERTGUIDE, 165
+        VERTGUIDE, 195
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 85
+        HORZGUIDE, 7
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+    END
+
+    IDD_DESKTOP, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 182
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 32
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+#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 Server Configuration Applet for Win32\0"
+            VALUE "FileVersion", "4.1.1\0"
+            VALUE "InternalName", "vncconfig\0"
+            VALUE "LegalCopyright", "Copyright (C) 1998-2005 [many holders]\0"
+            VALUE "LegalTrademarks", "TightVNC\0"
+            VALUE "OriginalFilename", "vncconfig.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "TightVNC Configurator\0"
+            VALUE "ProductVersion", "4.1.1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x809, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 24
+//
+
+IDR_MANIFEST            24      DISCARDABLE     "vncconfig.exe.manifest"
+#endif    // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/win/vncviewer/CConn.cxx b/win/vncviewer/CConn.cxx
new file mode 100644 (file)
index 0000000..73597f5
--- /dev/null
@@ -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 (file)
index 0000000..29023f3
--- /dev/null
@@ -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 (file)
index 0000000..4ea0ada
--- /dev/null
@@ -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 (file)
index 0000000..59fd0a3
--- /dev/null
@@ -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 (file)
index 0000000..cfd2695
--- /dev/null
@@ -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 (file)
index 0000000..7a8451c
--- /dev/null
@@ -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 (file)
index 0000000..60fcb66
--- /dev/null
@@ -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 (file)
index 0000000..c38b3a1
--- /dev/null
@@ -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 (file)
index 0000000..e7c6b0a
--- /dev/null
@@ -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 (file)
index 0000000..f739280
--- /dev/null
@@ -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 (file)
index 0000000..27ef2dc
--- /dev/null
@@ -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 (file)
index 0000000..3d2211f
--- /dev/null
@@ -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 (file)
index 0000000..1b6dfb6
--- /dev/null
@@ -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 (file)
index 0000000..5c9ba35
--- /dev/null
@@ -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 (file)
index 0000000..5f71f7d
--- /dev/null
@@ -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 (file)
index 0000000..a4b5546
--- /dev/null
@@ -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 (file)
index 0000000..8f41abf
--- /dev/null
@@ -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 (file)
index 0000000..c920fa0
--- /dev/null
@@ -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 (file)
index 0000000..e6cc952
--- /dev/null
@@ -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 (file)
index 0000000..caad779
--- /dev/null
@@ -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 (file)
index 0000000..cf57072
--- /dev/null
@@ -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 (file)
index 0000000..1bfded2
--- /dev/null
@@ -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 (file)
index 0000000..e74896d
--- /dev/null
@@ -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 (file)
index 0000000..752d53c
--- /dev/null
@@ -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 (file)
index 0000000..4d1590c
--- /dev/null
@@ -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 (file)
index 0000000..7e334d9
--- /dev/null
@@ -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 (file)
index 0000000..ae703b3
--- /dev/null
@@ -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 (file)
index 0000000..2e43b38
--- /dev/null
@@ -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 (file)
index 0000000..fcddc71
--- /dev/null
@@ -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 (file)
index 0000000..2eea0ea
--- /dev/null
@@ -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 (file)
index 0000000..bf006f4
--- /dev/null
@@ -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 (file)
index 0000000..29b8030
--- /dev/null
@@ -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 (file)
index 0000000..30e7708
--- /dev/null
@@ -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 (file)
index 0000000..9f37b38
--- /dev/null
@@ -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 (file)
index 0000000..20a713f
Binary files /dev/null and b/win/vncviewer/cursor1.cur differ
diff --git a/win/vncviewer/ftdir.ico b/win/vncviewer/ftdir.ico
new file mode 100644 (file)
index 0000000..7a7f741
Binary files /dev/null and b/win/vncviewer/ftdir.ico differ
diff --git a/win/vncviewer/ftfile.ico b/win/vncviewer/ftfile.ico
new file mode 100644 (file)
index 0000000..a8084b8
Binary files /dev/null and b/win/vncviewer/ftfile.ico differ
diff --git a/win/vncviewer/ftreload.ico b/win/vncviewer/ftreload.ico
new file mode 100644 (file)
index 0000000..34383e9
Binary files /dev/null and b/win/vncviewer/ftreload.ico differ
diff --git a/win/vncviewer/ftup.ico b/win/vncviewer/ftup.ico
new file mode 100644 (file)
index 0000000..fc215ad
Binary files /dev/null and b/win/vncviewer/ftup.ico differ
diff --git a/win/vncviewer/resource.h b/win/vncviewer/resource.h
new file mode 100644 (file)
index 0000000..5493fd0
--- /dev/null
@@ -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 (file)
index 0000000..0a14636
Binary files /dev/null and b/win/vncviewer/toolbar.bmp differ
diff --git a/win/vncviewer/vncviewer.bmp b/win/vncviewer/vncviewer.bmp
new file mode 100644 (file)
index 0000000..4ea9c37
Binary files /dev/null and b/win/vncviewer/vncviewer.bmp differ
diff --git a/win/vncviewer/vncviewer.cxx b/win/vncviewer/vncviewer.cxx
new file mode 100644 (file)
index 0000000..3a5214a
--- /dev/null
@@ -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 (file)
index 0000000..e245cd6
--- /dev/null
@@ -0,0 +1,321 @@
+# Microsoft Developer Studio Project File - Name="vncviewer" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+CFG=vncviewer - Win32 Debug Unicode\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "vncviewer.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "vncviewer.mak" CFG="vncviewer - Win32 Debug Unicode"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "vncviewer - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "vncviewer - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE "vncviewer - Win32 Debug Unicode" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "vncviewer - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release"\r
+# PROP Intermediate_Dir "..\Release\vncviewer"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c\r
+# 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\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /machine:I386\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Desc=Updating buildTime\r
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\vncviewer /MT buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "vncviewer - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug"\r
+# PROP Intermediate_Dir "..\Debug\vncviewer"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c\r
+# 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\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# 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\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Desc=Updating buildTime\r
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\vncviewer /MTd buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "vncviewer - Win32 Debug Unicode"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "vncviewer___Win32_Debug_Unicode"\r
+# PROP BASE Intermediate_Dir "vncviewer___Win32_Debug_Unicode"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug_Unicode"\r
+# PROP Intermediate_Dir "..\Debug_Unicode\vncviewer"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# 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\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# 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\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Desc=Updating buildTime\r
+PreLink_Cmds=cl /c /nologo /Fo..\Debug_Unicode\ /Fd..\Debug_Unicode\vncviewer /MTd buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "vncviewer - Win32 Release"\r
+# Name "vncviewer - Win32 Debug"\r
+# Name "vncviewer - Win32 Debug Unicode"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\buildTime.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConn.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnOptions.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnThread.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ConnectingDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ConnectionDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DesktopWindow.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FileTransfer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTBrowseDlg.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTListView.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTProgress.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\InfoDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\OptionsDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\UserPasswdDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ViewerToolBar.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncviewer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncviewer.rc\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\CConn.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnOptions.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnThread.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ConnectingDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ConnectionDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\DesktopWindow.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FileTransfer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTBrowseDlg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTListView.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\FTProgress.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\InfoDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ListenServer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ListenTrayIcon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\MRU.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\OptionsDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\UserPasswdDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ViewerToolBar.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# Begin Source File\r
+\r
+SOURCE=.\cursor1.cur\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ftdir.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ftfile.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ftreload.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ftup.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\toolbar.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncviewer.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncviewer.exe.manifest\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\vncviewer.ico\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/vncviewer/vncviewer.exe.manifest b/win/vncviewer/vncviewer.exe.manifest
new file mode 100644 (file)
index 0000000..7fd947f
--- /dev/null
@@ -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 (file)
index 0000000..6572661
Binary files /dev/null and b/win/vncviewer/vncviewer.ico differ
diff --git a/win/vncviewer/vncviewer.rc b/win/vncviewer/vncviewer.rc
new file mode 100644 (file)
index 0000000..ea5dd65
--- /dev/null
@@ -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
+
diff --git a/win/winvnc/AddNewClientDialog.h b/win/winvnc/AddNewClientDialog.h
new file mode 100644 (file)
index 0000000..9bf5135
--- /dev/null
@@ -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.
+ */
+
+// -=- AddnewClientDialog.h
+
+#ifndef __WINVNC_ADD_NEW_CLIENT_DIALOG_H__
+#define __WINVNC_ADD_NEW_CLIENT_DIALOG_H__
+
+#include <winvnc/resource.h>
+#include <rfb_win32/Dialog.h>
+//#include <rfb_win32/TCharArray.h>
+
+namespace winvnc {
+
+  class AddNewClientDialog : public rfb::win32::Dialog {
+  public:
+    AddNewClientDialog() : Dialog(GetModuleHandle(0)) {}
+    // - Show the dialog and return true if OK was clicked,
+    //   false in case of error or Cancel
+    virtual bool showDialog() {
+      return Dialog::showDialog(MAKEINTRESOURCE(IDD_ADD_NEW_CLIENT));
+    }
+    const char* getHostName() const {return hostName.buf;}
+  protected:
+
+    // Dialog methods (protected)
+    virtual void initDialog() {
+      if (hostName.buf)
+        setItemString(IDC_HOST, rfb::TStr(hostName.buf));
+    }
+    virtual bool onOk() {
+      hostName.replaceBuf(rfb::strDup(rfb::CStr(getItemString(IDC_HOST))));
+      return true;
+    }
+
+    rfb::CharArray hostName;
+  };
+
+};
+
+#endif
diff --git a/win/winvnc/ControlPanel.cxx b/win/winvnc/ControlPanel.cxx
new file mode 100644 (file)
index 0000000..7428230
--- /dev/null
@@ -0,0 +1,161 @@
+// ControlPanel.cxx: implementation of the ControlPanel class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "ControlPanel.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+using namespace winvnc;
+
+bool ControlPanel::showDialog()
+{
+  return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONTROL_PANEL), NULL);
+}
+
+void ControlPanel::initDialog()
+{
+  TCHAR *ColumnsStrings[] = {
+    "IP address",
+    "Time connected",
+    "Status"
+  };
+  InitLVColumns(IDC_LIST_CONNECTIONS, handle, 120, 3, ColumnsStrings,
+                LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,
+                LVS_EX_FULLROWSELECT, LVCFMT_LEFT);
+  SendCommand(4, -1);
+}
+
+bool ControlPanel::onCommand(int cmd)
+{
+  switch (cmd) {
+  case IDC_PROPERTIES:
+    SendMessage(m_hSTIcon, WM_COMMAND, ID_OPTIONS, 0);
+    return false;
+  case IDC_ADD_CLIENT:
+    SendMessage(m_hSTIcon, WM_COMMAND, ID_CONNECT, 0);
+    return false;
+  case IDC_KILL_ALL:
+    {
+      SendCommand(2, -1);
+      return false;
+    }
+  case IDC_KILL_SEL_CLIENT:
+    {     
+      SendCommand(3, 3);
+      return false;
+    }
+  case IDC_VIEW_ONLY:
+    {     
+      SendCommand(3, 1);
+      return false;
+    }
+  case IDC_FULL_CONTROL:
+    {     
+      SendCommand(3, 0);
+      return false;
+    }
+  case IDC_STOP_UPDATE:
+    {     
+      stop_updating = true;
+      EndDialog(handle, 0);
+      return false;
+    }
+  case IDC_DISABLE_CLIENTS:
+    {   
+      ListConnStatus.setDisable(isItemChecked(IDC_DISABLE_CLIENTS));
+      SendCommand(3, -1);
+      return false;
+    }
+  }
+  return false;
+  
+}
+
+void ControlPanel::UpdateListView(rfb::ListConnInfo* LCInfo)
+{
+  getSelConnInfo();
+  DeleteAllLVItem(IDC_LIST_CONNECTIONS, handle);
+  setItemChecked(IDC_DISABLE_CLIENTS, LCInfo->getDisable());
+
+  if(LCInfo->Empty()) 
+    return;
+
+  ListConn.Copy(LCInfo);
+
+  char* ItemString[3];
+  int i = 0;
+
+  for (ListConn.iBegin(); !ListConn.iEnd(); ListConn.iNext()) {
+    ListConn.iGetCharInfo(ItemString);
+    InsertLVItem(IDC_LIST_CONNECTIONS, handle, i, ItemString, 3);
+    for (ListSelConn.iBegin(); !ListSelConn.iEnd(); ListSelConn.iNext()) {
+      if (ListSelConn.iGetConn() == ListConn.iGetConn())
+        SelectLVItem(IDC_LIST_CONNECTIONS, handle, i);
+    }
+    i++;
+  } 
+}
+
+BOOL ControlPanel::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+  switch (msg) {
+  case WM_INITDIALOG:
+    handle = hwnd;
+    initDialog();
+    return TRUE;
+  case WM_DESTROY:
+    if (stop_updating) {
+      stop_updating = false;
+      SendCommand(3, 2);
+    }
+    return TRUE;
+  case WM_COMMAND:
+    switch (LOWORD(wParam)) {
+    case IDCANCEL:
+      handle = NULL;
+      EndDialog(hwnd, 0);
+      return TRUE;
+    default:
+      return onCommand(LOWORD(wParam));
+    }
+  }
+  return FALSE;
+}
+
+void ControlPanel::getSelConnInfo()
+{
+  int i = 0;
+  ListSelConn.Clear();
+  if(ListConn.Empty()) return;
+  for (ListConn.iBegin(); !ListConn.iEnd(); ListConn.iNext()) {
+    if (IsSelectedLVItem(IDC_LIST_CONNECTIONS, handle, i))
+      ListSelConn.iAdd(&ListConn);
+    i++;
+  }
+}
+
+void ControlPanel::SendCommand(DWORD command, int data)
+{
+  COPYDATASTRUCT copyData;
+  copyData.dwData = command;
+  copyData.lpData = 0;
+  getSelConnInfo();
+  if (data != -1) {
+    ListConnStatus.Copy(&ListSelConn);
+    ListConnStatus.setAllStatus(data);
+    ListConnStatus.setDisable(isItemChecked(IDC_DISABLE_CLIENTS));
+    copyData.cbData = (DWORD)&ListConnStatus;
+  } else {
+    ListConnStatus.Clear();
+  }
+  copyData.cbData = (DWORD)&ListConnStatus;
+  SendMessage(m_hSTIcon, WM_COPYDATA, 0, (LPARAM)&copyData);
+}
+
+ControlPanel::~ControlPanel()
+{
+  
+}
diff --git a/win/winvnc/ControlPanel.h b/win/winvnc/ControlPanel.h
new file mode 100644 (file)
index 0000000..73b859f
--- /dev/null
@@ -0,0 +1,45 @@
+// ControlPanel.h: interface for the ControlPanel class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef AFX_CONTROLPANEL_H__
+#define AFX_CONTROLPANEL_H__
+
+
+#pragma once
+
+
+#include <list>
+#include <winvnc/resource.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/ListViewControl.h>
+#include <rfb_win32/Win32Util.h>
+#include <rfb/ListConnInfo.h>
+
+namespace winvnc {
+  
+  class ControlPanel : rfb::win32::Dialog, rfb::win32::ListViewControl {
+  public:
+    ControlPanel(HWND hSTIcon) : Dialog(GetModuleHandle(0)), ListViewControl(){
+      m_hSTIcon = hSTIcon;
+      stop_updating = false;
+    };
+    virtual bool showDialog();
+    virtual void initDialog();
+    virtual bool onCommand(int cmd);
+    void UpdateListView(rfb::ListConnInfo* LCInfo);
+    HWND GetHandle() {return handle;};
+    void SendCommand(DWORD command, int data);
+    ~ControlPanel();
+    rfb::ListConnInfo ListConnStatus;
+  protected: 
+    virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+    void getSelConnInfo();
+    HWND m_hSTIcon;
+    rfb::ListConnInfo ListConn;
+    rfb::ListConnInfo ListSelConn;
+    bool stop_updating;
+  };
+};
+
+#endif  
\ No newline at end of file
diff --git a/win/winvnc/JavaViewer.cxx b/win/winvnc/JavaViewer.cxx
new file mode 100644 (file)
index 0000000..15c05c4
--- /dev/null
@@ -0,0 +1,98 @@
+/* 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 <winvnc/JavaViewer.h>
+#include <winvnc/resource.h>
+#include <rdr/MemInStream.h>
+#include <rfb/LogWriter.h>
+#include <rfb/VNCserverST.h>
+#include <rfb_win32/TCharArray.h>
+
+#define strcasecmp _stricmp
+
+using namespace winvnc;
+using namespace rfb;
+
+
+static rfb::LogWriter vlog("JavaViewerServer");
+
+JavaViewerServer::JavaViewerServer(rfb::VNCServerST* svr) : server(svr) {
+}
+
+JavaViewerServer::~JavaViewerServer() {
+}
+
+rdr::InStream* JavaViewerServer::getFile(const char* name,
+                                         const char** contentType,
+                                         int* contentLength,
+                                         time_t* lastModified)
+{
+  if (strcmp(name, "/") == 0)
+    name = "/index.vnc";
+
+  HRSRC resource = FindResource(0, TStr(name), _T("HTTPFILE"));
+  if (!resource) return 0;
+  HGLOBAL handle = LoadResource(0, resource);
+  if (!handle) return 0;
+  void* buf = LockResource(handle);
+  int len = SizeofResource(0, resource);
+
+  rdr::InStream* is = new rdr::MemInStream(buf, len);
+  if (strlen(name) > 4 && strcasecmp(&name[strlen(name)-4], ".vnc") == 0) {
+    is = new rdr::SubstitutingInStream(is, this, 20);
+    *contentType = "text/html";
+  }
+  return is;
+}
+
+char* JavaViewerServer::substitute(const char* varName)
+{
+  if (strcmp(varName, "$$") == 0) {
+    return rfb::strDup("$");
+  }
+  if (strcmp(varName, "$PORT") == 0) {
+    char* str = new char[10];
+    sprintf(str, "%d", rfbPort);
+    return str;
+  }
+  if (strcmp(varName, "$WIDTH") == 0) {
+    char* str = new char[10];
+    sprintf(str, "%d", server->getDesktopSize().x);
+    return str;
+  }
+  if (strcmp(varName, "$HEIGHT") == 0) {
+    char* str = new char[10];
+    sprintf(str, "%d", server->getDesktopSize().y);
+    return str;
+  }
+  if (strcmp(varName, "$APPLETWIDTH") == 0) {
+    char* str = new char[10];
+    sprintf(str, "%d", server->getDesktopSize().x);
+    return str;
+  }
+  if (strcmp(varName, "$APPLETHEIGHT") == 0) {
+    char* str = new char[10];
+    sprintf(str, "%d", server->getDesktopSize().y + 32);
+    return str;
+  }
+  if (strcmp(varName, "$DESKTOP") == 0) {
+    return rfb::strDup(server->getName());
+  }
+  return 0;
+}
diff --git a/win/winvnc/JavaViewer.h b/win/winvnc/JavaViewer.h
new file mode 100644 (file)
index 0000000..ecda4d3
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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.
+ */
+
+// -=- JavaViewer.h
+
+// Custom HTTPServer-derived class which serves the Java VNC Viewer
+// to clients, using resource files compiled in to the WinVNC executable.
+
+#ifndef WINVNC_JAVA_VIEWER
+#define WINVNC_JAVA_VIEWER
+
+#include <rfb/HTTPServer.h>
+#include <rfb/VNCServerST.h>
+#include <rdr/SubstitutingInStream.h>
+
+namespace winvnc {
+
+  class JavaViewerServer : public rfb::HTTPServer, public rdr::Substitutor {
+  public:
+    JavaViewerServer(rfb::VNCServerST* desktop);
+    virtual ~JavaViewerServer();
+
+    virtual rdr::InStream* getFile(const char* name, const char** contentType,
+                                   int* contentLength, time_t* lastModified);
+
+    // rdr::Substitutor callback
+    virtual char* substitute(const char* varName);
+
+    void setRFBport(int port) {
+      rfbPort = port;
+    }
+  protected:
+    int rfbPort;
+    rfb::VNCServerST* server;
+  };
+
+};
+
+#endif
+
diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
new file mode 100644 (file)
index 0000000..9bf1b9a
--- /dev/null
@@ -0,0 +1,94 @@
+/* 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.
+ */
+#include <winvnc/ManagedListener.h>
+#include <rfb/LogWriter.h>
+
+using namespace winvnc;
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("ManagedListener");
+
+
+ManagedListener::ManagedListener(SocketManager* mgr)
+: sock(0), filter(0), manager(mgr), addrChangeNotifier(0), server(0), port(0), localOnly(false) {
+}
+
+ManagedListener::~ManagedListener() {
+  if (sock)
+    manager->remListener(sock);
+  delete filter;
+}
+
+
+void ManagedListener::setServer(network::SocketServer* svr) {
+  if (svr == server)
+    return;
+  vlog.info("set server to %p", svr);
+  server = svr;
+  refresh();
+}
+
+void ManagedListener::setPort(int port_, bool localOnly_) {
+  if ((port_ == port) && (localOnly == localOnly_))
+    return;
+  vlog.info("set port to %d", port_);
+  port = port_;
+  localOnly = localOnly_;
+  refresh();
+}
+
+void ManagedListener::setFilter(const char* filterStr) {
+  vlog.info("set filter to %s", filterStr);
+  delete filter;
+  filter = new network::TcpFilter(filterStr);
+  if (sock && !localOnly)
+    sock->setFilter(filter);
+}
+
+void ManagedListener::setAddressChangeNotifier(SocketManager::AddressChangeNotifier* acn) {
+  if (acn == addrChangeNotifier)
+    return;
+  addrChangeNotifier = acn;
+  refresh();
+}
+
+
+void ManagedListener::refresh() {
+  if (sock)
+    manager->remListener(sock);
+  sock = 0;
+  if (!server)
+    return;
+  try {
+    if (port)
+      sock = new network::TcpListener(port, localOnly);
+  } catch (rdr::Exception& e) {
+    vlog.error(e.str());
+  }
+  if (sock) {
+    if (!localOnly)
+      sock->setFilter(filter);
+    try {
+      manager->addListener(sock, server, addrChangeNotifier);
+    } catch (...) {
+      sock = 0;
+      throw;
+    }
+  }
+}
diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h
new file mode 100644 (file)
index 0000000..e83aa0b
--- /dev/null
@@ -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.
+ */
+
+#ifndef __VNCSERVER_MANAGED_LISTENER_H__
+#define __VNCSERVER_MANAGED_LISTENER_H__
+
+#include <winsock2.h>
+#include <network/TcpSocket.h>
+#include <rfb_win32/SocketManager.h>
+
+namespace winvnc {
+
+  // -=- ManagedListener
+  //     Wrapper class which simplifies the management of a listening socket
+  //     on a specified port, attached to a SocketManager and SocketServer.
+  //     Reopens sockets & reconfigures filters & callbacks as appropriate.
+  //     Handles addition/removal of Listeners from SocketManager internally.
+
+  class ManagedListener {
+  public:
+    ManagedListener(rfb::win32::SocketManager* mgr);
+    ~ManagedListener();
+    
+    void setServer(network::SocketServer* svr);
+    void setPort(int port, bool localOnly=false);
+    void setFilter(const char* filter);
+    void setAddressChangeNotifier(rfb::win32::SocketManager::AddressChangeNotifier* acn);
+  
+    network::TcpListener* sock;
+  protected:
+    void refresh();
+    network::TcpFilter* filter;
+    rfb::win32::SocketManager* manager;
+    rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier;
+    network::SocketServer* server;
+    int port;
+    bool localOnly;
+  };
+
+};
+
+#endif
diff --git a/win/winvnc/QueryConnectDialog.cxx b/win/winvnc/QueryConnectDialog.cxx
new file mode 100644 (file)
index 0000000..dc50eab
--- /dev/null
@@ -0,0 +1,100 @@
+/* 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 <winvnc/QueryConnectDialog.h>
+#include <winvnc/VNCServerWin32.h>
+#include <winvnc/resource.h>
+#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb_win32/Service.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace win32;
+using namespace winvnc;
+
+static LogWriter vlog("QueryConnectDialog");
+
+static IntParameter timeout("QueryConnectTimeout",
+                            "Number of seconds to show the Accept Connection dialog before "
+                            "rejecting the connection",
+                            10);
+
+
+// - Visible methods
+
+QueryConnectDialog::QueryConnectDialog(network::Socket* sock_,
+                                       const char* userName_,
+                                       VNCServerWin32* s)
+: Thread("QueryConnectDialog"), Dialog(GetModuleHandle(0)),
+  sock(sock_), approve(false), server(s) {
+  peerIp.buf = sock->getPeerAddress();
+  userName.buf = strDup(userName_);
+}
+
+void QueryConnectDialog::startDialog() {
+  start();
+}
+
+
+// - Thread overrides
+
+void QueryConnectDialog::run() {
+  countdown = timeout;
+  try {
+    if (desktopChangeRequired() && !changeDesktop())
+      throw rdr::Exception("changeDesktop failed");
+    approve = Dialog::showDialog(MAKEINTRESOURCE(IDD_QUERY_CONNECT));
+    server->queryConnectionComplete();
+  } catch (...) {
+    server->queryConnectionComplete();
+    throw;
+  }
+}
+
+
+// - Dialog overrides
+
+void QueryConnectDialog::initDialog() {
+  if (!SetTimer(handle, 1, 1000, 0))
+    throw rdr::SystemException("SetTimer", GetLastError());
+  setItemString(IDC_QUERY_HOST, TStr(peerIp.buf));
+  if (!userName.buf)
+    userName.buf = strDup("(anonymous)");
+  setItemString(IDC_QUERY_USER, TStr(userName.buf));
+  setCountdownLabel();
+}
+
+void QueryConnectDialog::setCountdownLabel() {
+  TCHAR buf[16];
+  _stprintf(buf, _T("%d"), countdown);
+  setItemString(IDC_QUERY_COUNTDOWN, buf);
+}
+
+BOOL QueryConnectDialog::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  if (msg == WM_TIMER) {
+    if (--countdown == 0 || desktopChangeRequired()) {
+      DestroyWindow(hwnd);
+    } else {
+      setCountdownLabel();
+    }
+    return TRUE;
+  } else {
+    return Dialog::dialogProc(hwnd, msg, wParam, lParam);
+  }
+}
diff --git a/win/winvnc/QueryConnectDialog.h b/win/winvnc/QueryConnectDialog.h
new file mode 100644 (file)
index 0000000..b28de19
--- /dev/null
@@ -0,0 +1,60 @@
+/* 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.
+ */
+
+// -=- QueryConnectDialog.h
+
+#ifndef __WINVNC_QUERY_CONNECT_DIALOG_H__
+#define __WINVNC_QUERY_CONNECT_DIALOG_H__
+
+#include <rfb/Threading.h>
+#include <rfb_win32/Dialog.h>
+#include <rfb/util.h>
+
+namespace network { class Socket; }
+
+namespace winvnc {
+
+  class VNCServerWin32;
+
+  class QueryConnectDialog : public rfb::Thread, rfb::win32::Dialog {
+  public:
+    QueryConnectDialog(network::Socket* sock, const char* userName, VNCServerWin32* s);
+    virtual void startDialog();
+    virtual void run();
+    network::Socket* getSock() {return sock;}
+    bool isAccepted() const {return approve;}
+  protected:
+
+    // Dialog methods (protected)
+    virtual void initDialog();
+    virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+    // Custom internal methods
+    void setCountdownLabel();
+
+    int countdown;
+    network::Socket* sock;
+    rfb::CharArray peerIp;
+    rfb::CharArray userName;
+    bool approve;
+    VNCServerWin32* server;
+  };
+
+};
+
+#endif
diff --git a/win/winvnc/STrayIcon.cxx b/win/winvnc/STrayIcon.cxx
new file mode 100644 (file)
index 0000000..0b10fa5
--- /dev/null
@@ -0,0 +1,280 @@
+/* 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.
+ */
+
+// -=- WinVNC Version 4.0 Tray Icon implementation
+
+#include <winvnc/STrayIcon.h>
+#include <winvnc/VNCServerService.h>
+#include <winvnc/resource.h>
+
+#include <rfb/LogWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb_win32/LaunchProcess.h>
+#include <rfb_win32/TrayIcon.h>
+#include <rfb_win32/AboutDialog.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/Service.h>
+#include <rfb_win32/CurrentUser.h>
+#include <winvnc/ControlPanel.h>
+
+using namespace rfb;
+using namespace win32;
+using namespace winvnc;
+
+static LogWriter vlog("STrayIcon");
+
+BoolParameter STrayIconThread::disableOptions("DisableOptions", "Disable the Options entry in the VNC Server tray menu.", false);
+BoolParameter STrayIconThread::disableClose("DisableClose", "Disable the Close entry in the VNC Server tray menu.", 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;
+
+
+//
+// -=- Internal tray icon class
+//
+
+const UINT WM_SET_TOOLTIP = WM_USER + 1;
+
+
+class winvnc::STrayIcon : public TrayIcon {
+public:
+  STrayIcon(STrayIconThread& t) : thread(t),
+    vncConfig(_T("vncconfig.exe"), isServiceProcess() ? _T("-noconsole -service") : _T("-noconsole")),
+    vncConnect(_T("winvnc4.exe"), _T("-noconsole -connect")) {
+
+    // ***
+    SetWindowText(getHandle(), _T("winvnc::IPC_Interface"));
+    // ***
+
+    SetTimer(getHandle(), 1, 3000, 0);
+    PostMessage(getHandle(), WM_TIMER, 1, 0);
+    PostMessage(getHandle(), WM_SET_TOOLTIP, 0, 0);
+    CPanel = new ControlPanel(getHandle());
+  }
+
+  virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+    switch(msg) {
+
+    case WM_USER:
+      {
+        bool userKnown = CurrentUserToken().canImpersonate();
+        bool allowOptions = !STrayIconThread::disableOptions && userKnown;
+        bool allowClose = !STrayIconThread::disableClose && userKnown;
+
+        switch (lParam) {
+        case WM_LBUTTONDBLCLK:
+          SendMessage(getHandle(), WM_COMMAND, ID_CONTR0L_PANEL, 0);
+          break;
+        case WM_RBUTTONUP:
+          HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(thread.menu));
+          HMENU trayMenu = GetSubMenu(menu, 0);
+
+
+          // Default item is Options, if available, or About if not
+          SetMenuDefaultItem(trayMenu, ID_CONTR0L_PANEL, FALSE);
+          
+          // Enable/disable options as required
+          EnableMenuItem(trayMenu, ID_OPTIONS, (!allowOptions ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
+          EnableMenuItem(trayMenu, ID_CONNECT, (!userKnown ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
+          EnableMenuItem(trayMenu, ID_CLOSE, (!allowClose ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
+
+          thread.server.getClientsInfo(&LCInfo);
+          CheckMenuItem(trayMenu, ID_DISABLE_NEW_CLIENTS, (LCInfo.getDisable() ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND);
+
+          // 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;
+      }
+    
+      // Handle tray icon menu commands
+    case WM_COMMAND:
+      switch (LOWORD(wParam)) {
+      case ID_CONTR0L_PANEL:
+        CPanel->showDialog();
+        break;
+      case ID_DISABLE_NEW_CLIENTS:
+        {
+          thread.server.getClientsInfo(&LCInfo);
+          LCInfo.setDisable(!LCInfo.getDisable());
+          thread.server.setClientsStatus(&LCInfo);
+          CPanel->UpdateListView(&LCInfo);
+        }
+        break;
+      case ID_OPTIONS:
+        {
+          CurrentUserToken token;
+          if (token.canImpersonate())
+            vncConfig.start(isServiceProcess() ? (HANDLE)token : INVALID_HANDLE_VALUE);
+          else
+            vlog.error("Options: unknown current user");
+        }
+        break;
+      case ID_CONNECT:
+        {
+          CurrentUserToken token;
+          if (token.canImpersonate())
+            vncConnect.start(isServiceProcess() ? (HANDLE)token : INVALID_HANDLE_VALUE);
+          else
+            vlog.error("Options: unknown current user");
+        }
+        break;
+      case ID_DISCONNECT:
+        thread.server.disconnectClients("tray menu disconnect");
+        break;
+      case ID_CLOSE:
+        if (MsgBox(0, _T("Are you sure you want to close the server?"),
+                   MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) == IDYES) {
+          if (isServiceProcess()) {
+            ImpersonateCurrentUser icu;
+            try {
+              rfb::win32::stopService(VNCServerService::Name);
+            } catch (rdr::Exception& e) {
+              MsgBox(0, TStr(e.str()), MB_ICONERROR | MB_OK);
+            }
+          } else {
+            thread.server.stop();
+          }
+        }
+        break;
+      case ID_ABOUT:
+        AboutDialog::instance.showDialog();
+        break;
+      }
+      return 0;
+
+      // Handle commands send by other processes
+    case WM_COPYDATA:
+      {
+        COPYDATASTRUCT* command = (COPYDATASTRUCT*)lParam;
+        switch (command->dwData) {
+        case 1:
+          {
+            CharArray viewer = new char[command->cbData + 1];
+            memcpy(viewer.buf, command->lpData, command->cbData);
+            viewer.buf[command->cbData] = 0;
+            return thread.server.addNewClient(viewer.buf) ? 1 : 0;
+          }
+        case 2:
+          return thread.server.disconnectClients("IPC disconnect") ? 1 : 0;
+        case 3:
+          thread.server.setClientsStatus((rfb::ListConnInfo *)command->cbData);
+        case 4:
+          thread.server.getClientsInfo(&LCInfo);
+          CPanel->UpdateListView(&LCInfo);
+          break;
+        };
+      };
+      break;
+
+    case WM_CLOSE:
+      PostQuitMessage(0);
+      break;
+
+    case WM_TIMER:
+      if (rfb::win32::desktopChangeRequired()) {
+        SendMessage(getHandle(), WM_CLOSE, 0, 0);
+        return 0;
+      }
+
+      thread.server.getClientsInfo(&LCInfo);
+      CPanel->UpdateListView(&LCInfo);
+
+      setIcon(thread.server.isServerInUse() ?
+              (!LCInfo.getDisable() ? thread.activeIcon : thread.dis_activeIcon) : 
+              (!LCInfo.getDisable() ? thread.inactiveIcon : thread.dis_inactiveIcon));
+
+      return 0;
+
+    case WM_SET_TOOLTIP:
+      {
+        rfb::Lock l(thread.lock);
+        if (thread.toolTip.buf)
+          setToolTip(thread.toolTip.buf);
+      }
+      return 0;
+
+    }
+
+    return TrayIcon::processMessage(msg, wParam, lParam);
+  }
+
+protected:
+  LaunchProcess vncConfig;
+  LaunchProcess vncConnect;
+  STrayIconThread& thread;
+  ControlPanel * CPanel;
+  rfb::ListConnInfo LCInfo;
+};
+
+
+STrayIconThread::STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon_, UINT activeIcon_, 
+                                 UINT dis_inactiveIcon_, UINT dis_activeIcon_, UINT menu_)
+: Thread("TrayIcon"), server(sm), inactiveIcon(inactiveIcon_), activeIcon(activeIcon_),
+  dis_inactiveIcon(dis_inactiveIcon_), dis_activeIcon(dis_activeIcon_),menu(menu_),
+  windowHandle(0), runTrayIcon(true) {
+  start();
+}
+
+
+void STrayIconThread::run() {
+  while (runTrayIcon) {
+    if (rfb::win32::desktopChangeRequired() && 
+      !rfb::win32::changeDesktop())
+      Sleep(2000);
+
+    STrayIcon icon(*this);
+    windowHandle = icon.getHandle();
+
+    MSG msg;
+    while (runTrayIcon && ::GetMessage(&msg, 0, 0, 0) > 0) {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+
+    windowHandle = 0;
+  }
+}
+
+void STrayIconThread::setToolTip(const TCHAR* text) {
+  if (!windowHandle) return;
+  Lock l(lock);
+  delete [] toolTip.buf;
+  toolTip.buf = tstrDup(text);
+  PostMessage(windowHandle, WM_SET_TOOLTIP, 0, 0);
+}
+
+
diff --git a/win/winvnc/STrayIcon.h b/win/winvnc/STrayIcon.h
new file mode 100644 (file)
index 0000000..309d3f4
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 WINVNC_TRAYICON_H
+#define WINVNC_TRAYICON_H
+
+#include <winvnc/VNCServerWin32.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/Configuration.h>
+#include <rfb/Threading.h>
+
+namespace winvnc {
+
+  class STrayIconThread : rfb::Thread {
+  public:
+    STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon,
+      UINT activeIcon, UINT dis_inactiveIcon, UINT dis_activeIcon, UINT menu);
+    virtual ~STrayIconThread() {
+      runTrayIcon = false;
+      PostThreadMessage(getThreadId(), WM_QUIT, 0, 0);
+    }
+
+    virtual void run();
+
+    void setToolTip(const TCHAR* text);
+
+    static rfb::BoolParameter disableOptions;
+    static rfb::BoolParameter disableClose;
+
+    friend class STrayIcon;
+  protected:
+    rfb::Mutex lock;
+    HWND windowHandle;
+    rfb::TCharArray toolTip;
+    VNCServerWin32& server;
+    UINT inactiveIcon;
+    UINT activeIcon;
+    UINT dis_inactiveIcon;
+    UINT dis_activeIcon;
+    UINT menu;
+    bool runTrayIcon;
+  };
+
+};
+
+#endif
diff --git a/win/winvnc/VNCServerService.cxx b/win/winvnc/VNCServerService.cxx
new file mode 100644 (file)
index 0000000..2ef2ee0
--- /dev/null
@@ -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.
+ */
+
+// -=- WinVNC Version 4.0 Service-Mode implementation
+
+#include <winvnc/VNCServerService.h>
+#include <rfb_win32/OSVersion.h>
+
+using namespace winvnc;
+using namespace rfb;
+using namespace win32;
+
+const TCHAR* winvnc::VNCServerService::Name = _T("WinVNC4");
+
+
+VNCServerService::VNCServerService(VNCServerWin32& s)
+  : Service(Name), server(s) {
+  // - Set the service-mode logging defaults
+  //   These will be overridden by the Log option in the
+  //   registry, if present.
+  if (osVersion.isPlatformNT)
+    logParams.setParam("*:EventLog:0,Connections:EventLog:100");
+  else
+    logParams.setParam("*:file:0,Connections:file:100");
+}
+
+
+DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[]) {
+  setStatus(SERVICE_RUNNING);
+  int result = server.run();
+  setStatus(SERVICE_STOP_PENDING);
+  return result;
+}
+
+void VNCServerService::stop() {
+  server.stop();
+}
diff --git a/win/winvnc/VNCServerService.h b/win/winvnc/VNCServerService.h
new file mode 100644 (file)
index 0000000..c7a76cc
--- /dev/null
@@ -0,0 +1,41 @@
+/* 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 __WINVNC_SERVICEMODE_H__
+#define __WINVNC_SERVICEMODE_H__
+
+#include <winvnc/VNCServerWin32.h>
+#include <rfb_win32/Service.h>
+
+namespace winvnc {
+
+  class VNCServerService : public rfb::win32::Service {
+  public:
+    VNCServerService(VNCServerWin32& s);
+
+    DWORD serviceMain(int argc, TCHAR* argv[]);
+    void stop();
+
+    static const TCHAR* Name;
+  protected:
+    VNCServerWin32& server;
+  };
+
+};
+
+#endif
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
new file mode 100644 (file)
index 0000000..3b0e1a0
--- /dev/null
@@ -0,0 +1,333 @@
+/* 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.
+ */
+
+// -=- WinVNC Version 4.0 Main Routine
+
+#include <winvnc/VNCServerWin32.h>
+#include <winvnc/resource.h>
+#include <winvnc/STrayIcon.h>
+#include <rfb_win32/ComputerName.h>
+#include <rfb_win32/CurrentUser.h>
+#include <rfb_win32/Service.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/Hostname.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/SFileTransferWin32.h>
+
+using namespace rfb;
+using namespace win32;
+using namespace winvnc;
+using namespace network;
+
+static LogWriter vlog("VNCServerWin32");
+
+
+const TCHAR* winvnc::VNCServerWin32::RegConfigPath = _T("Software\\TightVNC\\WinVNC4");
+
+// FIXME: Move into an .h file?
+extern const UINT VNCM_FT_DOWNLOAD;
+
+
+static IntParameter http_port("HTTPPortNumber",
+  "TCP/IP port on which the server will serve the Java applet VNC Viewer ", 5800);
+static IntParameter port_number("PortNumber",
+  "TCP/IP port on which the server will accept connections", 5900);
+static StringParameter hosts("Hosts",
+  "Filter describing which hosts are allowed access to this server", "+0.0.0.0/0.0.0.0");
+static BoolParameter localHost("LocalHost",
+  "Only accept connections from via the local loop-back network interface", false);
+static BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
+  "Only prompt for a local user to accept incoming connections if there is a user logged on", false);
+
+
+VNCServerWin32::VNCServerWin32()
+  : command(NoCommand), commandSig(commandLock),
+    commandEvent(CreateEvent(0, TRUE, FALSE, 0)),
+    vncServer(CStr(ComputerName().buf), &desktop),
+    hostThread(0), runServer(false), isDesktopStarted(false),
+    httpServer(&vncServer), config(&sockMgr), trayIcon(0),
+    rfbSock(&sockMgr), httpSock(&sockMgr),
+    queryConnectDialog(0)
+{
+  // Initialise the desktop
+  desktop.setStatusLocation(&isDesktopStarted);
+
+  // Initialise the VNC server
+  vncServer.setQueryConnectionHandler(this);
+
+  // Register the desktop's event to be handled
+  sockMgr.addEvent(desktop.getUpdateEvent(), &desktop);
+
+  // Register the queued command event to be handled
+  sockMgr.addEvent(commandEvent, this);
+
+  vncServer.setFTManager((rfb::SFileTransferManager *)&m_FTManager);
+}
+
+VNCServerWin32::~VNCServerWin32() {
+  delete trayIcon;
+
+  // Stop the SDisplay from updating our state
+  desktop.setStatusLocation(0);
+
+  // Join the Accept/Reject dialog thread
+  if (queryConnectDialog)
+    delete queryConnectDialog->join();
+}
+
+
+void VNCServerWin32::processAddressChange(network::SocketListener* sock_) {
+  if (!trayIcon || (sock_ != rfbSock.sock))
+    return;
+
+  // Tool-tip prefix depends on server mode
+  const TCHAR* prefix = _T("VNC Server (User):");
+  if (isServiceProcess())
+    prefix = _T("VNC Server (Service):");
+
+  // Fetch the list of addresses
+  std::list<char*> addrs;
+  if (rfbSock.sock)
+    rfbSock.sock->getMyAddresses(&addrs);
+  else
+    addrs.push_front(strDup("Not accepting connections"));
+
+  // Allocate space for the new tip
+  std::list<char*>::iterator i, next_i;
+  int length = _tcslen(prefix)+1;
+  for (i=addrs.begin(); i!= addrs.end(); i++)
+    length += strlen(*i) + 1;
+
+  // Build the new tip
+  TCharArray toolTip(length);
+  _tcscpy(toolTip.buf, prefix);
+  for (i=addrs.begin(); i!= addrs.end(); i=next_i) {
+    next_i = i; next_i ++;
+    TCharArray addr = *i;    // Assumes ownership of string
+    _tcscat(toolTip.buf, addr.buf);
+    if (next_i != addrs.end())
+      _tcscat(toolTip.buf, _T(","));
+  }
+  
+  // Pass the new tip to the tray icon
+  vlog.info("Refreshing tray icon");
+  trayIcon->setToolTip(toolTip.buf);
+}
+
+void VNCServerWin32::regConfigChanged() {
+  // -=- Make sure we're listening on the right ports.
+  rfbSock.setServer(&vncServer);
+  rfbSock.setPort(port_number, localHost);
+  httpSock.setServer(&httpServer);
+  httpSock.setPort(http_port, localHost);
+
+  // -=- Update the Java viewer's web page port number.
+  httpServer.setRFBport(rfbSock.sock ? port_number : 0);
+
+  // -=- Update the TCP address filter for both ports, if open.
+  CharArray pattern(hosts.getData());
+  rfbSock.setFilter(pattern.buf);
+  httpSock.setFilter(pattern.buf);
+
+  // -=- Update the tray icon tooltip text with IP addresses
+  processAddressChange(rfbSock.sock);
+}
+
+
+int VNCServerWin32::run() {
+  { Lock l(runLock);
+    hostThread = Thread::self();
+    runServer = true;
+  }
+
+  // - Create the tray icon (if possible)
+  trayIcon = new STrayIconThread(*this, IDI_ICON, IDI_CONNECTED,
+                                 IDI_ICON_DISABLE, IDI_CONNECTED_DISABLE,
+                                 IDR_TRAY);
+
+  // - Register for notification of configuration changes
+  config.setCallback(this);
+  if (isServiceProcess())
+    config.setKey(HKEY_LOCAL_MACHINE, RegConfigPath);
+  else
+    config.setKey(HKEY_CURRENT_USER, RegConfigPath);
+
+  // - Set the address-changed handler for the RFB socket
+  rfbSock.setAddressChangeNotifier(this);
+
+  DWORD result = 0;
+  try {
+    vlog.debug("Entering message loop");
+
+    // - Run the server until we're told to quit
+    MSG msg;
+    int result = 0;
+    while (runServer) {
+      result = sockMgr.getMessage(&msg, NULL, 0, 0);
+      if (result < 0)
+        throw rdr::SystemException("getMessage", GetLastError());
+      if (!isServiceProcess() && (result == 0))
+        break;
+      if (msg.message == VNCM_FT_DOWNLOAD)
+        m_FTManager.processDownloadMsg(msg);
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+
+    vlog.debug("Server exited cleanly");
+  } catch (rdr::SystemException &s) {
+    vlog.error(s.str());
+    result = s.err;
+  } catch (rdr::Exception &e) {
+    vlog.error(e.str());
+  }
+
+  { Lock l(runLock);
+    runServer = false;
+    hostThread = 0;
+  }
+
+  return result;
+}
+
+void VNCServerWin32::stop() {
+  Lock l(runLock);
+  runServer = false;
+  if (hostThread)
+    PostThreadMessage(hostThread->getThreadId(), WM_QUIT, 0, 0);
+}
+
+
+bool VNCServerWin32::disconnectClients(const char* reason) {
+  return queueCommand(DisconnectClients, reason, 0);
+}
+
+bool VNCServerWin32::addNewClient(const char* client) {
+  TcpSocket* sock = 0;
+  try {
+    CharArray hostname;
+    int port;
+    getHostAndPort(client, &hostname.buf, &port, 5500);
+    vlog.error("port=%d", port);
+    sock = new TcpSocket(hostname.buf, port);
+    if (queueCommand(AddClient, sock, 0))
+      return true;
+    delete sock;
+  } catch (...) {
+    delete sock;
+  }
+  return false;
+}
+
+bool VNCServerWin32::getClientsInfo(rfb::ListConnInfo* LCInfo) {
+  return queueCommand(GetClientsInfo, LCInfo, 0);
+}
+
+bool VNCServerWin32::setClientsStatus(rfb::ListConnInfo* LCInfo) {
+  return queueCommand(SetClientsStatus, LCInfo, 0);
+}
+
+VNCServerST::queryResult VNCServerWin32::queryConnection(network::Socket* sock,
+                                            const char* userName,
+                                            char** reason)
+{
+  if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn())
+    return VNCServerST::ACCEPT;
+  if (queryConnectDialog) {
+    *reason = rfb::strDup("Another connection is currently being queried.");
+    return VNCServerST::REJECT;
+  }
+  queryConnectDialog = new QueryConnectDialog(sock, userName, this);
+  queryConnectDialog->startDialog();
+  return VNCServerST::PENDING;
+}
+
+void VNCServerWin32::queryConnectionComplete() {
+  queueCommand(QueryConnectionComplete, 0, 0, false);
+}
+
+
+bool VNCServerWin32::queueCommand(Command cmd, const void* data, int len, bool wait) {
+  Lock l(commandLock);
+  while (command != NoCommand)
+    commandSig.wait();
+  command = cmd;
+  commandData = data;
+  commandDataLen = len;
+  SetEvent(commandEvent);
+  if (wait) {
+    while (command != NoCommand)
+      commandSig.wait();
+    commandSig.signal();
+  }
+  return true;
+}
+
+void VNCServerWin32::processEvent(HANDLE event_) {
+  ResetEvent(event_);
+
+  if (event_ == commandEvent.h) {
+    // If there is no command queued then return immediately
+    {
+      Lock l(commandLock);
+      if (command == NoCommand)
+        return;
+    }
+
+    // Perform the required command
+    switch (command) {
+
+    case DisconnectClients:
+      // Disconnect all currently active VNC Viewers
+      vncServer.closeClients((const char*)commandData);
+      break;
+
+    case AddClient:
+      // Make a reverse connection to a VNC Viewer
+      sockMgr.addSocket((network::Socket*)commandData, &vncServer);
+      break;
+  case GetClientsInfo:
+    vncServer.getConnInfo((ListConnInfo*)commandData); 
+    break;
+  case SetClientsStatus:
+    vncServer.setConnStatus((ListConnInfo*)commandData); 
+    break;
+
+    case QueryConnectionComplete:
+      // The Accept/Reject dialog has completed
+      // Get the result, then clean it up
+      vncServer.approveConnection(queryConnectDialog->getSock(),
+                                  queryConnectDialog->isAccepted(),
+                                  "Connection rejected by user");
+      delete queryConnectDialog->join();
+      queryConnectDialog = 0;
+      break;
+
+    default:
+      vlog.error("unknown command %d queued", command);
+    };
+
+    // Clear the command and signal completion
+    {
+      Lock l(commandLock);
+      command = NoCommand;
+      commandSig.signal();
+    }
+  }
+}
+
diff --git a/win/winvnc/VNCServerWin32.h b/win/winvnc/VNCServerWin32.h
new file mode 100644 (file)
index 0000000..579a6a0
--- /dev/null
@@ -0,0 +1,130 @@
+/* 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 __VNCSERVER_WIN32_H__
+#define __VNCSERVER_WIN32_H__
+
+#include <winsock2.h>
+#include <network/TcpSocket.h>
+#include <rfb/VNCServerST.h>
+#include <rfb_win32/RegConfig.h>
+#include <rfb_win32/SDisplay.h>
+#include <rfb_win32/SocketManager.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb_win32/SFileTransferManagerWin32.h>
+#include <winvnc/QueryConnectDialog.h>
+#include <winvnc/JavaViewer.h>
+#include <winvnc/ManagedListener.h>
+
+namespace winvnc {
+
+  class STrayIconThread;
+
+  class VNCServerWin32 : rfb::VNCServerST::QueryConnectionHandler,
+                         rfb::win32::SocketManager::AddressChangeNotifier,
+                         rfb::win32::RegConfig::Callback,
+                         rfb::win32::EventHandler {
+  public:
+    VNCServerWin32();
+    virtual ~VNCServerWin32();
+
+    // Run the server in the current thread
+    int run();
+
+    // Cause the run() call to return
+    // THREAD-SAFE
+    void stop();
+
+    // Determine whether a viewer is active
+    // THREAD-SAFE
+    bool isServerInUse() const {return isDesktopStarted;}
+
+    // Connect out to the specified VNC Viewer
+    // THREAD-SAFE
+    bool addNewClient(const char* client);
+
+    // Disconnect all connected clients
+    // THREAD-SAFE
+    bool disconnectClients(const char* reason=0);
+
+    // Call used to notify VNCServerST of user accept/reject query completion
+    // CALLED FROM AcceptConnectDialog THREAD
+    void queryConnectionComplete();
+
+    // Where to read the configuration settings from
+    static const TCHAR* RegConfigPath;
+
+    bool getClientsInfo(rfb::ListConnInfo* LCInfo);
+
+    bool setClientsStatus(rfb::ListConnInfo* LCInfo);
+
+  protected:
+    // VNCServerST::QueryConnectionHandler interface
+    // Callback used to prompt user to accept or reject a connection.
+    // CALLBACK IN VNCServerST "HOST" THREAD
+    virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock,
+                                                          const char* userName,
+                                                          char** reason);
+
+    // SocketManager::AddressChangeNotifier interface
+    // Used to keep tray icon up to date
+    virtual void processAddressChange(network::SocketListener* sl);
+
+    // RegConfig::Callback interface
+    // Called via the EventManager whenver RegConfig sees the registry change
+    virtual void regConfigChanged();
+
+    // EventHandler interface
+    // Used to perform queued commands
+    virtual void processEvent(HANDLE event);
+
+  protected:
+    // Perform a particular internal function in the server thread
+    typedef enum {NoCommand, DisconnectClients, AddClient, QueryConnectionComplete, SetClientsStatus, GetClientsInfo} Command;
+    bool queueCommand(Command cmd, const void* data, int len, bool wait=true);
+    Command command;
+    const void* commandData;
+    int commandDataLen;
+    rfb::Mutex commandLock;
+    rfb::Condition commandSig;
+    rfb::win32::Handle commandEvent;
+
+    // VNCServerWin32 Server-internal state
+    rfb::win32::SDisplay desktop;
+    rfb::VNCServerST vncServer;
+    rfb::Mutex runLock;
+    rfb::Thread* hostThread;
+    bool runServer;
+    bool isDesktopStarted;
+    JavaViewerServer httpServer;
+    rfb::win32::SocketManager sockMgr;
+    rfb::win32::RegConfig config;
+
+    ManagedListener rfbSock;
+    ManagedListener httpSock;
+    STrayIconThread* trayIcon;
+
+    //rfb::SSecurityFactoryStandard securityFactory;
+
+    QueryConnectDialog* queryConnectDialog;
+    rfb::win32::SFileTransferManagerWin32 m_FTManager;
+  };
+
+};
+
+#endif
diff --git a/win/winvnc/buildTime.cxx b/win/winvnc/buildTime.cxx
new file mode 100644 (file)
index 0000000..9f37b38
--- /dev/null
@@ -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/winvnc/connecte.ico b/win/winvnc/connecte.ico
new file mode 100644 (file)
index 0000000..8f814b3
Binary files /dev/null and b/win/winvnc/connecte.ico differ
diff --git a/win/winvnc/connected.ico b/win/winvnc/connected.ico
new file mode 100644 (file)
index 0000000..44ce3c9
Binary files /dev/null and b/win/winvnc/connected.ico differ
diff --git a/win/winvnc/icon_dis.ico b/win/winvnc/icon_dis.ico
new file mode 100644 (file)
index 0000000..0a6ea15
Binary files /dev/null and b/win/winvnc/icon_dis.ico differ
diff --git a/win/winvnc/resource.h b/win/winvnc/resource.h
new file mode 100644 (file)
index 0000000..68316be
--- /dev/null
@@ -0,0 +1,54 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by winvnc.rc
+//
+#define IDR_MANIFEST                    1
+#define IDI_ICON                        101
+#define IDR_TRAY                        102
+#define IDD_DIALOG1                     103
+#define IDD_ABOUT                       104
+#define IDI_CONNECTED                   105
+#define IDR_VNCVIEWER_JAR               106
+#define IDD_QUERY_CONNECT               107
+#define IDD_ADD_NEW_CLIENT              108
+#define IDB_BITMAP                      109
+#define IDD_CONTROL_PANEL               110
+#define IDI_ICON_DISABLE                111
+#define IDI_CONNECTED_DISABLE           112
+#define IDC_DESCRIPTION                 1000
+#define IDC_BUILDTIME                   1001
+#define IDC_VERSION                     1002
+#define IDC_COPYRIGHT                   1003
+#define IDC_QUERY_COUNTDOWN             1008
+#define IDC_QUERY_USER                  1009
+#define IDC_QUERY_HOST                  1010
+#define IDC_HOST                        1011
+#define IDC_LIST_CONNECTIONS            1012
+#define IDC_STATIC_KLIENTS_LIST         1013
+#define IDC_STATIC_SELECTED_KLIENTS     1014
+#define IDC_VIEW_ONLY                   1015
+#define IDC_FULL_CONTROL                1016
+#define IDC_STOP_UPDATE                 1017
+#define IDC_KILL_SEL_CLIENT             1018
+#define IDC_PROPERTIES                  1019
+#define IDC_ADD_CLIENT                  1020
+#define IDC_KILL_ALL                    1021
+#define IDC_DISABLE_CLIENTS             1022
+#define ID_CONTR0L_PANEL                40001
+#define ID_CLOSE                        40002
+#define ID_ABOUT                        40003
+#define ID_DISCONNECT                   40004
+#define ID_CONNECT                      40005
+#define ID_OPTIONS                      40006
+#define ID_DISABLE_NEW_CLIENTS          40007
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        113
+#define _APS_NEXT_COMMAND_VALUE         40008
+#define _APS_NEXT_CONTROL_VALUE         1023
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/win/winvnc/winvnc.bmp b/win/winvnc/winvnc.bmp
new file mode 100644 (file)
index 0000000..90c02f8
Binary files /dev/null and b/win/winvnc/winvnc.bmp differ
diff --git a/win/winvnc/winvnc.cxx b/win/winvnc/winvnc.cxx
new file mode 100644 (file)
index 0000000..2d01f89
--- /dev/null
@@ -0,0 +1,262 @@
+/* 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 Server 4.0 for Windows (WinVNC4)
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+#include <winvnc/VNCServerWin32.h>
+#include <winvnc/VNCServerService.h>
+#include <winvnc/AddNewClientDialog.h>
+
+#include <rfb/Logger_stdio.h>
+#include <rfb/Logger_file.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/AboutDialog.h>
+#include <rfb_win32/MsgBox.h>
+#include <network/TcpSocket.h>
+
+using namespace winvnc;
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("main");
+
+TStr rfb::win32::AppName("VNC Server");
+
+
+static bool runAsService = false;
+static bool runServer = true;
+static bool close_console = false;
+
+
+//
+// -=- processParams
+//     Read in the command-line parameters and interpret them.
+//
+
+static 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")));
+}
+
+static void programUsage() {
+  printf("Command-line options:\n");
+  printf("  -connect [<host[::port]>]            - Connect an existing WinVNC server to a listening viewer.\n");
+  printf("  -disconnect                          - Disconnect all clients from an existing WinVNC server.\n");
+  printf("  -register <options...>               - Register WinVNC server as a system service.\n");
+  printf("  -unregister                          - Remove WinVNC server from the list of system services.\n");
+  printf("  -start                               - Start the WinVNC server system service.\n");
+  printf("  -stop                                - Stop the WinVNC server system service.\n");
+  printf("  -status                              - Query the WinVNC service status.\n");
+  printf("  -help                                - Provide usage information.\n");
+  printf("  -noconsole                           - Run without a console (i.e. no stderr/stdout)\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("\nAvailable configuration parameters:\n");
+  Configuration::listParams();
+}
+
+static void MsgBoxOrLog(const char* msg, bool isError=false) {
+  if (close_console) {
+    MsgBox(0, TStr(msg), (isError ? MB_ICONERROR : MB_ICONINFORMATION) | MB_OK);
+  } else {
+    if (isError) {
+      try {
+        vlog.error(msg);
+        return;
+      } catch (...) {
+      }
+    }
+    fprintf(stderr, "%s\n", msg);
+  }
+}
+
+static void processParams(int argc, const char* argv[]) {
+  for (int i=1; i<argc; i++) {
+    try {
+
+      if (strcasecmp(argv[i], "-connect") == 0) {
+        runServer = false;
+        CharArray host;
+        if (i+1 < argc) {
+          host.buf = strDup(argv[i+1]);
+          i++;
+        } else {
+          AddNewClientDialog ancd;
+          if (ancd.showDialog())
+            host.buf = strDup(ancd.getHostName());
+        }
+        if (host.buf) {
+          HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
+          if (!hwnd)
+            throw rdr::Exception("Unable to locate existing VNC Server.");
+          COPYDATASTRUCT copyData;
+          copyData.dwData = 1; // *** AddNewClient
+          copyData.cbData = strlen(host.buf);
+          copyData.lpData = (void*)host.buf;
+          printf("Sending connect request to VNC Server...\n");
+          if (!SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&copyData))
+            MsgBoxOrLog("Connection failed.", true);
+        }
+      } else if (strcasecmp(argv[i], "-disconnect") == 0) {
+        runServer = false;
+        HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
+        if (!hwnd)
+          throw rdr::Exception("Unable to locate existing VNC Server.");
+        COPYDATASTRUCT copyData;
+        copyData.dwData = 2; // *** DisconnectClients
+        copyData.lpData = 0;
+        copyData.cbData = 0;
+        printf("Sending disconnect request to VNC Server...\n");
+        if (!SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&copyData))
+          MsgBoxOrLog("Failed to disconnect clients.", true);
+      } else if (strcasecmp(argv[i], "-start") == 0) {
+        printf("Attempting to start service...\n");
+        runServer = false;
+        if (rfb::win32::startService(VNCServerService::Name))
+          MsgBoxOrLog("Started service successfully");
+      } else if (strcasecmp(argv[i], "-stop") == 0) {
+        printf("Attempting to stop service...\n");
+        runServer = false;
+        if (rfb::win32::stopService(VNCServerService::Name))
+          MsgBoxOrLog("Stopped service successfully");
+      } else if (strcasecmp(argv[i], "-status") == 0) {
+        printf("Querying service status...\n");
+        runServer = false;
+        DWORD state = rfb::win32::getServiceState(VNCServerService::Name);
+        CharArray stateStr(rfb::win32::serviceStateName(state));
+        const char* stateMsg = "The %s Service is in the %s state.";
+        CharArray result(strlen(stateStr.buf) + _tcslen(VNCServerService::Name) + strlen(stateMsg) + 1);
+        sprintf(result.buf, stateMsg, (const char*)CStr(VNCServerService::Name), stateStr.buf);
+        MsgBoxOrLog(result.buf);
+      } else if (strcasecmp(argv[i], "-service") == 0) {
+        printf("Run in service mode\n");
+        runAsService = true;
+
+      } else if (strcasecmp(argv[i], "-register") == 0) {
+        printf("Attempting to register service...\n");
+        runServer = false;
+        int j = i;
+        i = argc;
+        if (rfb::win32::registerService(VNCServerService::Name,
+                                        _T("VNC Server Version 4"),
+                                        argc-(j+1), &argv[j+1]))
+          MsgBoxOrLog("Registered service successfully");
+      } else if (strcasecmp(argv[i], "-unregister") == 0) {
+        printf("Attempting to unregister service...\n");
+        runServer = false;
+        if (rfb::win32::unregisterService(VNCServerService::Name))
+          MsgBoxOrLog("Unregistered service successfully");
+
+      } else if (strcasecmp(argv[i], "-noconsole") == 0) {
+        close_console = true;
+        vlog.info("closing console");
+        if (!FreeConsole())
+          vlog.info("unable to close console:%u", GetLastError());
+
+      } else if ((strcasecmp(argv[i], "-help") == 0) ||
+        (strcasecmp(argv[i], "--help") == 0) ||
+        (strcasecmp(argv[i], "-h") == 0) ||
+        (strcasecmp(argv[i], "/?") == 0)) {
+        runServer = false;
+        programUsage();
+        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;
+          }
+        }
+        // Nope.  Show them usage and don't run the server
+        runServer = false;
+        programUsage();
+        break;
+      }
+
+    } catch (rdr::Exception& e) {
+      MsgBoxOrLog(e.str(), true);
+    }
+  }
+}
+
+
+//
+// -=- main
+//
+
+int main(int argc, const char* argv[]) {
+  int result = 0;
+
+  try {
+    // - Initialise the available loggers
+    //freopen("\\\\drupe\\tjr\\WinVNC4.log","ab",stderr);
+    //setbuf(stderr, 0);
+    initStdIOLoggers();
+    initFileLogger("C:\\temp\\WinVNC4.log");
+    rfb::win32::initEventLogLogger(VNCServerService::Name);
+
+    // - By default, just log errors to stderr
+    logParams.setParam("*:stderr:0");
+
+    // - Print program details and process the command line
+    programInfo();
+    processParams(argc, argv);
+
+    // - Run the server if required
+    if (runServer) {
+      // Start the network subsystem and run the server
+      VNCServerWin32 server;
+
+      if (runAsService) {
+        printf("Starting Service-Mode VNC Server.\n");
+        VNCServerService service(server);
+        service.start();
+        result = service.getStatus().dwWin32ExitCode;
+      } else {
+        printf("Starting User-Mode VNC Server.\n");
+        result = server.run();
+      }
+    }
+
+    vlog.debug("WinVNC service destroyed");
+  } catch (rdr::Exception& e) {
+    MsgBoxOrLog(e.str(), true);
+  }
+
+  vlog.debug("WinVNC process quitting");
+  return result;
+}
diff --git a/win/winvnc/winvnc.dsp b/win/winvnc/winvnc.dsp
new file mode 100644 (file)
index 0000000..ec76f3f
--- /dev/null
@@ -0,0 +1,252 @@
+# Microsoft Developer Studio Project File - Name="winvnc" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=winvnc - Win32 Debug Unicode\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "winvnc.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "winvnc.mak" CFG="winvnc - Win32 Debug Unicode"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "winvnc - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "winvnc - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "winvnc - Win32 Debug Unicode" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "winvnc - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release"\r
+# PROP Intermediate_Dir "..\Release\winvnc"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /FR /YX /FD /c\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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:console /machine:I386\r
+# ADD LINK32 advapi32.lib user32.lib gdi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:console /machine:I386 /out:"../Release/winvnc4.exe"\r
+# SUBTRACT LINK32 /profile\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Desc=Updating buildTime\r
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\winvnc /MT buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "winvnc - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug"\r
+# PROP Intermediate_Dir "..\Debug\winvnc"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 advapi32.lib user32.lib gdi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../Debug/winvnc4.exe" /fixed:no\r
+# SUBTRACT LINK32 /profile\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Desc=Updating buildTime\r
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\winvnc /MTd buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ELSEIF  "$(CFG)" == "winvnc - Win32 Debug Unicode"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "winvnc___Win32_Debug_Unicode"\r
+# PROP BASE Intermediate_Dir "winvnc___Win32_Debug_Unicode"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug_Unicode"\r
+# PROP Intermediate_Dir "..\Debug_Unicode\winvnc"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_CONSOLE" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../Debug/winvnc4.exe" /fixed:no\r
+# SUBTRACT BASE LINK32 /pdb:none\r
+# ADD LINK32 advapi32.lib user32.lib gdi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\Debug_Unicode/winvnc4.exe" /fixed:no\r
+# SUBTRACT LINK32 /pdb:none\r
+# Begin Special Build Tool\r
+SOURCE="$(InputPath)"\r
+PreLink_Desc=Updating buildTime\r
+PreLink_Cmds=cl /c /nologo /Fo..\Debug_Unicode /Fd..\Debug_Unicode\winvnc /MTd buildTime.cxx\r
+# End Special Build Tool\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "winvnc - Win32 Release"\r
+# Name "winvnc - Win32 Debug"\r
+# Name "winvnc - Win32 Debug Unicode"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\buildTime.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ControlPanel.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\JavaViewer.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ManagedListener.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\QueryConnectDialog.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\STrayIcon.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\VNCServerService.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\VNCServerWin32.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\winvnc.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\winvnc.rc\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\AddNewClientDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ControlPanel.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\JavaViewer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ManagedListener.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\QueryConnectDialog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\STrayIcon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\VNCServerService.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\VNCServerWin32.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# Begin Source File\r
+\r
+SOURCE=.\connecte.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\connected.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icon_dis.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\common\javabin\logo150x150.gif\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\winvnc.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\winvnc.ico\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=..\..\common\javabin\index.vnc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\common\javabin\vncviewer.jar\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\winvnc4.exe.manifest\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/win/winvnc/winvnc.ico b/win/winvnc/winvnc.ico
new file mode 100644 (file)
index 0000000..1b42416
Binary files /dev/null and b/win/winvnc/winvnc.ico differ
diff --git a/win/winvnc/winvnc.rc b/win/winvnc/winvnc.rc
new file mode 100644 (file)
index 0000000..143b0d6
--- /dev/null
@@ -0,0 +1,328 @@
+//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
+
+
+#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 Server for Win32\0"
+            VALUE "FileVersion", "4.1.1\0"
+            VALUE "InternalName", "winvnc\0"
+            VALUE "LegalCopyright", "Copyright (C) 1998-2005 [many holders]\0"
+            VALUE "LegalTrademarks", "TightVNC\0"
+            VALUE "OriginalFilename", "winvnc4.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "TightVNC Server\0"
+            VALUE "ProductVersion", "4.1.1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x809, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON                ICON    DISCARDABLE     "winvnc.ico"
+IDI_CONNECTED           ICON    DISCARDABLE     "connected.ico"
+IDI_ICON_DISABLE        ICON    DISCARDABLE     "icon_dis.ico"
+IDI_CONNECTED_DISABLE   ICON    DISCARDABLE     "connecte.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAY MENU DISCARDABLE 
+BEGIN
+    POPUP "Tray Menu"
+    BEGIN
+        MENUITEM "Control &Panel",              ID_CONTR0L_PANEL
+        MENUITEM SEPARATOR
+        MENUITEM "&Options...",                 ID_OPTIONS
+        MENUITEM "Add &New Client...",          ID_CONNECT
+        MENUITEM "&Disconnect Clients",         ID_DISCONNECT
+        MENUITEM "D&isable New Clients",        ID_DISABLE_NEW_CLIENTS
+        MENUITEM SEPARATOR
+        MENUITEM "&Close VNC Server",           ID_CLOSE
+        MENUITEM "&About...",                   ID_ABOUT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUT DIALOG DISCARDABLE  0, 0, 249, 92
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "About VNC Server for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,195,70,47,15
+    CONTROL         109,IDC_STATIC,"Static",SS_BITMAP,5,10,33,31
+    LTEXT           ">appname<",IDC_DESCRIPTION,45,10,125,15
+    LTEXT           ">version<",IDC_VERSION,170,10,72,15
+    LTEXT           ">buildtime<",IDC_BUILDTIME,45,25,202,15
+    LTEXT           ">copyright<",IDC_COPYRIGHT,45,40,202,15
+    LTEXT           "See http://www.tightvnc.com for more information on VNC.",
+                    IDC_STATIC,45,55,202,15
+END
+
+IDD_QUERY_CONNECT DIALOG DISCARDABLE  0, 0, 164, 93
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "VNC Server : Accept Connection?"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "&Reject",IDCANCEL,105,72,52,14
+    PUSHBUTTON      "&Accept",IDOK,7,72,53,14
+    RTEXT           "User:",IDC_STATIC,7,10,28,15,SS_CENTERIMAGE
+    RTEXT           "Host:",IDC_STATIC,7,30,28,15,SS_CENTERIMAGE
+    CTEXT           "Seconds until automatic reject:",IDC_STATIC,7,50,113,15,
+                    SS_CENTERIMAGE
+    LTEXT           "-",IDC_QUERY_COUNTDOWN,125,50,32,15,SS_CENTERIMAGE
+    LTEXT           "-",IDC_QUERY_USER,40,10,117,15,SS_CENTERIMAGE
+    LTEXT           "-",IDC_QUERY_HOST,40,30,117,15,SS_CENTERIMAGE
+END
+
+IDD_ADD_NEW_CLIENT DIALOG DISCARDABLE  0, 0, 177, 52
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | 
+    WS_CAPTION | WS_SYSMENU
+CAPTION "VNC Server : Add New Client"
+FONT 8, "MS Sans Serif"
+BEGIN
+    EDITTEXT        IDC_HOST,80,10,90,15,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "OK",IDOK,80,31,40,14
+    PUSHBUTTON      "Cancel",IDCANCEL,125,31,45,14
+    CONTROL         109,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,7,
+                    10,33,31
+    RTEXT           "Viewer:",IDC_STATIC,45,10,30,15,SS_CENTERIMAGE
+END
+
+IDD_CONTROL_PANEL DIALOG DISCARDABLE  0, 0, 267, 238
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | DS_CONTEXTHELP | 
+    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Control Panel"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "List1",IDC_LIST_CONNECTIONS,"SysListView32",LVS_REPORT | 
+                    LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | 
+                    WS_BORDER | WS_TABSTOP,7,25,253,76
+    LTEXT           "Authorised clients list",IDC_STATIC_KLIENTS_LIST,87,7,
+                    74,11,SS_CENTERIMAGE
+    GROUPBOX        "Control of selected clients",
+                    IDC_STATIC_SELECTED_KLIENTS,7,108,124,103
+    PUSHBUTTON      "View-only",IDC_VIEW_ONLY,13,121,111,14
+    PUSHBUTTON      "Full control ",IDC_FULL_CONTROL,13,145,112,14
+    PUSHBUTTON      "Stop updating",IDC_STOP_UPDATE,13,167,111,14
+    PUSHBUTTON      "Kill Clients",IDC_KILL_SEL_CLIENT,13,190,111,14
+    PUSHBUTTON      "Properties",IDC_PROPERTIES,144,121,111,14
+    PUSHBUTTON      "Add New Client",IDC_ADD_CLIENT,144,145,111,14
+    PUSHBUTTON      "Kill All Clients",IDC_KILL_ALL,144,167,111,14
+    CONTROL         "Disable New Clients",IDC_DISABLE_CLIENTS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,144,191,111,13
+    PUSHBUTTON      "Close",IDCANCEL,144,217,111,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// HTTPFILE
+//
+
+/VNCVIEWER.JAR          HTTPFILE DISCARDABLE    "..\\..\\common\\javabin\\vncviewer.jar"
+/LOGO150X150.GIF        HTTPFILE DISCARDABLE    "..\\..\\common\\javabin\\logo150x150.gif"
+/INDEX.VNC              HTTPFILE DISCARDABLE    "..\\..\\common\\javabin\\index.vnc"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 24
+//
+
+IDR_MANIFEST            24      DISCARDABLE     "winvnc4.exe.manifest"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_ABOUT, DIALOG
+    BEGIN
+        LEFTMARGIN, 5
+        VERTGUIDE, 45
+        VERTGUIDE, 170
+        VERTGUIDE, 195
+        VERTGUIDE, 242
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 85
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 40
+        HORZGUIDE, 55
+        HORZGUIDE, 70
+    END
+
+    IDD_QUERY_CONNECT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 157
+        VERTGUIDE, 35
+        VERTGUIDE, 40
+        VERTGUIDE, 60
+        VERTGUIDE, 120
+        VERTGUIDE, 125
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 86
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 30
+        HORZGUIDE, 45
+        HORZGUIDE, 50
+        HORZGUIDE, 65
+    END
+
+    IDD_ADD_NEW_CLIENT, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 170
+        VERTGUIDE, 45
+        VERTGUIDE, 75
+        VERTGUIDE, 80
+        VERTGUIDE, 120
+        VERTGUIDE, 125
+        VERTGUIDE, 170
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 45
+        HORZGUIDE, 10
+        HORZGUIDE, 25
+        HORZGUIDE, 30
+        HORZGUIDE, 45
+    END
+
+    IDD_CONTROL_PANEL, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 260
+        VERTGUIDE, 13
+        VERTGUIDE, 124
+        VERTGUIDE, 144
+        VERTGUIDE, 255
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 231
+        HORZGUIDE, 121
+        HORZGUIDE, 135
+        HORZGUIDE, 145
+        HORZGUIDE, 159
+        HORZGUIDE, 181
+        HORZGUIDE, 191
+        HORZGUIDE, 204
+        HORZGUIDE, 217
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP              BITMAP  DISCARDABLE     "winvnc.bmp"
+#endif    // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/win/winvnc/winvnc4.exe.manifest b/win/winvnc/winvnc4.exe.manifest
new file mode 100644 (file)
index 0000000..69be5a0
--- /dev/null
@@ -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.winvnc4.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/wm_hooks/resource.h b/win/wm_hooks/resource.h
new file mode 100644 (file)
index 0000000..0d8f646
--- /dev/null
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by wm_hooks.rc
+//
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/win/wm_hooks/wm_hooks.cxx b/win/wm_hooks/wm_hooks.cxx
new file mode 100644 (file)
index 0000000..fd01159
--- /dev/null
@@ -0,0 +1,465 @@
+/* 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.
+ */
+
+// -=- wm_hooks.cxx
+//
+// Window Message Hooks Dynamic Link library
+
+#include <tchar.h>
+
+#include <wm_hooks/wm_hooks.h>
+
+UINT WM_HK_PingThread = RegisterWindowMessage(_T("RFB.WM_Hooks.PingThread"));
+
+UINT WM_HK_WindowChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowChanged"));
+UINT WM_Hooks_WindowChanged() {
+  return WM_HK_WindowChanged;
+}
+
+UINT WM_HK_WindowClientAreaChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowClientAreaChanged"));
+UINT WM_Hooks_WindowClientAreaChanged() {
+  return WM_HK_WindowClientAreaChanged;
+}
+
+UINT WM_HK_WindowBorderChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowBorderChanged"));
+UINT WM_Hooks_WindowBorderChanged() {
+  return WM_HK_WindowBorderChanged;
+}
+
+UINT WM_HK_RectangleChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.RectangleChanged"));
+UINT WM_Hooks_RectangleChanged() {
+  return WM_HK_RectangleChanged;
+}
+
+UINT WM_HK_CursorChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.CursorChanged"));
+UINT WM_Hooks_CursorChanged() {
+  return WM_HK_CursorChanged;
+}
+
+#ifdef _DEBUG
+UINT WM_HK_Diagnostic = RegisterWindowMessage(_T("RFB.WM_Hooks.Diagnostic"));
+UINT WM_Hooks_Diagnostic() {
+  return WM_HK_Diagnostic;
+}
+#endif
+
+ATOM ATOM_Popup_Selection = GlobalAddAtom(_T("RFB.WM_Hooks.PopupSelectionAtom"));
+
+//
+// -=- DLL entry point
+//
+
+HINSTANCE dll_instance = 0;
+
+BOOL WINAPI DllMain(HANDLE instance, ULONG reason, LPVOID reserved) {
+  switch (reason) {
+  case DLL_PROCESS_ATTACH:
+    dll_instance = (HINSTANCE)instance;
+    return TRUE;
+  case DLL_PROCESS_DETACH:
+    return TRUE;
+  case DLL_THREAD_DETACH:
+    WM_Hooks_Remove(GetCurrentThreadId());
+    return TRUE;
+  default:
+    return TRUE;
+  };
+}
+
+//
+// -=- Display update hooks
+//
+
+#pragma data_seg(".WM_Hooks_Shared")
+DWORD hook_owner = 0;
+DWORD hook_target = 0;
+HHOOK hook_CallWndProc = 0;
+HHOOK hook_CallWndProcRet = 0;
+HHOOK hook_GetMessage = 0;
+HHOOK hook_DialogMessage = 0;
+BOOL enable_cursor_shape = FALSE;
+HCURSOR cursor = 0;
+#ifdef _DEBUG
+UINT diagnostic_min=1;
+UINT diagnostic_max=0;
+#endif
+#pragma data_seg()
+
+#ifdef _DEBUG
+DLLEXPORT void WM_Hooks_SetDiagnosticRange(UINT min, UINT max) {
+  diagnostic_min = min; diagnostic_max=max;
+}
+#endif
+
+bool NotifyHookOwner(UINT event, WPARAM wParam, LPARAM lParam) {
+  if (hook_owner) {
+    return PostThreadMessage(hook_owner, event, wParam, lParam)!=0;
+    /*
+    if (last_event)
+      return PostThreadMessage(hook_owner, last_event, last_wParam, last_lParam);
+    last_event = event;
+    last_wParam = wParam;
+    last_lParam = lParam;
+    return true;
+    */
+  }
+  return false;
+}
+
+bool NotifyWindow(HWND hwnd, UINT msg) {
+  return NotifyHookOwner(WM_HK_WindowChanged, msg, (LPARAM)hwnd);
+}
+bool NotifyWindowBorder(HWND hwnd, UINT msg) {
+  return NotifyHookOwner(WM_HK_WindowBorderChanged, msg, (LPARAM)hwnd);
+}
+bool NotifyWindowClientArea(HWND hwnd, UINT msg) {
+  return NotifyHookOwner(WM_HK_WindowClientAreaChanged, msg, (LPARAM)hwnd);
+}
+bool NotifyRectangle(RECT* rect) {
+  WPARAM w = MAKELONG((SHORT)rect->left, (SHORT)rect->top);
+  LPARAM l = MAKELONG((SHORT)rect->right, (SHORT)rect->bottom);
+  return NotifyHookOwner(WM_HK_RectangleChanged, w, l);
+}
+bool NotifyCursor(HCURSOR cursor) {
+  return NotifyHookOwner(WM_HK_CursorChanged, 0, (LPARAM)cursor);
+}
+
+void ProcessWindowMessage(UINT msg, HWND wnd, WPARAM wParam, LPARAM lParam) {
+#ifdef _DEBUG
+  if ((msg >= diagnostic_min) && (msg <= diagnostic_max))
+    PostThreadMessage(hook_owner, WM_HK_Diagnostic, msg, (LPARAM)wnd);
+#endif
+  if (!IsWindowVisible(wnd)) return;
+  switch (msg) {
+
+    // -=- Border update events
+       case WM_NCPAINT:
+       case WM_NCACTIVATE:
+    NotifyWindowBorder(wnd, msg);
+               break;
+
+    // -=- Client area update events
+       case BM_SETCHECK:
+       case BM_SETSTATE:
+       case EM_SETSEL:
+       case WM_CHAR:
+       case WM_ENABLE:
+       case WM_KEYUP:
+       case WM_LBUTTONUP:
+       case WM_MBUTTONUP:
+       case WM_PALETTECHANGED:
+       case WM_RBUTTONUP:
+       case WM_SYSCOLORCHANGE:
+       case WM_SETTEXT:
+  case WM_SETFOCUS:
+       //case WM_TIMER:
+    NotifyWindowClientArea(wnd, msg);
+    break;
+       case WM_HSCROLL:
+       case WM_VSCROLL:
+               if (((int) LOWORD(wParam) == SB_THUMBTRACK) || ((int) LOWORD(wParam) == SB_ENDSCROLL))
+                       NotifyWindow(wnd, msg);
+               break;
+
+       case WM_WINDOWPOSCHANGING:
+  case WM_DESTROY:
+    {
+      RECT wrect;
+      if (GetWindowRect(wnd, &wrect)) {
+        NotifyRectangle(&wrect);
+      }
+    }
+    break;
+
+  case WM_WINDOWPOSCHANGED:
+    NotifyWindow(wnd, msg);
+    break;
+
+       case WM_PAINT:
+    // *** could improve this
+    NotifyWindowClientArea(wnd, msg);
+    break;
+
+    // Handle pop-up menus appearing
+  case 482:
+    NotifyWindow(wnd, 482);
+    break;
+
+    // Handle pop-up menus having items selected
+       case 485:
+               {
+                       HANDLE prop = GetProp(wnd, (LPCTSTR) MAKELONG(ATOM_Popup_Selection, 0));
+      if (prop != (HANDLE) wParam) {
+        NotifyWindow(wnd, 485);
+                               SetProp(wnd,
+                                       (LPCTSTR) MAKELONG(ATOM_Popup_Selection, 0),
+                                       (HANDLE) wParam);
+                       }
+               }
+               break;
+
+  case WM_NCMOUSEMOVE:
+  case WM_MOUSEMOVE:
+    if (enable_cursor_shape) {
+      HCURSOR new_cursor = GetCursor();
+      if (new_cursor != cursor) {
+        cursor = new_cursor;
+        NotifyCursor(cursor);
+      }
+    }
+    break;
+
+    /* ***
+               if (prf_use_GetUpdateRect)
+               {
+                       HRGN region;
+                       region = CreateRectRgn(0, 0, 0, 0);
+
+                       // Get the affected region
+                       if (GetUpdateRgn(hWnd, region, FALSE) != ERROR)
+                       {
+                               int buffsize;
+                               UINT x;
+                               RGNDATA *buff;
+                               POINT TopLeft;
+
+                               // Get the top-left point of the client area
+                               TopLeft.x = 0;
+                               TopLeft.y = 0;
+                               if (!ClientToScreen(hWnd, &TopLeft))
+                                       break;
+
+                               // Get the size of buffer required
+                               buffsize = GetRegionData(region, 0, 0);
+                               if (buffsize != 0)
+                               {
+                                       buff = (RGNDATA *) new BYTE [buffsize];
+                                       if (buff == NULL)
+                                               break;
+
+                                       // Now get the region data
+                                       if(GetRegionData(region, buffsize, buff))
+                                       {
+                                               for (x=0; x<(buff->rdh.nCount); x++)
+                                               {
+                                                       // Obtain the rectangles from the list
+                                                       RECT *urect = (RECT *) (((BYTE *) buff) + sizeof(RGNDATAHEADER) + (x * sizeof(RECT)));
+                                                       SendDeferredUpdateRect(
+                                                               hWnd,
+                                                               (SHORT) (TopLeft.x + urect->left),
+                                                               (SHORT) (TopLeft.y + urect->top),
+                                                               (SHORT) (TopLeft.x + urect->right),
+                                                               (SHORT) (TopLeft.y + urect->bottom)
+                                                               );
+                                               }
+                                       }
+
+                                       delete [] buff;
+                               }
+                       }
+
+                       // Now free the region
+                       if (region != NULL)
+                               DeleteObject(region);
+               }
+    */
+  };
+}
+
+LRESULT CALLBACK HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
+  if (nCode == HC_ACTION) {
+    CWPSTRUCT* info = (CWPSTRUCT*) lParam;
+    ProcessWindowMessage(info->message, info->hwnd, info->wParam, info->lParam);
+  }
+  return CallNextHookEx(hook_CallWndProc, nCode, wParam, lParam);
+}
+
+LRESULT CALLBACK HookCallWndProcRet(int nCode, WPARAM wParam, LPARAM lParam) {
+  if (nCode == HC_ACTION) {
+    CWPRETSTRUCT* info = (CWPRETSTRUCT*) lParam;
+    ProcessWindowMessage(info->message, info->hwnd, info->wParam, info->lParam);
+  }
+  return CallNextHookEx(hook_CallWndProcRet, nCode, wParam, lParam);
+}
+
+LRESULT CALLBACK HookGetMessage(int nCode, WPARAM wParam, LPARAM lParam) {
+  if (nCode == HC_ACTION) {
+    if (wParam & PM_REMOVE) {
+      MSG* msg = (MSG*) lParam;
+      ProcessWindowMessage(msg->message, msg->hwnd, msg->wParam, msg->lParam);
+    }
+  }
+  return CallNextHookEx(hook_GetMessage, nCode, wParam, lParam);
+}
+
+LRESULT CALLBACK HookDialogMessage(int nCode, WPARAM wParam, LPARAM lParam) {
+  if (nCode == HC_ACTION) {
+    MSG* msg = (MSG*) lParam;
+    ProcessWindowMessage(msg->message, msg->hwnd, msg->wParam, msg->lParam);
+  }
+  return CallNextHookEx(hook_DialogMessage, nCode, wParam, lParam);
+}
+
+// - WM_Hooks_Install
+
+BOOL WM_Hooks_Install(DWORD owner, DWORD thread) {
+  // - Are there already hooks set?
+  if (hook_owner) {
+    if (!PostThreadMessage(hook_owner, WM_HK_PingThread, 0, 0)) {
+      WM_Hooks_Remove(hook_owner);
+    } else {
+      return FALSE;
+    }
+  }
+
+  // - Initialise the hooks
+  hook_owner = owner;
+  hook_target = thread;
+
+  hook_CallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, HookCallWndProc, dll_instance, thread);
+  hook_CallWndProcRet = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProcRet, dll_instance, thread);
+  hook_GetMessage = SetWindowsHookEx(WH_GETMESSAGE, HookGetMessage, dll_instance, thread);
+  hook_DialogMessage = SetWindowsHookEx(WH_SYSMSGFILTER, HookDialogMessage, dll_instance, thread);
+
+  if (!hook_CallWndProc /*|| !hook_CallWndProcRet*/ || !hook_GetMessage || !hook_DialogMessage) {
+    WM_Hooks_Remove(owner);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+// - WM_Hooks_Remove
+
+BOOL WM_Hooks_Remove(DWORD owner) {
+  if (owner != hook_owner) return FALSE;
+  if (hook_CallWndProc) {
+    UnhookWindowsHookEx(hook_CallWndProc);
+    hook_CallWndProc = 0;
+  }
+  if (hook_CallWndProcRet) {
+    UnhookWindowsHookEx(hook_CallWndProcRet);
+    hook_CallWndProcRet = 0;
+  }
+  if (hook_GetMessage) {
+    UnhookWindowsHookEx(hook_GetMessage);
+    hook_GetMessage = 0;
+  }
+  if (hook_DialogMessage) {
+    UnhookWindowsHookEx(hook_DialogMessage);
+    hook_DialogMessage = 0;
+  }
+  hook_owner = 0;
+  hook_target = 0;
+  return TRUE;
+}
+
+//
+// -=- User input hooks
+//
+
+#pragma data_seg(".WM_Hooks_Shared")
+HHOOK hook_keyboard = 0;
+HHOOK hook_pointer = 0;
+bool enable_real_ptr = true;
+bool enable_synth_ptr = true;
+bool enable_real_kbd = true;
+bool enable_synth_kbd = true;
+#pragma data_seg()
+
+#ifdef WH_KEYBOARD_LL
+LRESULT CALLBACK HookKeyboardHook(int nCode, WPARAM wParam, LPARAM lParam) {
+  if (nCode >= 0) {
+    KBDLLHOOKSTRUCT* info = (KBDLLHOOKSTRUCT*) lParam;
+    bool real_event = (info->flags & LLKHF_INJECTED) == 0;
+    if ((real_event && !enable_real_kbd) ||
+      (!real_event && !enable_synth_kbd)) {
+      return 1;
+    }
+  }
+  return CallNextHookEx(hook_keyboard, nCode, wParam, lParam);
+}
+
+LRESULT CALLBACK HookPointerHook(int nCode, WPARAM wParam, LPARAM lParam) {
+  if (nCode >= 0) {
+    MSLLHOOKSTRUCT* info = (MSLLHOOKSTRUCT*) lParam;
+    bool real_event = (info->flags & LLMHF_INJECTED) == 0;
+    if ((real_event && !enable_real_ptr) ||
+      (!real_event && !enable_synth_ptr)) {
+      return 1;
+    }
+  }
+  return CallNextHookEx(hook_keyboard, nCode, wParam, lParam);
+}
+
+bool RefreshInputHooks() {
+  bool success = true;
+  bool set_ptr_hook = !enable_real_ptr || !enable_synth_ptr;
+  bool set_kbd_hook = !enable_real_kbd || !enable_synth_kbd;
+  if (hook_keyboard && !set_kbd_hook) {
+    UnhookWindowsHookEx(hook_keyboard);
+    hook_keyboard = 0;
+  }
+  if (hook_pointer && !set_ptr_hook) {
+    UnhookWindowsHookEx(hook_pointer);
+    hook_pointer = 0;
+  }
+  if (!hook_keyboard && set_kbd_hook) {
+    hook_keyboard = SetWindowsHookEx(WH_KEYBOARD_LL, HookKeyboardHook, dll_instance, 0);
+    if (!hook_keyboard) success = false;
+  }
+  if (!hook_pointer && set_ptr_hook) {
+    hook_pointer = SetWindowsHookEx(WH_MOUSE_LL, HookPointerHook, dll_instance, 0);
+    if (!hook_pointer) success = false;
+  }
+  return success;
+}
+#else
+#pragma message("  NOTE: low-level mouse and keyboard hooks not supported")
+#endif
+
+// - WM_Hooks_EnableRealInputs
+
+BOOL WM_Hooks_EnableRealInputs(BOOL pointer, BOOL keyboard) {
+#ifdef WH_KEYBOARD_LL
+  enable_real_ptr = pointer!=0;
+  enable_real_kbd = keyboard!=0;
+  return RefreshInputHooks();
+#else
+  return FALSE;
+#endif
+}
+
+// - WM_Hooks_EnableSynthInputs
+
+BOOL WM_Hooks_EnableSynthInputs(BOOL pointer, BOOL keyboard) {
+#ifdef WH_KEYBOARD_LL
+  enable_synth_ptr = pointer!=0;
+  enable_synth_kbd = keyboard!=0;
+  return RefreshInputHooks();
+#else
+  return FALSE;
+#endif
+}
+
+// - WM_Hooks_EnableCursorShape
+
+BOOL WM_Hooks_EnableCursorShape(BOOL enable) {
+  enable_cursor_shape = enable;
+  return TRUE;
+}
diff --git a/win/wm_hooks/wm_hooks.def b/win/wm_hooks/wm_hooks.def
new file mode 100644 (file)
index 0000000..b9198ab
--- /dev/null
@@ -0,0 +1,5 @@
+LIBRARY      "wm_hooks"
+DESCRIPTION  'Window Message Hooks Dynamic Link Library'
+
+SECTIONS
+       .WM_Hooks_Shared read write shared
diff --git a/win/wm_hooks/wm_hooks.dsp b/win/wm_hooks/wm_hooks.dsp
new file mode 100644 (file)
index 0000000..65e4b86
--- /dev/null
@@ -0,0 +1,149 @@
+# Microsoft Developer Studio Project File - Name="wm_hooks" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=wm_hooks - Win32 Debug Unicode\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "wm_hooks.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "wm_hooks.mak" CFG="wm_hooks - Win32 Debug Unicode"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "wm_hooks - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "wm_hooks - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "wm_hooks - Win32 Debug Unicode" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "wm_hooks - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "../Release"\r
+# PROP Intermediate_Dir "..\Release\wm_hooks"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /FI"../../common/rdr/msvcwarning.h" /D "NDEBUG" /D "_MBCS" /D "_WINDOWS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /D "WIN32" /YX /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "wm_hooks - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "../Debug"\r
+# PROP Intermediate_Dir "..\Debug\wm_hooks"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"../../common/rdr/msvcwarning.h" /D "_DEBUG" /D "_MBCS" /D "_WINDOWS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /D "WIN32" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept\r
+# SUBTRACT LINK32 /profile\r
+\r
+!ELSEIF  "$(CFG)" == "wm_hooks - Win32 Debug Unicode"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "wm_hooks___Win32_Debug_Unicode"\r
+# PROP BASE Intermediate_Dir "wm_hooks___Win32_Debug_Unicode"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug_Unicode"\r
+# PROP Intermediate_Dir "..\Debug_Unicode\wm_hooks"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"../../common/rdr/msvcwarning.h" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_WINDOWS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /D "WIN32" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "wm_hooks - Win32 Release"\r
+# Name "wm_hooks - Win32 Debug"\r
+# Name "wm_hooks - Win32 Debug Unicode"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\wm_hooks.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\wm_hooks.def\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\wm_hooks.rc\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\wm_hooks.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win/wm_hooks/wm_hooks.h b/win/wm_hooks/wm_hooks.h
new file mode 100644 (file)
index 0000000..f65412e
--- /dev/null
@@ -0,0 +1,102 @@
+/* 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.
+ */
+
+// -=- wm_hooks.h
+//
+// Window Message Hooks Dynamic Link library
+//
+// This interface is used by the WMHooks class in rfb_win32 to hook the
+// windows on the desktop and receive notifications of changes in their
+// state.
+
+#ifndef __WM_HOOKS_H__
+#define __WM_HOOKS_H__
+
+#include <windows.h>
+
+#define DLLEXPORT __declspec(dllexport)
+
+extern "C"
+{
+  //
+  // -=- Display hook message types
+  //
+
+  DLLEXPORT UINT WM_Hooks_WindowChanged();
+  DLLEXPORT UINT WM_Hooks_WindowBorderChanged();
+  DLLEXPORT UINT WM_Hooks_WindowClientAreaChanged();
+  DLLEXPORT UINT WM_Hooks_RectangleChanged();
+  DLLEXPORT UINT WM_Hooks_CursorChanged();
+
+  //
+  // -=- Display update hooks
+  //
+
+  // - WM_Hooks_Install
+  // Add the current thread to the list of threads that will receive
+  // notifications of changes to the display.
+  // If thread is NULL then the entire display will be hooked.
+  // If thread is !NULL and then the specified
+  // thread will be hooked.
+  // Each thread may only register one hook at a time.
+  // The call will fail (return FALSE) if the thread already has hooks
+  // set, or if the hooks cannot be set, or some other error occurs.
+
+  DLLEXPORT BOOL WM_Hooks_Install(DWORD owner, DWORD thread);
+
+  // - WM_Hooks_Remove
+  // Removes any hook set by the current thread.
+  // The return indicates whether anything went wrong removing the hooks,
+  // that might cause problems later.
+
+  DLLEXPORT BOOL WM_Hooks_Remove(DWORD owner);
+
+  //
+  // -=- User input hooks
+  //
+
+  // - WM_Hooks_EnableRealInputs
+  // If TRUE is passed, then "real" input is enabled, otherwise it is disabled.
+
+  DLLEXPORT BOOL WM_Hooks_EnableRealInputs(BOOL pointer, BOOL keyboard);
+
+  // - WM_Hooks_EnableSynthInputs
+  // If TRUE is passed, then synthetic inputs are enabled, otherwise disabled.
+
+  DLLEXPORT BOOL WM_Hooks_EnableSynthInputs(BOOL pointer, BOOL keyboard);
+
+  //
+  // -=- Cursor shape hooking
+  //
+
+  // - WM_Hooks_EnableCursorShape
+  // If TRUE is passed, then hooks will produce notifications when cursor shape
+  // changes.
+
+  DLLEXPORT BOOL WM_Hooks_EnableCursorShape(BOOL enable);
+
+#ifdef _DEBUG
+  // - WM_Hooks_SetDiagnosticRange
+  // Select a range of messages that will be reported while hooks are active
+  DLLEXPORT void WM_Hooks_SetDiagnosticRange(UINT min, UINT max);
+  DLLEXPORT UINT WM_Hooks_Diagnostic();
+#endif
+
+}
+
+#endif // __WM_HOOKS_H__
diff --git a/win/wm_hooks/wm_hooks.rc b/win/wm_hooks/wm_hooks.rc
new file mode 100644 (file)
index 0000000..3f171d2
--- /dev/null
@@ -0,0 +1,109 @@
+//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
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,1,0,0
+ PRODUCTVERSION 4,1,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "080904b0"
+        BEGIN
+            VALUE "Comments", "\0"
+            VALUE "CompanyName", "Constantin Kaplinsky\0"
+            VALUE "FileDescription", "TightVNC Server Hooking DLL for Win32\0"
+            VALUE "FileVersion", "4.1\0"
+            VALUE "InternalName", "\0"
+            VALUE "LegalCopyright", "Copyright (C) 1998-2005 [many holders]\0"
+            VALUE "LegalTrademarks", "TightVNC\0"
+            VALUE "OriginalFilename", "wm_hooks.dll\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "TightVNC Server\0"
+            VALUE "ProductVersion", "4.1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x809, 1200
+    END
+END
+
+#endif    // !_MAC
+
+#endif    // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+