summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:12:25 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:12:25 +0000
commit729598cb00d791bbdfe23ebe0023d3a1c3962f83 (patch)
treeffe1b87705a0541998b8d7c44ea75dc4702dc515 /win
parentb30ae7facbdf8273f34f5d67d3d2e9c81db75576 (diff)
downloadtigervnc-729598cb00d791bbdfe23ebe0023d3a1c3962f83.tar.gz
tigervnc-729598cb00d791bbdfe23ebe0023d3a1c3962f83.zip
Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@591 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'win')
-rw-r--r--win/README.txt128
-rw-r--r--win/README_BINARY.txt126
-rw-r--r--win/logmessages/logmessages.dsp202
-rw-r--r--win/logmessages/messages.h47
-rw-r--r--win/logmessages/messages.mc7
-rw-r--r--win/logmessages/messages.rc2
-rw-r--r--win/rfb_win32/AboutDialog.cxx49
-rw-r--r--win/rfb_win32/AboutDialog.h55
-rw-r--r--win/rfb_win32/BitmapInfo.h48
-rw-r--r--win/rfb_win32/CKeyboard.cxx258
-rw-r--r--win/rfb_win32/CKeyboard.h51
-rw-r--r--win/rfb_win32/CPointer.cxx186
-rw-r--r--win/rfb_win32/CPointer.h74
-rw-r--r--win/rfb_win32/CleanDesktop.cxx321
-rw-r--r--win/rfb_win32/CleanDesktop.h57
-rw-r--r--win/rfb_win32/Clipboard.cxx200
-rw-r--r--win/rfb_win32/Clipboard.h66
-rw-r--r--win/rfb_win32/CompatibleBitmap.h46
-rw-r--r--win/rfb_win32/ComputerName.h40
-rw-r--r--win/rfb_win32/CurrentUser.cxx152
-rw-r--r--win/rfb_win32/CurrentUser.h100
-rw-r--r--win/rfb_win32/DIBSectionBuffer.cxx222
-rw-r--r--win/rfb_win32/DIBSectionBuffer.h85
-rw-r--r--win/rfb_win32/DeviceContext.cxx188
-rw-r--r--win/rfb_win32/DeviceContext.h86
-rw-r--r--win/rfb_win32/DeviceFrameBuffer.cxx289
-rw-r--r--win/rfb_win32/DeviceFrameBuffer.h106
-rw-r--r--win/rfb_win32/Dialog.cxx391
-rw-r--r--win/rfb_win32/Dialog.h158
-rw-r--r--win/rfb_win32/DynamicFn.cxx45
-rw-r--r--win/rfb_win32/DynamicFn.h51
-rw-r--r--win/rfb_win32/EventManager.cxx103
-rw-r--r--win/rfb_win32/EventManager.h77
-rw-r--r--win/rfb_win32/FolderManager.cxx279
-rw-r--r--win/rfb_win32/FolderManager.h66
-rw-r--r--win/rfb_win32/Handle.h43
-rw-r--r--win/rfb_win32/IconInfo.h44
-rw-r--r--win/rfb_win32/IntervalTimer.h70
-rw-r--r--win/rfb_win32/LaunchProcess.cxx103
-rw-r--r--win/rfb_win32/LaunchProcess.h71
-rw-r--r--win/rfb_win32/ListViewControl.cxx103
-rw-r--r--win/rfb_win32/ListViewControl.h35
-rw-r--r--win/rfb_win32/LocalMem.h45
-rw-r--r--win/rfb_win32/LogicalPalette.h90
-rw-r--r--win/rfb_win32/LowLevelKeyEvents.cxx96
-rw-r--r--win/rfb_win32/LowLevelKeyEvents.h49
-rw-r--r--win/rfb_win32/ModuleFileName.h40
-rw-r--r--win/rfb_win32/MonitorInfo.cxx205
-rw-r--r--win/rfb_win32/MonitorInfo.h72
-rw-r--r--win/rfb_win32/MsgBox.h63
-rw-r--r--win/rfb_win32/MsgWindow.cxx116
-rw-r--r--win/rfb_win32/MsgWindow.h53
-rw-r--r--win/rfb_win32/OSVersion.cxx47
-rw-r--r--win/rfb_win32/OSVersion.h53
-rw-r--r--win/rfb_win32/ProgressControl.cxx97
-rw-r--r--win/rfb_win32/ProgressControl.h56
-rw-r--r--win/rfb_win32/RegConfig.cxx114
-rw-r--r--win/rfb_win32/RegConfig.h84
-rw-r--r--win/rfb_win32/Registry.cxx316
-rw-r--r--win/rfb_win32/Registry.h112
-rw-r--r--win/rfb_win32/SDisplay.cxx524
-rw-r--r--win/rfb_win32/SDisplay.h163
-rw-r--r--win/rfb_win32/SDisplayCoreDriver.h52
-rw-r--r--win/rfb_win32/SDisplayCorePolling.cxx81
-rw-r--r--win/rfb_win32/SDisplayCorePolling.h75
-rw-r--r--win/rfb_win32/SDisplayCoreWMHooks.cxx74
-rw-r--r--win/rfb_win32/SDisplayCoreWMHooks.h68
-rw-r--r--win/rfb_win32/SFileTransferManagerWin32.cxx71
-rw-r--r--win/rfb_win32/SFileTransferManagerWin32.h48
-rw-r--r--win/rfb_win32/SFileTransferWin32.cxx125
-rw-r--r--win/rfb_win32/SFileTransferWin32.h59
-rw-r--r--win/rfb_win32/SInput.cxx466
-rw-r--r--win/rfb_win32/SInput.h68
-rw-r--r--win/rfb_win32/ScaledDIBSectionBuffer.cxx124
-rw-r--r--win/rfb_win32/ScaledDIBSectionBuffer.h78
-rw-r--r--win/rfb_win32/Security.cxx192
-rw-r--r--win/rfb_win32/Security.h123
-rw-r--r--win/rfb_win32/Service.cxx645
-rw-r--r--win/rfb_win32/Service.h128
-rw-r--r--win/rfb_win32/SocketManager.cxx213
-rw-r--r--win/rfb_win32/SocketManager.h90
-rw-r--r--win/rfb_win32/TCharArray.cxx85
-rw-r--r--win/rfb_win32/TCharArray.h135
-rw-r--r--win/rfb_win32/Threading.cxx151
-rw-r--r--win/rfb_win32/Threading.h154
-rw-r--r--win/rfb_win32/ToolBar.cxx216
-rw-r--r--win/rfb_win32/ToolBar.h132
-rw-r--r--win/rfb_win32/TrayIcon.h89
-rw-r--r--win/rfb_win32/TsSessions.cxx93
-rw-r--r--win/rfb_win32/TsSessions.h61
-rw-r--r--win/rfb_win32/WMCursor.cxx104
-rw-r--r--win/rfb_win32/WMCursor.h61
-rw-r--r--win/rfb_win32/WMHooks.cxx394
-rw-r--r--win/rfb_win32/WMHooks.h92
-rw-r--r--win/rfb_win32/WMNotifier.cxx57
-rw-r--r--win/rfb_win32/WMNotifier.h68
-rw-r--r--win/rfb_win32/WMPoller.cxx85
-rw-r--r--win/rfb_win32/WMPoller.h62
-rw-r--r--win/rfb_win32/WMShatter.cxx57
-rw-r--r--win/rfb_win32/WMShatter.h50
-rw-r--r--win/rfb_win32/WMWindowCopyRect.cxx67
-rw-r--r--win/rfb_win32/WMWindowCopyRect.h53
-rw-r--r--win/rfb_win32/Win32Util.cxx114
-rw-r--r--win/rfb_win32/Win32Util.h55
-rw-r--r--win/rfb_win32/keymap.h149
-rw-r--r--win/rfb_win32/rfb_win32.dsp513
-rw-r--r--win/rfbplayer/ChoosePixelFormatDialog.h59
-rw-r--r--win/rfbplayer/EditPixelFormatDialog.h104
-rw-r--r--win/rfbplayer/FbsInputStream.cxx251
-rw-r--r--win/rfbplayer/FbsInputStream.h68
-rw-r--r--win/rfbplayer/GotoPosDialog.h44
-rw-r--r--win/rfbplayer/InfoDialog.h41
-rw-r--r--win/rfbplayer/OptionsDialog.h112
-rw-r--r--win/rfbplayer/PixelFormatList.cxx159
-rw-r--r--win/rfbplayer/PixelFormatList.h85
-rw-r--r--win/rfbplayer/PlayerOptions.cxx152
-rw-r--r--win/rfbplayer/PlayerOptions.h77
-rw-r--r--win/rfbplayer/PlayerToolBar.cxx248
-rw-r--r--win/rfbplayer/PlayerToolBar.h77
-rw-r--r--win/rfbplayer/RfbProto.cxx142
-rw-r--r--win/rfbplayer/RfbProto.h69
-rw-r--r--win/rfbplayer/SessionInfoDialog.h100
-rw-r--r--win/rfbplayer/UserPixelFormatsDialog.h105
-rw-r--r--win/rfbplayer/buildTime.cxx1
-rw-r--r--win/rfbplayer/resource.h81
-rw-r--r--win/rfbplayer/rfbSessionReader.h59
-rw-r--r--win/rfbplayer/rfbplayer.cxx1294
-rw-r--r--win/rfbplayer/rfbplayer.dsp207
-rw-r--r--win/rfbplayer/rfbplayer.h195
-rw-r--r--win/rfbplayer/rfbplayer.icobin0 -> 766 bytes
-rw-r--r--win/rfbplayer/rfbplayer.rc466
-rw-r--r--win/rfbplayer/toolbar.bmpbin0 -> 630 bytes
-rw-r--r--win/vnc.dsw248
-rw-r--r--win/vncconfig/Authentication.h142
-rw-r--r--win/vncconfig/Connections.h298
-rw-r--r--win/vncconfig/Desktop.h94
-rw-r--r--win/vncconfig/Hooking.h88
-rw-r--r--win/vncconfig/Inputs.h84
-rw-r--r--win/vncconfig/Legacy.cxx248
-rw-r--r--win/vncconfig/Legacy.h85
-rw-r--r--win/vncconfig/PasswordDialog.cxx52
-rw-r--r--win/vncconfig/PasswordDialog.h40
-rw-r--r--win/vncconfig/Sharing.h59
-rw-r--r--win/vncconfig/resource.h102
-rw-r--r--win/vncconfig/vncconfig.cxx191
-rw-r--r--win/vncconfig/vncconfig.dsp196
-rw-r--r--win/vncconfig/vncconfig.exe.manifest22
-rw-r--r--win/vncconfig/vncconfig.icobin0 -> 1078 bytes
-rw-r--r--win/vncconfig/vncconfig.rc496
-rw-r--r--win/vncviewer/CConn.cxx712
-rw-r--r--win/vncviewer/CConn.h165
-rw-r--r--win/vncviewer/CConnOptions.cxx450
-rw-r--r--win/vncviewer/CConnOptions.h97
-rw-r--r--win/vncviewer/CConnThread.cxx198
-rw-r--r--win/vncviewer/CConnThread.h57
-rw-r--r--win/vncviewer/ConnectingDialog.cxx160
-rw-r--r--win/vncviewer/ConnectingDialog.h65
-rw-r--r--win/vncviewer/ConnectionDialog.cxx79
-rw-r--r--win/vncviewer/ConnectionDialog.h52
-rw-r--r--win/vncviewer/DesktopWindow.cxx1103
-rw-r--r--win/vncviewer/DesktopWindow.h254
-rw-r--r--win/vncviewer/FTBrowseDlg.cxx196
-rw-r--r--win/vncviewer/FTBrowseDlg.h70
-rw-r--r--win/vncviewer/FTDialog.cxx1162
-rw-r--r--win/vncviewer/FTDialog.h243
-rw-r--r--win/vncviewer/FTListView.cxx211
-rw-r--r--win/vncviewer/FTListView.h69
-rw-r--r--win/vncviewer/FTProgress.cxx151
-rw-r--r--win/vncviewer/FTProgress.h66
-rw-r--r--win/vncviewer/FileTransfer.cxx803
-rw-r--r--win/vncviewer/FileTransfer.h136
-rw-r--r--win/vncviewer/InfoDialog.cxx65
-rw-r--r--win/vncviewer/InfoDialog.h48
-rw-r--r--win/vncviewer/ListenServer.h56
-rw-r--r--win/vncviewer/ListenTrayIcon.h95
-rw-r--r--win/vncviewer/MRU.h133
-rw-r--r--win/vncviewer/OptionsDialog.cxx337
-rw-r--r--win/vncviewer/OptionsDialog.h48
-rw-r--r--win/vncviewer/UserPasswdDialog.cxx85
-rw-r--r--win/vncviewer/UserPasswdDialog.h58
-rw-r--r--win/vncviewer/ViewerToolBar.cxx117
-rw-r--r--win/vncviewer/ViewerToolBar.h38
-rw-r--r--win/vncviewer/buildTime.cxx18
-rw-r--r--win/vncviewer/cursor1.curbin0 -> 326 bytes
-rw-r--r--win/vncviewer/ftdir.icobin0 -> 318 bytes
-rw-r--r--win/vncviewer/ftfile.icobin0 -> 318 bytes
-rw-r--r--win/vncviewer/ftreload.icobin0 -> 318 bytes
-rw-r--r--win/vncviewer/ftup.icobin0 -> 318 bytes
-rw-r--r--win/vncviewer/resource.h154
-rw-r--r--win/vncviewer/toolbar.bmpbin0 -> 1654 bytes
-rw-r--r--win/vncviewer/vncviewer.bmpbin0 -> 2006 bytes
-rw-r--r--win/vncviewer/vncviewer.cxx295
-rw-r--r--win/vncviewer/vncviewer.dsp321
-rw-r--r--win/vncviewer/vncviewer.exe.manifest22
-rw-r--r--win/vncviewer/vncviewer.icobin0 -> 1078 bytes
-rw-r--r--win/vncviewer/vncviewer.rc708
-rw-r--r--win/winvnc/AddNewClientDialog.h56
-rw-r--r--win/winvnc/ControlPanel.cxx161
-rw-r--r--win/winvnc/ControlPanel.h45
-rw-r--r--win/winvnc/JavaViewer.cxx98
-rw-r--r--win/winvnc/JavaViewer.h55
-rw-r--r--win/winvnc/ManagedListener.cxx94
-rw-r--r--win/winvnc/ManagedListener.h57
-rw-r--r--win/winvnc/QueryConnectDialog.cxx100
-rw-r--r--win/winvnc/QueryConnectDialog.h60
-rw-r--r--win/winvnc/STrayIcon.cxx280
-rw-r--r--win/winvnc/STrayIcon.h61
-rw-r--r--win/winvnc/VNCServerService.cxx52
-rw-r--r--win/winvnc/VNCServerService.h41
-rw-r--r--win/winvnc/VNCServerWin32.cxx333
-rw-r--r--win/winvnc/VNCServerWin32.h130
-rw-r--r--win/winvnc/buildTime.cxx18
-rw-r--r--win/winvnc/connecte.icobin0 -> 766 bytes
-rw-r--r--win/winvnc/connected.icobin0 -> 1078 bytes
-rw-r--r--win/winvnc/icon_dis.icobin0 -> 766 bytes
-rw-r--r--win/winvnc/resource.h54
-rw-r--r--win/winvnc/winvnc.bmpbin0 -> 2018 bytes
-rw-r--r--win/winvnc/winvnc.cxx262
-rw-r--r--win/winvnc/winvnc.dsp252
-rw-r--r--win/winvnc/winvnc.icobin0 -> 1078 bytes
-rw-r--r--win/winvnc/winvnc.rc328
-rw-r--r--win/winvnc/winvnc4.exe.manifest22
-rw-r--r--win/wm_hooks/resource.h15
-rw-r--r--win/wm_hooks/wm_hooks.cxx465
-rw-r--r--win/wm_hooks/wm_hooks.def5
-rw-r--r--win/wm_hooks/wm_hooks.dsp149
-rw-r--r--win/wm_hooks/wm_hooks.h102
-rw-r--r--win/wm_hooks/wm_hooks.rc109
228 files changed, 32244 insertions, 0 deletions
diff --git a/win/README.txt b/win/README.txt
new file mode 100644
index 00000000..a834b21e
--- /dev/null
+++ b/win/README.txt
@@ -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
index 00000000..4c77e027
--- /dev/null
+++ b/win/README_BINARY.txt
@@ -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
index 00000000..06ed8c4f
--- /dev/null
+++ b/win/logmessages/logmessages.dsp
@@ -0,0 +1,202 @@
+# Microsoft Developer Studio Project File - Name="logmessages" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=logmessages - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "logmessages.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "logmessages.mak" CFG="logmessages - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "logmessages - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "logmessages - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "logmessages - Win32 Debug Unicode" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "logmessages - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\logmessages"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "LOGMESSAGES_EXPORTS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 /nologo /dll /machine:I386 /out:"messages.mc"
+# Begin Custom Build
+InputPath=.\messages.mc
+SOURCE="$(InputPath)"
+
+BuildCmds= \
+ mc messages.mc \
+ rc -r -fo messages.res messages.rc \
+ link -dll -noentry -out:..\Release\logmessages.dll messages.res \
+
+
+"messages.res" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"messages.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"messages.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"..\Release\logmessages.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "logmessages - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../Debug"
+# PROP Intermediate_Dir "..\Debug\logmessages"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# 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
+# 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
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /out:"messages.mc" /pdbtype:sept
+# Begin Custom Build
+InputPath=.\messages.mc
+SOURCE="$(InputPath)"
+
+BuildCmds= \
+ mc messages.mc \
+ rc -r -fo messages.res messages.rc \
+ link -dll -noentry -out:..\Debug\logmessages.dll messages.res \
+
+
+"messages.res" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"messages.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"messages.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"..\Debug\logmessages.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "logmessages - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "logmessages___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "logmessages___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 1
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\logmessages"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# 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
+# 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
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /out:"messages.mc" /pdbtype:sept
+# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib /out:"messages.mc" /pdbtype:sept
+# Begin Custom Build
+InputPath=.\messages.mc
+SOURCE="$(InputPath)"
+
+BuildCmds= \
+ mc messages.mc \
+ rc -r -fo messages.res messages.rc \
+ link -dll -noentry -out:..\Debug_Unicode\logmessages.dll messages.res \
+
+
+"messages.res" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"messages.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"messages.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"..\Debug_Unicode\logmessages.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+# End Custom Build
+
+!ENDIF
+
+# Begin Target
+
+# Name "logmessages - Win32 Release"
+# Name "logmessages - Win32 Debug"
+# Name "logmessages - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=.\messages.mc
+# End Source File
+# End Target
+# End Project
diff --git a/win/logmessages/messages.h b/win/logmessages/messages.h
new file mode 100644
index 00000000..bfb8c56d
--- /dev/null
+++ b/win/logmessages/messages.h
@@ -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
index 00000000..0bc8329e
--- /dev/null
+++ b/win/logmessages/messages.mc
@@ -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
index 00000000..0885a897
--- /dev/null
+++ b/win/logmessages/messages.rc
@@ -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
index 00000000..030be1b3
--- /dev/null
+++ b/win/rfb_win32/AboutDialog.cxx
@@ -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
index 00000000..0dd9d494
--- /dev/null
+++ b/win/rfb_win32/AboutDialog.h
@@ -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
index 00000000..6a6f0d24
--- /dev/null
+++ b/win/rfb_win32/BitmapInfo.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#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
index 00000000..28aceab7
--- /dev/null
+++ b/win/rfb_win32/CKeyboard.cxx
@@ -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
index 00000000..666ebce5
--- /dev/null
+++ b/win/rfb_win32/CKeyboard.h
@@ -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
index 00000000..3d0d9342
--- /dev/null
+++ b/win/rfb_win32/CPointer.cxx
@@ -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
index 00000000..b5916010
--- /dev/null
+++ b/win/rfb_win32/CPointer.h
@@ -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
index 00000000..39cca119
--- /dev/null
+++ b/win/rfb_win32/CleanDesktop.cxx
@@ -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
index 00000000..22e246fa
--- /dev/null
+++ b/win/rfb_win32/CleanDesktop.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- 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
index 00000000..a4c43f04
--- /dev/null
+++ b/win/rfb_win32/Clipboard.cxx
@@ -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
index 00000000..b79768f6
--- /dev/null
+++ b/win/rfb_win32/Clipboard.h
@@ -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
index 00000000..4beed8dc
--- /dev/null
+++ b/win/rfb_win32/CompatibleBitmap.h
@@ -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
index 00000000..110caa59
--- /dev/null
+++ b/win/rfb_win32/ComputerName.h
@@ -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
index 00000000..7562d29b
--- /dev/null
+++ b/win/rfb_win32/CurrentUser.cxx
@@ -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
index 00000000..794f27c6
--- /dev/null
+++ b/win/rfb_win32/CurrentUser.h
@@ -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
index 00000000..18ce3ea4
--- /dev/null
+++ b/win/rfb_win32/DIBSectionBuffer.cxx
@@ -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
index 00000000..ad1a310c
--- /dev/null
+++ b/win/rfb_win32/DIBSectionBuffer.h
@@ -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
index 00000000..4f70a1bf
--- /dev/null
+++ b/win/rfb_win32/DeviceContext.cxx
@@ -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
index 00000000..9d91cec2
--- /dev/null
+++ b/win/rfb_win32/DeviceContext.h
@@ -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
index 00000000..8da894e0
--- /dev/null
+++ b/win/rfb_win32/DeviceFrameBuffer.cxx
@@ -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
index 00000000..7718c339
--- /dev/null
+++ b/win/rfb_win32/DeviceFrameBuffer.h
@@ -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
index 00000000..398334f0
--- /dev/null
+++ b/win/rfb_win32/Dialog.cxx
@@ -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
index 00000000..9784ba46
--- /dev/null
+++ b/win/rfb_win32/Dialog.h
@@ -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
index 00000000..e933f249
--- /dev/null
+++ b/win/rfb_win32/DynamicFn.cxx
@@ -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
index 00000000..57fdbec5
--- /dev/null
+++ b/win/rfb_win32/DynamicFn.h
@@ -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
index 00000000..0f9993b7
--- /dev/null
+++ b/win/rfb_win32/EventManager.cxx
@@ -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
index 00000000..bb66e340
--- /dev/null
+++ b/win/rfb_win32/EventManager.h
@@ -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
index 00000000..a2fa08d3
--- /dev/null
+++ b/win/rfb_win32/FolderManager.cxx
@@ -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
index 00000000..24923dd6
--- /dev/null
+++ b/win/rfb_win32/FolderManager.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- 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
index 00000000..d3baa580
--- /dev/null
+++ b/win/rfb_win32/Handle.h
@@ -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
index 00000000..cb33a42d
--- /dev/null
+++ b/win/rfb_win32/IconInfo.h
@@ -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
index 00000000..ddfae493
--- /dev/null
+++ b/win/rfb_win32/IntervalTimer.h
@@ -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
index 00000000..56a712e6
--- /dev/null
+++ b/win/rfb_win32/LaunchProcess.cxx
@@ -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
index 00000000..38521dcd
--- /dev/null
+++ b/win/rfb_win32/LaunchProcess.h
@@ -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
index 00000000..12e04003
--- /dev/null
+++ b/win/rfb_win32/ListViewControl.cxx
@@ -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
index 00000000..8a163738
--- /dev/null
+++ b/win/rfb_win32/ListViewControl.h
@@ -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
index 00000000..a99d3241
--- /dev/null
+++ b/win/rfb_win32/LocalMem.h
@@ -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
index 00000000..204f1081
--- /dev/null
+++ b/win/rfb_win32/LogicalPalette.h
@@ -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
index 00000000..322d1f40
--- /dev/null
+++ b/win/rfb_win32/LowLevelKeyEvents.cxx
@@ -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
index 00000000..40d2ecfa
--- /dev/null
+++ b/win/rfb_win32/LowLevelKeyEvents.h
@@ -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
index 00000000..2264e89d
--- /dev/null
+++ b/win/rfb_win32/ModuleFileName.h
@@ -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
index 00000000..03772e97
--- /dev/null
+++ b/win/rfb_win32/MonitorInfo.cxx
@@ -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
index 00000000..acf27755
--- /dev/null
+++ b/win/rfb_win32/MonitorInfo.h
@@ -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
index 00000000..59571395
--- /dev/null
+++ b/win/rfb_win32/MsgBox.h
@@ -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
index 00000000..95bd5237
--- /dev/null
+++ b/win/rfb_win32/MsgWindow.cxx
@@ -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
index 00000000..92b6cf20
--- /dev/null
+++ b/win/rfb_win32/MsgWindow.h
@@ -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
index 00000000..3d74c956
--- /dev/null
+++ b/win/rfb_win32/OSVersion.cxx
@@ -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
index 00000000..18ec003e
--- /dev/null
+++ b/win/rfb_win32/OSVersion.h
@@ -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
index 00000000..85bd15f3
--- /dev/null
+++ b/win/rfb_win32/ProgressControl.cxx
@@ -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
index 00000000..ceeb153f
--- /dev/null
+++ b/win/rfb_win32/ProgressControl.h
@@ -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
index 00000000..dd1c3b06
--- /dev/null
+++ b/win/rfb_win32/RegConfig.cxx
@@ -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
index 00000000..e9c01b1d
--- /dev/null
+++ b/win/rfb_win32/RegConfig.h
@@ -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
index 00000000..4ece4bac
--- /dev/null
+++ b/win/rfb_win32/Registry.cxx
@@ -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
index 00000000..68d535cd
--- /dev/null
+++ b/win/rfb_win32/Registry.h
@@ -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
index 00000000..0af50649
--- /dev/null
+++ b/win/rfb_win32/SDisplay.cxx
@@ -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
index 00000000..6dbb50a5
--- /dev/null
+++ b/win/rfb_win32/SDisplay.h
@@ -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
index 00000000..5fea75cc
--- /dev/null
+++ b/win/rfb_win32/SDisplayCoreDriver.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- 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
index 00000000..fc57ecd0
--- /dev/null
+++ b/win/rfb_win32/SDisplayCorePolling.cxx
@@ -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
index 00000000..9e1b5ad1
--- /dev/null
+++ b/win/rfb_win32/SDisplayCorePolling.h
@@ -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
index 00000000..10b88e08
--- /dev/null
+++ b/win/rfb_win32/SDisplayCoreWMHooks.cxx
@@ -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
index 00000000..24fa5cdc
--- /dev/null
+++ b/win/rfb_win32/SDisplayCoreWMHooks.h
@@ -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
index 00000000..edc898be
--- /dev/null
+++ b/win/rfb_win32/SFileTransferManagerWin32.cxx
@@ -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
index 00000000..ed1f997a
--- /dev/null
+++ b/win/rfb_win32/SFileTransferManagerWin32.h
@@ -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
index 00000000..5aea4126
--- /dev/null
+++ b/win/rfb_win32/SFileTransferWin32.cxx
@@ -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
index 00000000..5f682a44
--- /dev/null
+++ b/win/rfb_win32/SFileTransferWin32.h
@@ -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
index 00000000..db59287a
--- /dev/null
+++ b/win/rfb_win32/SInput.cxx
@@ -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
index 00000000..2a0b3e67
--- /dev/null
+++ b/win/rfb_win32/SInput.h
@@ -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
index 00000000..e6c15b8e
--- /dev/null
+++ b/win/rfb_win32/ScaledDIBSectionBuffer.cxx
@@ -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
index 00000000..3cc267b2
--- /dev/null
+++ b/win/rfb_win32/ScaledDIBSectionBuffer.h
@@ -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
index 00000000..985f00cb
--- /dev/null
+++ b/win/rfb_win32/Security.cxx
@@ -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
index 00000000..1e2e9068
--- /dev/null
+++ b/win/rfb_win32/Security.h
@@ -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
index 00000000..2b11a22d
--- /dev/null
+++ b/win/rfb_win32/Service.cxx
@@ -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
index 00000000..00abe108
--- /dev/null
+++ b/win/rfb_win32/Service.h
@@ -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
index 00000000..1d52bc86
--- /dev/null
+++ b/win/rfb_win32/SocketManager.cxx
@@ -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
index 00000000..ef359749
--- /dev/null
+++ b/win/rfb_win32/SocketManager.h
@@ -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
index 00000000..fd4c0783
--- /dev/null
+++ b/win/rfb_win32/TCharArray.cxx
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <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
index 00000000..dde63b78
--- /dev/null
+++ b/win/rfb_win32/TCharArray.h
@@ -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
index 00000000..c41ac38b
--- /dev/null
+++ b/win/rfb_win32/Threading.cxx
@@ -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
index 00000000..850f04dd
--- /dev/null
+++ b/win/rfb_win32/Threading.h
@@ -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
index 00000000..6392ebdc
--- /dev/null
+++ b/win/rfb_win32/ToolBar.cxx
@@ -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
index 00000000..2242c2a4
--- /dev/null
+++ b/win/rfb_win32/ToolBar.h
@@ -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
index 00000000..dc5102a9
--- /dev/null
+++ b/win/rfb_win32/TrayIcon.h
@@ -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
index 00000000..efe75640
--- /dev/null
+++ b/win/rfb_win32/TsSessions.cxx
@@ -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
index 00000000..b15ada71
--- /dev/null
+++ b/win/rfb_win32/TsSessions.h
@@ -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
index 00000000..4d696cbc
--- /dev/null
+++ b/win/rfb_win32/WMCursor.cxx
@@ -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
index 00000000..41f9ee84
--- /dev/null
+++ b/win/rfb_win32/WMCursor.h
@@ -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
index 00000000..2d690538
--- /dev/null
+++ b/win/rfb_win32/WMHooks.cxx
@@ -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
index 00000000..4713b416
--- /dev/null
+++ b/win/rfb_win32/WMHooks.h
@@ -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
index 00000000..20a5445f
--- /dev/null
+++ b/win/rfb_win32/WMNotifier.cxx
@@ -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
index 00000000..a7609642
--- /dev/null
+++ b/win/rfb_win32/WMNotifier.h
@@ -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
index 00000000..f8505342
--- /dev/null
+++ b/win/rfb_win32/WMPoller.cxx
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- 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
index 00000000..851b69f4
--- /dev/null
+++ b/win/rfb_win32/WMPoller.h
@@ -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
index 00000000..e68abfb1
--- /dev/null
+++ b/win/rfb_win32/WMShatter.cxx
@@ -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
index 00000000..3ea63b1a
--- /dev/null
+++ b/win/rfb_win32/WMShatter.h
@@ -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
index 00000000..63c1da2e
--- /dev/null
+++ b/win/rfb_win32/WMWindowCopyRect.cxx
@@ -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
index 00000000..5a0e876d
--- /dev/null
+++ b/win/rfb_win32/WMWindowCopyRect.h
@@ -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
index 00000000..ef8039ab
--- /dev/null
+++ b/win/rfb_win32/Win32Util.cxx
@@ -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
index 00000000..8cc1a2b9
--- /dev/null
+++ b/win/rfb_win32/Win32Util.h
@@ -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
index 00000000..a340d09d
--- /dev/null
+++ b/win/rfb_win32/keymap.h
@@ -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
index 00000000..acfb5aaf
--- /dev/null
+++ b/win/rfb_win32/rfb_win32.dsp
@@ -0,0 +1,513 @@
+# Microsoft Developer Studio Project File - Name="rfb_win32" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=rfb_win32 - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "rfb_win32.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "rfb_win32.mak" CFG="rfb_win32 - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "rfb_win32 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "rfb_win32 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "rfb_win32 - Win32 Debug Unicode" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "rfb_win32 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\rfb_win32"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# 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
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "rfb_win32 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\rfb_win32"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# 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
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "rfb_win32 - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "rfb_win32___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "rfb_win32___Win32_Debug_Unicode"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\rfb_win32"
+# PROP Target_Dir ""
+# 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
+# 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
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "rfb_win32 - Win32 Release"
+# Name "rfb_win32 - Win32 Debug"
+# Name "rfb_win32 - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\AboutDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CKeyboard.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CleanDesktop.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Clipboard.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CPointer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CurrentUser.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\DeviceContext.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\DeviceFrameBuffer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Dialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\DIBSectionBuffer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\DynamicFn.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\EventManager.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FolderManager.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\LaunchProcess.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListViewControl.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\LowLevelKeyEvents.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\MonitorInfo.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\MsgWindow.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\OSVersion.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgressControl.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegConfig.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Registry.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ScaledDIBSectionBuffer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplay.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplayCorePolling.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplayCoreWMHooks.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Security.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Service.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransferManagerWin32.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransferWin32.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SInput.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SocketManager.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\TCharArray.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Threading.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ToolBar.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\TsSessions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Win32Util.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMCursor.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMHooks.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMNotifier.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMPoller.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMShatter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMWindowCopyRect.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\AboutDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\BitmapInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CKeyboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CleanDesktop.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Clipboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CompatibleBitmap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ComputerName.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CPointer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CurrentUser.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DeviceContext.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DeviceFrameBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DIBSectionBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DynamicFn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\EventManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FolderManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\IconInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\IntervalTimer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\keymap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LaunchProcess.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListViewControl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LocalMem.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LogicalPalette.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LowLevelKeyEvents.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ModuleFileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MonitorInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MsgBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MsgWindow.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OSVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgressControl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegConfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ScaledDIBSectionBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplay.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplayCoreDriver.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplayCorePolling.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDisplayCoreWMHooks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Security.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Service.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransferManagerWin32.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransferWin32.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SInput.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SocketManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TCharArray.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Threading.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ToolBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TrayIcon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TsSessions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Win32Util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMCursor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMHooks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMNotifier.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMPoller.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMShatter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\WMWindowCopyRect.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win/rfbplayer/ChoosePixelFormatDialog.h b/win/rfbplayer/ChoosePixelFormatDialog.h
new file mode 100644
index 00000000..ada820b3
--- /dev/null
+++ b/win/rfbplayer/ChoosePixelFormatDialog.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ChoosePixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class ChoosePixelFormatDialog : public rfb::win32::Dialog {
+public:
+ ChoosePixelFormatDialog(PixelFormatList *_supportedPF)
+ : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), combo(0) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_PIXELFORMAT), parent);
+ }
+ const long getPFIndex() const {return pfIndex;}
+ bool isBigEndian() {return isItemChecked(IDC_BIG_ENDIAN);}
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+ SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+ for (int i = 0; i < supportedPF->count(); i++) {
+ SendMessage(combo, CB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ SendMessage(combo, CB_SETCURSEL, pfIndex + 1, 0);
+ setItemChecked(IDC_BIG_ENDIAN, bigEndian);
+ }
+ virtual bool onOk() {
+ pfIndex = SendMessage(combo, CB_GETCURSEL, 0, 0) - 1;
+ bigEndian = isItemChecked(IDC_BIG_ENDIAN);
+ return true;
+ }
+ virtual bool onCancel() {
+ return false;
+ }
+ static long pfIndex;
+ static bool bigEndian;
+ PixelFormatList *supportedPF;
+ HWND combo;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/EditPixelFormatDialog.h b/win/rfbplayer/EditPixelFormatDialog.h
new file mode 100644
index 00000000..0765285d
--- /dev/null
+++ b/win/rfbplayer/EditPixelFormatDialog.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- EditPixelFormatDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+#define MAX_STR_LEN 256
+
+class EditPixelFormatDialog : public rfb::win32::Dialog {
+public:
+ EditPixelFormatDialog(PixelFormatList *_supportedPF, char *_format_name,
+ PixelFormat *_pf)
+ : Dialog(GetModuleHandle(0)), format_name(_format_name),
+ supportedPF(_supportedPF), pf(_pf) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_UPF_EDIT), parent);
+ }
+
+protected:
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ HWND bppCombo = GetDlgItem(handle, IDC_BPP_COMBO);
+ SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("8"));
+ SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("16"));
+ SendMessage(bppCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("32"));
+ SendMessage(bppCombo, CB_SETCURSEL, min(2, (pf->bpp - 8) / 8), 0);
+
+ HWND bigendianCombo = GetDlgItem(handle, IDC_BIGENDIAN_COMBO);
+ SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("No"));
+ SendMessage(bigendianCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Yes"));
+ SendMessage(bigendianCombo, CB_SETCURSEL, pf->bigEndian, 0);
+
+ setItemString(IDC_NAME_EDIT, format_name);
+ setItemInt(IDC_DEPTH_EDIT, pf->depth);
+ setItemInt(IDC_REDMAX_EDIT, pf->redMax);
+ setItemInt(IDC_GREENMAX_EDIT, pf->greenMax);
+ setItemInt(IDC_BLUEMAX_EDIT, pf->blueMax);
+ setItemInt(IDC_REDSHIFT_EDIT, pf->redShift);
+ setItemInt(IDC_GREENSHIFT_EDIT, pf->greenShift);
+ setItemInt(IDC_BLUESHIFT_EDIT, pf->blueShift);
+ }
+ virtual bool onOk() {
+ // Check for the errors
+ char err_msg[256] = "\0";
+ if (((getItemString(IDC_NAME_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_DEPTH_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_REDMAX_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_GREENMAX_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_BLUEMAX_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_REDSHIFT_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_GREENSHIFT_EDIT))[0] == '\0') ||
+ ((getItemString(IDC_BLUESHIFT_EDIT))[0] == '\0')) {
+ strcpy(err_msg, "Please fill the all fields in the dialog.");
+ }
+ int newIndex = supportedPF->getIndexByPFName(getItemString(IDC_NAME_EDIT));
+ if ((supportedPF->getIndexByPFName(format_name) != newIndex) &&
+ (newIndex != -1)) {
+ strcpy(err_msg, "The pixel format with that name is already exist.");
+ }
+ if (getItemInt(IDC_DEPTH_EDIT) <= 0) {
+ strcpy(err_msg, "The pixel depth must be larger than 0.");
+ }
+ if (err_msg[0] != 0) {
+ MessageBox(handle, err_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return false;
+ }
+ // Fill the pixel format structure
+ strCopy(format_name, getItemString(IDC_NAME_EDIT), MAX_STR_LEN);
+ pf->bpp = getItemInt(IDC_BPP_COMBO);
+ pf->depth = getItemInt(IDC_DEPTH_EDIT);
+ pf->bigEndian = (SendMessage(GetDlgItem(handle, IDC_BIGENDIAN_COMBO),
+ CB_GETCURSEL, 0, 0)) ? true : false;
+ pf->trueColour = true;
+ pf->redMax = getItemInt(IDC_REDMAX_EDIT);
+ pf->greenMax = getItemInt(IDC_GREENMAX_EDIT);
+ pf->blueMax = getItemInt(IDC_BLUEMAX_EDIT);
+ pf->redShift = getItemInt(IDC_REDSHIFT_EDIT);
+ pf->greenShift = getItemInt(IDC_GREENSHIFT_EDIT);
+ pf->blueShift = getItemInt(IDC_BLUESHIFT_EDIT);
+ return true;
+ }
+
+ char *format_name;
+ PixelFormatList *supportedPF;
+ PixelFormat *pf;
+};
diff --git a/win/rfbplayer/FbsInputStream.cxx b/win/rfbplayer/FbsInputStream.cxx
new file mode 100644
index 00000000..6381a166
--- /dev/null
+++ b/win/rfbplayer/FbsInputStream.cxx
@@ -0,0 +1,251 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- FbsInputStream class
+
+#include <windows.h>
+
+#include <rfb/Exception.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+FbsInputStream::FbsInputStream(char* FileName) {
+ bufferSize = 0;
+ ptr = end = start = NULL;
+
+ timeOffset = 0;
+ seekOffset = -1;
+ startTime = GetTickCount();
+
+ playbackSpeed = 1.0;
+ seekBackwards = false;
+ paused = false;
+
+ interruptDelay = false;
+
+ fbsFile = fopen(FileName, "rb");
+ if (fbsFile == NULL) {
+ char *msg = new char[12 + sizeof(FileName)];
+ strcpy(msg, "Can't open ");
+ strcat(msg, FileName);
+ throw rfb::Exception(msg);
+ }
+
+ U8 b[12];
+ readNByte(b, 12);
+
+ if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
+ b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
+ b[8] < '0' || b[8] > '9' || b[9] < '0' || b[9] > '9' ||
+ b[10] < '0' || b[10] > '9' || b[11] != '\n') {
+ throw rfb::Exception("Incorrect protocol version");
+ }
+}
+
+FbsInputStream::~FbsInputStream() {
+ if (start != NULL)
+ delete [] start;
+ ptr = end = start = NULL;
+ fclose(fbsFile);
+}
+
+int FbsInputStream::pos() {
+ return ptr - start;
+}
+
+//
+// Close FbsInputStream and free data buffer
+//
+
+void FbsInputStream::close() {
+ fclose(fbsFile);
+
+ startTime = -1;
+ timeOffset = 0;
+ seekOffset = -1;
+ seekBackwards = false;
+ paused = false;
+ playbackSpeed = 1.0;
+
+ if (start != NULL)
+ delete [] start;
+ ptr = end = start = NULL;
+ bufferSize = 0;
+}
+
+//
+// Fill data buffer from the session file (InStream::overrun() override)
+//
+
+int FbsInputStream::overrun(int itemSize, int nItems, bool wait=true) {
+ // Just wait unless we are performing playback OR seeking.
+ waitWhilePaused();
+
+ // Perform backwardSeek (throws the special exception)
+ if (seekBackwards) {
+ throw rfb::Exception("[REWIND]");
+ }
+
+ // Save a tail of data
+ U8 *tmp;
+ int n = end - ptr;
+ if (n) {
+ tmp = new U8[n];
+ memmove(tmp, ptr, n);
+ }
+
+ bufferSize = (int)readUnsigned32();
+ if (bufferSize >= 0) {
+ if (start != NULL)
+ delete [] start;
+ int realSize = (bufferSize + 3) & 0xFFFFFFFC; // padding to multiple of 32-bits
+ ptr = start = new U8[realSize + n];
+ end = ptr + bufferSize + n;
+ if (n) {
+ memmove(start, tmp, n);
+ delete [] tmp;
+ }
+ readNByte(start + n, realSize);
+ timeOffset = (long)(readUnsigned32() / playbackSpeed);
+
+ if (itemSize * nItems > bufferSize)
+ nItems = bufferSize / itemSize;
+ }
+
+ if (bufferSize < 0 || timeOffset < 0) {
+ if (start != NULL)
+ delete [] start;
+ ptr = end = start = NULL;
+ bufferSize = 0;
+ return 0;
+ }
+
+ if (seekOffset >= 0) {
+ if (timeOffset >= seekOffset) {
+ startTime = GetTickCount() - seekOffset;
+ seekOffset = -1;
+ } else {
+ return nItems;
+ }
+ }
+
+ while (!interruptDelay) {
+ long timeDiff = startTime + timeOffset - GetTickCount();
+ if (timeDiff <= 0) {
+ break;
+ }
+ Sleep(min(20, timeDiff));
+ waitWhilePaused();
+ }
+ interruptDelay = false;
+
+ return nItems;
+}
+
+int FbsInputStream::readUnsigned32() {
+ U8 buf[4];
+ if (!readNByte(buf, 4))
+ return -1;
+
+ return ((long)(buf[0] & 0xFF) << 24 |
+ (buf[1] & 0xFF) << 16 |
+ (buf[2] & 0xFF) << 8 |
+ (buf[3] & 0xFF));
+}
+
+//
+// Read n-bytes from the session file
+//
+
+bool FbsInputStream::readNByte(U8 b[], int n) {
+ int off = 0;
+
+ while (off != n) {
+ int count = fread(b, 1, n - off, fbsFile);
+ if (count < n) {
+ if (ferror(fbsFile))
+ throw rfb::Exception("Read error from session file");
+ if (feof(fbsFile))
+ throw rfb::Exception("[End Of File]");
+ }
+ off += count;
+ }
+ return true;
+}
+
+void FbsInputStream::waitWhilePaused() {
+ while (paused && !isSeeking()) {
+ // A small delay helps to decrease the cpu usage
+ Sleep(20);
+ }
+}
+
+void FbsInputStream::interruptFrameDelay() {
+ interruptDelay = true;
+}
+
+//
+// Methods providing additional functionality.
+//
+
+long FbsInputStream::getTimeOffset() {
+ //long off = max(seekOffset, timeOffset);
+ return (long)(timeOffset * playbackSpeed);
+}
+
+void FbsInputStream::setTimeOffset(long pos) {
+ seekOffset = (long)(pos / playbackSpeed);
+ if (seekOffset < timeOffset) {
+ seekBackwards = true;
+ }
+}
+
+void FbsInputStream::setSpeed(double newSpeed) {
+ long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
+ startTime += timeOffset - newOffset;
+ timeOffset = newOffset;
+ if (isSeeking()) {
+ seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
+ }
+ playbackSpeed = newSpeed;
+}
+
+double FbsInputStream::getSpeed() {
+ return playbackSpeed;
+}
+
+bool FbsInputStream::isSeeking() {
+ return (seekOffset >= 0);
+}
+
+long FbsInputStream::getSeekOffset() {
+ return (long)(seekOffset * playbackSpeed);
+}
+
+bool FbsInputStream::isPaused() {
+ return paused;
+}
+
+void FbsInputStream::pausePlayback() {
+ paused = true;
+}
+
+void FbsInputStream::resumePlayback() {
+ paused = false;
+ startTime = GetTickCount() - timeOffset;
+}
diff --git a/win/rfbplayer/FbsInputStream.h b/win/rfbplayer/FbsInputStream.h
new file mode 100644
index 00000000..96492739
--- /dev/null
+++ b/win/rfbplayer/FbsInputStream.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- FbsInputStream.h
+
+#include <rdr/InStream.h>
+
+using namespace rdr;
+
+class FbsInputStream : public InStream {
+ public:
+ FbsInputStream(char *FileName);
+ ~FbsInputStream();
+
+ // Methods are used to contol the Rfb Stream
+ long getTimeOffset();
+ void setTimeOffset(long pos);
+ double getSpeed();
+ void setSpeed(double newSpeed);
+ bool isSeeking();
+ long getSeekOffset();
+ bool isPaused();
+ void pausePlayback();
+ void resumePlayback();
+ void interruptFrameDelay();
+ void close();
+ int pos();
+
+ private:
+ U8 *start;
+ int bufferSize;
+ long startTime;
+ long timeOffset;
+ long seekOffset;
+ double playbackSpeed;
+ bool seekBackwards;
+ bool paused;
+ bool interruptDelay;
+
+ FILE *fbsFile;
+
+ // overrun() - overrides InStream::overrun().
+ // It is implemented to fill the data buffer from the session file.
+ // It ensures there are at least itemSize bytes of buffer data. Returns
+ // the number of items in the buffer (up to a maximum of nItems). itemSize
+ // is supposed to be "small" (a few bytes).
+
+ int overrun(int itemSize, int nItems, bool wait);
+
+ int readUnsigned32();
+ bool readNByte(U8 *b, int n);
+ void waitWhilePaused();
+};
diff --git a/win/rfbplayer/GotoPosDialog.h b/win/rfbplayer/GotoPosDialog.h
new file mode 100644
index 00000000..ddbbe53a
--- /dev/null
+++ b/win/rfbplayer/GotoPosDialog.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- GotoPosDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class GotoPosDialog : public rfb::win32::Dialog {
+public:
+ GotoPosDialog() : Dialog(GetModuleHandle(0)) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_GOTO), parent);
+ }
+ const long getPos() const {return pos;}
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ setItemString(IDC_GOTO_EDIT, rfb::TStr("0"));
+ }
+ virtual bool onOk() {
+ pos = atol(rfb::CStr(getItemString(IDC_GOTO_EDIT)));
+ return true;
+ }
+
+ long pos;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/InfoDialog.h b/win/rfbplayer/InfoDialog.h
new file mode 100644
index 00000000..bbe9b26f
--- /dev/null
+++ b/win/rfbplayer/InfoDialog.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- InfoDialog.h
+
+#include <rfb_win32/Dialog.h>
+
+class InfoDialog : public rfb::win32::Dialog {
+public:
+ InfoDialog(char *_info_message, char *_title = "Information")
+ : Dialog(GetModuleHandle(0)), info_message(_info_message), title(_title) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent = 0) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_INFO), parent);
+ }
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ SetWindowText(handle, title);
+ setItemString(IDC_INFO_EDIT, info_message);
+ }
+ char *info_message;
+ char *title;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/OptionsDialog.h b/win/rfbplayer/OptionsDialog.h
new file mode 100644
index 00000000..8c3a87d7
--- /dev/null
+++ b/win/rfbplayer/OptionsDialog.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- OptionsDialog.h
+
+#include <rfbplayer/PlayerOptions.h>
+#include <rfbplayer/UserPixelFormatsDialog.h>
+
+class OptionsDialog : public rfb::win32::Dialog {
+public:
+ OptionsDialog(PlayerOptions *_options, PixelFormatList *_supportedPF)
+ : Dialog(GetModuleHandle(0)), options(_options), combo(0),
+ supportedPF(_supportedPF) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_OPTIONS), parent);
+ }
+protected:
+
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ combo = GetDlgItem(handle, IDC_PIXELFORMAT);
+ SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+ for (int i = 0; i < supportedPF->count(); i++) {
+ SendMessage(combo, CB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ SendMessage(combo, CB_SETCURSEL, options->pixelFormatIndex + 1, 0);
+ setItemChecked(IDC_ACCEPT_BELL, options->acceptBell);
+ setItemChecked(IDC_ACCEPT_CUT_TEXT, options->acceptCutText);
+ setItemChecked(IDC_AUTOPLAY, options->autoPlay);
+ setItemChecked(IDC_BIG_ENDIAN, options->bigEndianFlag);
+ if (options->askPixelFormat) {
+ setItemChecked(IDC_ASK_PF, true);
+ enableItem(IDC_PIXELFORMAT, false);
+ enableItem(IDC_BIG_ENDIAN, false);
+ }
+ }
+ virtual bool onOk() {
+ options->askPixelFormat = isItemChecked(IDC_ASK_PF);
+ options->acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+ options->acceptCutText = isItemChecked(IDC_ACCEPT_CUT_TEXT);
+ options->autoPlay = isItemChecked(IDC_AUTOPLAY);
+ options->bigEndianFlag = isItemChecked(IDC_BIG_ENDIAN);
+ if (!options->askPixelFormat) {
+ options->pixelFormatIndex = int(SendMessage(combo, CB_GETCURSEL, 0, 0)) - 1;
+ if (options->pixelFormatIndex < 0) {
+ options->autoDetectPF = true;
+ } else {
+ options->setPF(&((*supportedPF)[options->pixelFormatIndex])->PF);
+ options->pixelFormat.bigEndian = options->bigEndianFlag;
+ options->autoDetectPF = false;
+ }
+ }
+ options->writeToRegistry();
+ return true;
+ }
+ virtual bool onCommand(int item, int cmd) {
+ if (item == IDC_ASK_PF) {
+ enableItem(IDC_PIXELFORMAT, !isItemChecked(IDC_ASK_PF));
+ enableItem(IDC_BIG_ENDIAN, !isItemChecked(IDC_ASK_PF));
+ }
+ if (item == IDC_DEFAULT) {
+ SendMessage(combo, CB_SETCURSEL, DEFAULT_PF_INDEX + 1, 0);
+ enableItem(IDC_PIXELFORMAT, !DEFAULT_ASK_PF);
+ enableItem(IDC_BIG_ENDIAN, !DEFAULT_ASK_PF);
+ setItemChecked(IDC_ASK_PF, DEFAULT_ASK_PF);
+ setItemChecked(IDC_ACCEPT_BELL, DEFAULT_ACCEPT_BELL);
+ setItemChecked(IDC_ACCEPT_CUT_TEXT, DEFAULT_ACCEPT_CUT_TEXT);
+ setItemChecked(IDC_AUTOPLAY, DEFAULT_AUTOPLAY);
+ setItemChecked(IDC_BIG_ENDIAN, DEFAULT_BIG_ENDIAN);
+ }
+ if (item == IDC_EDIT_UPF) {
+ UserPixelFormatsDialog UpfListDialog(supportedPF);
+ if (UpfListDialog.showDialog(handle)) {
+ int index = SendMessage(combo, CB_GETCURSEL, 0, 0);
+ SendMessage(combo, CB_RESETCONTENT, 0, 0);
+ SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)("Auto"));
+ for (int i = 0; i < supportedPF->count(); i++) {
+ SendMessage(combo, CB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ if ( index > (SendMessage(combo, CB_GETCOUNT, 0, 0) - 1)) {
+ index = SendMessage(combo, CB_GETCOUNT, 0, 0) - 1;
+ }
+ SendMessage(combo, CB_SETCURSEL, index, 0);
+ options->pixelFormatIndex = index - 1;
+ }
+ }
+ return false;
+ }
+
+ HWND combo;
+ PlayerOptions *options;
+ PixelFormatList *supportedPF;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.cxx b/win/rfbplayer/PixelFormatList.cxx
new file mode 100644
index 00000000..25996f65
--- /dev/null
+++ b/win/rfbplayer/PixelFormatList.cxx
@@ -0,0 +1,159 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PixelFormatList class
+
+#include <rfbplayer/PixelFormatList.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+PixelFormatList::PixelFormatList() {
+ PixelFormatListElement PFElem;
+
+ // -=- Add the default pixel formats to list
+ // PF_BGR233
+ PFElem.setName("8-bits depth (BGR233)");
+ PFElem.setPF(&PixelFormat(8,8,0,1,7,7,3,0,3,6));
+ PFList.push_back(PFElem);
+ // PF_RGB555
+ PFElem.setName("15-bits depth (RGB555)");
+ PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,10,5,0));
+ PFList.push_back(PFElem);
+ // PF_BGR555
+ PFElem.setName("15-bits depth (BGR555)");
+ PFElem.setPF(&PixelFormat(16,15,0,1,31,31,31,0,5,10));
+ PFList.push_back(PFElem);
+ // PF_RGB565
+ PFElem.setName("16-bits depth (RGB565)");
+ PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,11,5,0));
+ PFList.push_back(PFElem);
+ // PF_BGR565
+ PFElem.setName("16-bits depth (BGR565)");
+ PFElem.setPF(&PixelFormat(16,16,0,1,31,63,31,0,5,11));
+ PFList.push_back(PFElem);
+ // PF_RGB888
+ PFElem.setName("24-bits depth (RGB888)");
+ PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,16,8,0));
+ PFList.push_back(PFElem);
+ // PF_BGR888
+ PFElem.setName("24-bits depth (BGR888)");
+ PFElem.setPF(&PixelFormat(32,24,0,1,255,255,255,0,8,16));
+ PFList.push_back(PFElem);
+
+ PF_DEFAULT_COUNT = PFList.size();
+}
+
+PixelFormatListElement *PixelFormatList::operator[](int index) {
+ return &(*getIterator(index));
+}
+
+void PixelFormatList::add(char *format_name, PixelFormat PF) {
+ PixelFormatListElement PFElem;
+ PFElem.setName(format_name);
+ PFElem.setPF(&PF);
+ PFList.push_back(PFElem);
+}
+
+void PixelFormatList::insert(int index, char *format_name, PixelFormat PF) {
+ if (isDefaultPF(index))
+ rdr::Exception("PixelFormatList:can't insert to the default pixel format place");
+
+ PixelFormatListElement PFElem;
+ PFElem.setName(format_name);
+ PFElem.setPF(&PF);
+ PFList.insert(getIterator(index), PFElem);
+}
+
+void PixelFormatList::remove(int index) {
+ if (isDefaultPF(index))
+ rdr::Exception("PixelFormatList:can't remove the default pixel format");
+ PFList.erase(getIterator(index));
+}
+
+list <PixelFormatListElement>::iterator PixelFormatList::getIterator(int index) {
+ if ((index >= PFList.size()) || (index < 0))
+ rdr::Exception("PixelFormatList:out of range");
+
+ int i = 0;
+ list <PixelFormatListElement>::iterator iter;
+ for (iter = PFList.begin(); iter != PFList.end(); iter++) {
+ if (i++ == index) break;
+ }
+ return iter;
+}
+
+bool PixelFormatList::isDefaultPF(int index) {
+ if (index < PF_DEFAULT_COUNT) return true;
+ return false;
+}
+
+void PixelFormatList::readUserDefinedPF(HKEY root, const char *keypath) {
+ RegKey regKey;
+ regKey.createKey(root, keypath);
+ int count = regKey.getInt(_T("PixelFormatCount"), 0);
+ if (count > 0) {
+ // Erase all user defined pixel formats
+ int upf_count = getUserPFCount();
+ if (upf_count > 0) {
+ for(int i = 0; i < upf_count; i++) {
+ remove(PF_DEFAULT_COUNT);
+ }
+ }
+ // Add the user defined pixel formats from the registry
+ for(int i = 0; i < count; i++) {
+ char upf_name[20] = "\0";
+ sprintf(upf_name, "%s%i", "Upf", i);
+ int size = sizeof(PixelFormatListElement);
+ PixelFormatListElement *pPFElem = 0;// = &PFElem;
+ regKey.getBinary(upf_name, (void**)&pPFElem, &size);
+ PFList.push_back(*pPFElem);
+ if (pPFElem) delete pPFElem;
+ }
+ }
+}
+
+void PixelFormatList::writeUserDefinedPF(HKEY root, const char *keypath) {
+ RegKey regKey;
+
+ // Delete all user defined pixel formats from the regisry
+ regKey.createKey(root, keypath);//_T("Software\\TightVnc\\RfbPlayer\\UserDefinedPF"));
+ int count = regKey.getInt(_T("PixelFormatCount"), 0);
+ for (int i = 0; i < count; i++) {
+ char upf_name[20] = "\0";
+ sprintf(upf_name, "%s%i", "Upf", i);
+ regKey.deleteValue(upf_name);
+ }
+ regKey.setInt(_T("PixelFormatCount"), 0);
+
+ // Write new user defined pixel formats to the registry
+ regKey.setInt(_T("PixelFormatCount"), getUserPFCount());
+ for (i = 0; i < getUserPFCount(); i++) {
+ char upf_name[20] = "\0";
+ sprintf(upf_name, "%s%i", "Upf", i);
+ regKey.setBinary(upf_name, (void *)operator[](i+getDefaultPFCount()),
+ sizeof(PixelFormatListElement));
+ }
+}
+
+int PixelFormatList::getIndexByPFName(const char *format_name) {
+ for (int i = 0; i < PixelFormatList::count(); i++) {
+ if (_stricmp(operator[](i)->format_name, format_name) == 0) return i;
+ }
+ return -1;
+} \ No newline at end of file
diff --git a/win/rfbplayer/PixelFormatList.h b/win/rfbplayer/PixelFormatList.h
new file mode 100644
index 00000000..cd7c50aa
--- /dev/null
+++ b/win/rfbplayer/PixelFormatList.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PixelFormatList.h
+
+// Definition of the PixelFormatList class, responsible for
+// controlling the list of supported pixel formats.
+
+#include <list>
+
+#include <rfb/Exception.h>
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+// Definition indexes of the default pixel formats
+#define PF_BGR233 0
+#define PF_RGB555 1
+#define PF_BGR555 2
+#define PF_RGB565 3
+#define PF_BGR565 4
+#define PF_RGB888 5
+#define PF_BGR888 6
+
+using namespace rfb;
+using namespace std;
+
+// PixelFormatListElement class, it is
+// an item of the PixelFormatList list.
+
+class PixelFormatListElement {
+public:
+ PixelFormatListElement() {
+ format_name[0] = 0;
+ }
+ char format_name[256];
+ PixelFormat PF;
+ void setName(const char *name) {
+ format_name[0] = '\0';
+ strcpy(format_name, name);
+ format_name[strlen(name)] = '\0';
+ }
+ void setPF(PixelFormat *_PF) {
+ memcpy(&PF, _PF, sizeof(PixelFormat));
+ }
+};
+
+class PixelFormatList {
+public:
+ PixelFormatList();
+
+ PixelFormatListElement* operator[](int index);
+ void add(char *format_name, PixelFormat PF);
+ void insert(int index, char *format_name, PixelFormat PF);
+ void remove(int index);
+
+ void readUserDefinedPF(HKEY root, const char *keypath);
+ void writeUserDefinedPF(HKEY root, const char *keypath);
+
+ int count() { return PFList.size(); }
+ int getDefaultPFCount() { return PF_DEFAULT_COUNT; }
+ int getUserPFCount() { return max(0, count() - PF_DEFAULT_COUNT); }
+ int getIndexByPFName(const char *format_name);
+ bool isDefaultPF(int index);
+
+protected:
+ list <PixelFormatListElement>::iterator getIterator(int index);
+ list <PixelFormatListElement> PFList;
+ int PF_DEFAULT_COUNT;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.cxx b/win/rfbplayer/PlayerOptions.cxx
new file mode 100644
index 00000000..5384c6ed
--- /dev/null
+++ b/win/rfbplayer/PlayerOptions.cxx
@@ -0,0 +1,152 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PlayerOptions class
+
+#include <rfbplayer/PlayerOptions.h>
+
+using namespace rfb::win32;
+
+PlayerOptions::PlayerOptions() {
+ writeDefaults();
+};
+
+void PlayerOptions::readFromRegistry() {
+ try {
+ PixelFormat *pPF = 0;
+ int pfSize = sizeof(PixelFormat);
+ RegKey regKey;
+ regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+ autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+ autoDetectPF = regKey.getBool(_T("AutoDetectPixelFormat"), DEFAULT_AUTOPF);
+ bigEndianFlag = regKey.getBool(_T("BigEndianFlag"), DEFAULT_BIG_ENDIAN);
+ pixelFormatIndex = regKey.getInt(_T("PixelFormatIndex"), DEFAULT_PF_INDEX);
+ regKey.getBinary(_T("PixelFormat"), (void**)&pPF, &pfSize,
+ &PixelFormat(32,24,0,1,255,255,255,16,8,0), sizeof(PixelFormat));
+ setPF(pPF);
+ acceptBell = regKey.getBool(_T("AcceptBell"), DEFAULT_ACCEPT_BELL);
+ acceptCutText = regKey.getBool(_T("AcceptCutText"), DEFAULT_ACCEPT_CUT_TEXT);
+ autoPlay = regKey.getBool(_T("AutoPlay"), DEFAULT_AUTOPLAY);
+ askPixelFormat = regKey.getBool(_T("AskPixelFormat"), DEFAULT_ASK_PF);
+ if (pPF) delete pPF;
+ } catch (rdr::Exception e) {
+ MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+}
+
+void PlayerOptions::writeToRegistry() {
+ try {
+ RegKey regKey;
+ regKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVnc\\RfbPlayer"));
+ regKey.setBool(_T("AutoPlay"), autoPlay);
+ regKey.setBool(_T("AutoDetectPixelFormat"), autoDetectPF);
+ regKey.setBool(_T("BigEndianFlag"), bigEndianFlag);
+ regKey.setInt(_T("PixelFormatIndex"), pixelFormatIndex);
+ regKey.setBinary(_T("PixelFormat"), &pixelFormat, sizeof(PixelFormat));
+ regKey.setBool(_T("AcceptBell"), acceptBell);
+ regKey.setBool(_T("AcceptCutText"), acceptCutText);
+ regKey.setBool(_T("AutoPlay"), autoPlay);
+ regKey.setBool(_T("AskPixelFormat"), askPixelFormat);
+ } catch (rdr::Exception e) {
+ MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+}
+
+void PlayerOptions::writeDefaults() {
+ initTime = DEFAULT_INIT_TIME;
+ playbackSpeed = DEFAULT_SPEED;
+ autoDetectPF = DEFAULT_AUTOPF;
+ bigEndianFlag = DEFAULT_BIG_ENDIAN;
+ pixelFormatIndex = DEFAULT_PF_INDEX;
+ pixelFormat = PixelFormat(32,24,0,1,255,255,255,16,8,0);
+ frameScale = DEFAULT_FRAME_SCALE;
+ autoPlay = DEFAULT_AUTOPLAY;
+ fullScreen = DEFAULT_FULL_SCREEN;
+ acceptBell = DEFAULT_ACCEPT_BELL;
+ acceptCutText = DEFAULT_ACCEPT_CUT_TEXT;
+ loopPlayback = DEFAULT_LOOP_PLAYBACK;
+ askPixelFormat = DEFAULT_ASK_PF;
+ commandLineParam = false;
+}
+
+void PlayerOptions::setPF(PixelFormat *newPF) {
+ memcpy(&pixelFormat, newPF, sizeof(PixelFormat));
+}
+
+bool PlayerOptions::setPF(int rgb_order, int rm, int gm, int bm, bool big_endian) {
+ PixelFormat newPF;
+
+ // Calculate the colour bits per pixel
+ int bpp = rm + gm + bm;
+ if (bpp < 0) {
+ return false;
+ } else if (bpp <= 8 ) {
+ newPF.bpp = 8;
+ } else if (bpp <= 16) {
+ newPF.bpp = 16;
+ } else if (bpp <= 32) {
+ newPF.bpp = 32;
+ } else {
+ return false;
+ }
+ newPF.depth = bpp;
+
+ // Calculate the r, g and b bits shifts
+ switch (rgb_order) {
+ case RGB_ORDER:
+ newPF.redShift = gm + bm;
+ newPF.greenShift = bm;
+ newPF.blueShift = 0;
+ break;
+ case RBG_ORDER:
+ newPF.redShift = bm + gm;
+ newPF.blueShift = gm;
+ newPF.greenShift = 0;
+ break;
+ case GRB_ORDER:
+ newPF.greenShift = rm + bm;
+ newPF.redShift = bm;
+ newPF.blueShift = 0;
+ break;
+ case GBR_ORDER:
+ newPF.greenShift = bm + rm;
+ newPF.blueShift = rm;
+ newPF.redShift = 0;
+ break;
+ case BGR_ORDER:
+ newPF.blueShift = gm + rm;
+ newPF.greenShift = rm;
+ newPF.redShift = 0;
+ break;
+ case BRG_ORDER:
+ newPF.blueShift = rm + gm;
+ newPF.redShift = gm;
+ newPF.greenShift = 0;
+ break;
+ default:
+ return false;
+ }
+
+ newPF.trueColour = true;
+ newPF.bigEndian = big_endian;
+ newPF.redMax = (1 << rm) - 1;
+ newPF.greenMax = (1 << gm) - 1;
+ newPF.blueMax = (1 << bm) - 1;
+ setPF(&newPF);
+ return true;
+} \ No newline at end of file
diff --git a/win/rfbplayer/PlayerOptions.h b/win/rfbplayer/PlayerOptions.h
new file mode 100644
index 00000000..83618a75
--- /dev/null
+++ b/win/rfbplayer/PlayerOptions.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PlayerOptions.h
+
+// Definition of the PlayerOptions class, responsible for
+// storing & retrieving the RfbPlayer's options.
+
+#include <rfb/PixelFormat.h>
+
+#include <rfb_win32/registry.h>
+
+#define PF_MODES 3
+
+// The R, G and B values order in the pixel
+#define RGB_ORDER 0
+#define RBG_ORDER 1
+#define GRB_ORDER 2
+#define GBR_ORDER 3
+#define BGR_ORDER 4
+#define BRG_ORDER 5
+
+// Default options values
+//#define DEFAULT_PF 0
+#define DEFAULT_PF_INDEX -1
+#define DEFAULT_AUTOPF TRUE
+#define DEFAULT_INIT_TIME -1
+#define DEFAULT_SPEED 1.0
+#define DEFAULT_FRAME_SCALE 100
+#define DEFAULT_ACCEPT_BELL FALSE
+#define DEFAULT_ACCEPT_CUT_TEXT FALSE
+#define DEFAULT_BIG_ENDIAN FALSE
+#define DEFAULT_LOOP_PLAYBACK FALSE
+#define DEFAULT_ASK_PF FALSE
+#define DEFAULT_AUTOPLAY FALSE
+#define DEFAULT_FULL_SCREEN FALSE
+
+using namespace rfb;
+
+class PlayerOptions {
+public:
+ PlayerOptions();
+ void readFromRegistry();
+ void writeToRegistry();
+ void writeDefaults();
+ void setPF(PixelFormat *pf);
+ bool setPF(int rgb_order, int rm, int gm, int bm, bool big_endian=false);
+ long initTime;
+ double playbackSpeed;
+ bool autoPlay;
+ bool fullScreen;
+ bool autoDetectPF;
+ bool bigEndianFlag;
+ long pixelFormatIndex;
+ PixelFormat pixelFormat;
+ bool acceptBell;
+ bool acceptCutText;
+ bool loopPlayback;
+ bool askPixelFormat;
+ long frameScale;
+ bool commandLineParam;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.cxx b/win/rfbplayer/PlayerToolBar.cxx
new file mode 100644
index 00000000..3056f283
--- /dev/null
+++ b/win/rfbplayer/PlayerToolBar.cxx
@@ -0,0 +1,248 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PlayerToolBar.cxx
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/resource.h>
+
+PlayerToolBar::PlayerToolBar()
+: ToolBar(), hFont(0), timeStatic(0), speedEdit(0), posTrackBar(0),
+ speedUpDown(0), sliderDragging(false), sliderStepMs(0)
+{
+}
+
+void PlayerToolBar::create(RfbPlayer *player_, HWND parentHwnd_) {
+ HDC hdc;
+ SIZE sz;
+ RECT tRect;
+ NONCLIENTMETRICS nonClientMetrics;
+
+ player = player_;
+
+ // Get the default font for the main menu
+ nonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);
+ if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nonClientMetrics, 0))
+ MessageBox(0, "Can't access to the system font.",
+ "RfbPlayer", MB_OK | MB_ICONERROR);
+ nonClientMetrics.lfMenuFont.lfHeight = 16;
+ hFont = CreateFontIndirect(&nonClientMetrics.lfMenuFont);
+
+ // Create the toolbar panel
+ ToolBar::create(ID_TOOLBAR, parentHwnd_,
+ WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NORESIZE);
+ addBitmap(4, IDB_TOOLBAR);
+
+ // Create the control buttons
+ addButton(0, ID_PLAY);
+ addButton(1, ID_PAUSE);
+ addButton(2, ID_STOP);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+ // Create the static control for the time output
+ timeStatic = CreateWindowEx(0, "Static", "00m:00s (00m:00s)",
+ WS_CHILD | WS_VISIBLE, 0, 0, 20, 20, getHandle(), (HMENU)ID_TIME_STATIC,
+ GetModuleHandle(0), 0);
+ SendMessage(timeStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+ hdc = GetDC(timeStatic);
+ SelectObject(hdc, hFont);
+ GetTextExtentPoint32(hdc, "00m:00s (00m:00s)", 16, &sz);
+ addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(4, &tRect);
+ MoveWindow(timeStatic, tRect.left, tRect.top+2, tRect.right-tRect.left,
+ tRect.bottom-tRect.top, FALSE);
+
+ // Create the trackbar control for the time position
+ addButton(200, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(6, &tRect);
+ posTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, "Trackbar Control",
+ WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE,
+ tRect.left, tRect.top, tRect.right-tRect.left, tRect.bottom-tRect.top,
+ parentHwnd, (HMENU)ID_POS_TRACKBAR, GetModuleHandle(0), 0);
+ // It's need to send notify messages to toolbar parent window
+ SetParent(posTrackBar, getHandle());
+ addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
+
+ // Create the label with "Speed:" caption
+ HWND speedStatic = CreateWindowEx(0, "Static", "Speed:", WS_CHILD | WS_VISIBLE,
+ 0, 0, 5, 5, getHandle(), (HMENU)ID_SPEED_STATIC, GetModuleHandle(0), 0);
+ SendMessage(speedStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
+ hdc = GetDC(speedStatic);
+ SelectObject(hdc, hFont);
+ GetTextExtentPoint32(hdc, "Speed:", 6, &sz);
+ addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(8, &tRect);
+ MoveWindow(speedStatic, tRect.left, tRect.top+2, tRect.right-tRect.left,
+ tRect.bottom-tRect.top, FALSE);
+
+ // Create the edit control and the spin for the speed managing
+ addButton(60, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ getButtonRect(9, &tRect);
+ speedEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "1.00",
+ WS_CHILD | WS_VISIBLE | ES_RIGHT, tRect.left, tRect.top,
+ tRect.right-tRect.left, tRect.bottom-tRect.top, parentHwnd,
+ (HMENU)ID_SPEED_EDIT, GetModuleHandle(0), 0);
+ SendMessage(speedEdit, WM_SETFONT,(WPARAM) hFont, TRUE);
+ // It's need to send notify messages to toolbar parent window
+ SetParent(speedEdit, getHandle());
+
+ speedUpDown = CreateUpDownControl(WS_CHILD | WS_VISIBLE
+ | WS_BORDER | UDS_ALIGNRIGHT, 0, 0, 0, 0, getHandle(),
+ ID_SPEED_UPDOWN, GetModuleHandle(0), speedEdit, 20, 1, 2);
+
+ // Resize the toolbar window
+ autoSize();
+}
+
+void PlayerToolBar::init(long sessionTimeMs_) {
+ sessionTimeMs = sessionTimeMs_;
+
+ setSessionTimeStr(sessionTimeMs);
+ SendMessage(posTrackBar, TBM_SETRANGE,
+ TRUE, MAKELONG(0, min(sessionTimeMs / 1000, MAX_POS_TRACKBAR_RANGE)));
+ if (sessionTimeMs == 0) {
+ sliderStepMs = 1;
+ } else {
+ sliderStepMs = sessionTimeMs / SendMessage(posTrackBar, TBM_GETRANGEMAX, 0, 0);
+ }
+ updatePos(0);
+}
+
+void PlayerToolBar::enable() {
+ enableButton(ID_PLAY, true);
+ enableButton(ID_PAUSE, true);
+ enableButton(ID_STOP, true);
+ enableButton(ID_FULLSCREEN, true);
+ EnableWindow(posTrackBar, true);
+ EnableWindow(speedEdit, true);
+ EnableWindow(speedUpDown, true);
+}
+
+void PlayerToolBar::disable() {
+ enableButton(ID_PLAY, false);
+ enableButton(ID_PAUSE, false);
+ enableButton(ID_STOP, false);
+ enableButton(ID_FULLSCREEN, false);
+ EnableWindow(posTrackBar, false);
+ EnableWindow(speedEdit, false);
+ EnableWindow(speedUpDown, false);
+}
+
+LRESULT PlayerToolBar::processWM_COMMAND(WPARAM wParam, LPARAM lParam) {
+ switch (LOWORD(wParam)) {
+
+ case ID_RETURN:
+ // Update the speed if return pressed in speedEdit
+ if (getSpeedEditHwnd() == GetFocus()) {
+ char speedStr[20], *stopStr;
+ GetWindowText(getSpeedEditHwnd(), speedStr, sizeof(speedStr));
+ double speed = strtod(speedStr, &stopStr);
+ if (speed > 0) {
+ speed = min(MAX_SPEED, speed);
+ } else {
+ speed = player->getSpeed();
+ }
+ player->setSpeed(speed);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_HSCROLL(WPARAM wParam, LPARAM lParam) {
+ long Pos = SendMessage(posTrackBar, TBM_GETPOS, 0, 0);
+ Pos *= sliderStepMs;
+
+ switch (LOWORD(wParam)) {
+ case TB_PAGEUP:
+ case TB_PAGEDOWN:
+ case TB_LINEUP:
+ case TB_LINEDOWN:
+ case TB_THUMBTRACK:
+ sliderDragging = true;
+ updatePos(Pos);
+ return FALSE;
+ case TB_THUMBPOSITION:
+ case TB_ENDTRACK:
+ player->setPos(Pos);
+ player->setPaused(player->isPaused());;
+ updatePos(Pos);
+ sliderDragging = false;
+ return FALSE;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+LRESULT PlayerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+ switch (((NMHDR*)lParam)->code) {
+ case UDN_DELTAPOS:
+ if ((int)wParam == ID_SPEED_UPDOWN) {
+ char speedStr[20] = "\0";
+ DWORD speedRange = SendMessage(speedUpDown, UDM_GETRANGE, 0, 0);
+ LPNM_UPDOWN upDown = (LPNM_UPDOWN)lParam;
+ double speed;
+
+ // The out of range checking
+ if (upDown->iDelta > 0) {
+ speed = min(upDown->iPos + upDown->iDelta, LOWORD(speedRange)) * 0.5;
+ } else {
+ // It's need to round the UpDown position
+ if ((upDown->iPos * 0.5) != player->getSpeed()) {
+ upDown->iDelta = 0;
+ }
+ speed = max(upDown->iPos + upDown->iDelta, HIWORD(speedRange)) * 0.5;
+ }
+ player->setSpeed(speed);
+ }
+ }
+
+ // We always return TRUE to prevent the change in the updown contol
+ // position. The control's position changes in the RfbPlayer::setSpeed().
+ return TRUE;
+}
+
+void PlayerToolBar::updatePos(long newPos) {
+ // Update time pos in static control
+ char timePos[30] = "\0";
+ long time = newPos / 1000;
+ sprintf(timePos, "%.2um:%.2us (%s)", time/60, time%60, fullSessionTimeStr);
+ SetWindowText(timeStatic, timePos);
+
+ // Update the position of slider
+ if (!sliderDragging) {
+ double error = SendMessage(posTrackBar, TBM_GETPOS, 0, 0) *
+ sliderStepMs / double(newPos);
+ if (!((error > 1 - CALCULATION_ERROR) && (error <= 1 + CALCULATION_ERROR))) {
+ SendMessage(posTrackBar, TBM_SETPOS, TRUE, newPos / sliderStepMs);
+ }
+ }
+}
+
+void PlayerToolBar::setSessionTimeStr(long sessionTimeMs) {
+ sprintf(fullSessionTimeStr, "%.2um:%.2us",
+ sessionTimeMs / 1000 / 60, sessionTimeMs / 1000 % 60);
+}
+
+void PlayerToolBar::setTimePos(long pos) {
+ SendMessage(posTrackBar, TBM_SETPOS, TRUE, pos);
+} \ No newline at end of file
diff --git a/win/rfbplayer/PlayerToolBar.h b/win/rfbplayer/PlayerToolBar.h
new file mode 100644
index 00000000..17ab82e4
--- /dev/null
+++ b/win/rfbplayer/PlayerToolBar.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PlayerToolBar.h
+
+// ToolBar for the RfbPlayer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+#define ID_TOOLBAR 500
+#define ID_PLAY 510
+#define ID_PAUSE 520
+#define ID_TIME_STATIC 530
+#define ID_SPEED_STATIC 540
+#define ID_SPEED_EDIT 550
+#define ID_POS_TRACKBAR 560
+#define ID_SPEED_UPDOWN 570
+
+#define MAX_SPEED 10.00
+#define CALCULATION_ERROR MAX_SPEED / 1000
+#define MAX_POS_TRACKBAR_RANGE 50
+
+class RfbPlayer;
+
+class PlayerToolBar : public ToolBar {
+public:
+ PlayerToolBar();
+ ~PlayerToolBar() {}
+
+ void create(RfbPlayer *player, HWND parentHwnd);
+
+ void init(long sessionTimeMs);
+
+ void enable();
+ void disable();
+
+ LRESULT processWM_COMMAND(WPARAM wParam, LPARAM lParam);
+ LRESULT processWM_HSCROLL(WPARAM wParam, LPARAM lParam);
+ LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+ HWND getSpeedEditHwnd() { return speedEdit; }
+ HWND getSpeedUpDownHwnd() { return speedUpDown; }
+
+ bool isPosSliderDragging() { return sliderDragging; };
+ void updatePos(long newPos);
+ void setSessionTimeStr(long sessionTimeMs);
+ void setTimePos(long newPos);
+
+protected:
+ RfbPlayer *player;
+ HFONT hFont;
+ HWND timeStatic;
+ HWND speedEdit;
+ HWND posTrackBar;
+ HWND speedUpDown;
+ char fullSessionTimeStr[20];
+ long sessionTimeMs;
+ bool sliderDragging;
+ long sliderStepMs;
+};
diff --git a/win/rfbplayer/RfbProto.cxx b/win/rfbplayer/RfbProto.cxx
new file mode 100644
index 00000000..5a7ff7f9
--- /dev/null
+++ b/win/rfbplayer/RfbProto.cxx
@@ -0,0 +1,142 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- RFB Protocol
+
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+static LogWriter vlog("RfbProto");
+
+//
+// Constructor
+//
+
+RfbProto::RfbProto(char *fileName) {
+ is = NULL;
+ reader = NULL;
+ newSession(fileName);
+}
+
+//
+// Destructor
+//
+
+RfbProto::~RfbProto() {
+ if (is) delete is;
+ is = 0;
+ if (reader) delete reader;
+ reader = 0;
+}
+
+void RfbProto::newSession(char *fileName) {
+ // Close the previous session
+ if (is) {
+ delete is;
+ is = NULL;
+ delete reader;
+ reader = NULL;
+ }
+
+ // Begin the new session
+ if (fileName != NULL) {
+ is = new FbsInputStream(fileName);
+ reader = new CMsgReaderV3(this, is);
+ initialiseProtocol();
+ }
+}
+
+void RfbProto::initialiseProtocol() {
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void RfbProto::processMsg()
+{
+ switch (state_) {
+
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader->readMsg(); break;
+ default:
+ throw rfb::Exception("RfbProto::processMsg: invalid state");
+ }
+}
+
+void RfbProto::processVersionMsg()
+{
+ vlog.debug("reading protocol version");
+ memset(&cp, 0, sizeof(cp));
+ bool done;
+ if (!cp.readVersion(is, &done)) {
+ state_ = RFBSTATE_INVALID;
+ throw rfb::Exception("reading version failed: wrong file format?");
+ }
+ if (!done) return;
+
+ // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+ if (!cp.isVersion(3,3) && !cp.isVersion(3,7) && !cp.isVersion(3,8)) {
+ char msg[256];
+ sprintf(msg,"File have unsupported RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+ state_ = RFBSTATE_INVALID;
+ throw rfb::Exception(msg);
+ }
+
+ state_ = RFBSTATE_SECURITY;
+
+ vlog.info("Using RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+}
+
+void RfbProto::processSecurityMsg()
+{
+ vlog.debug("processing security types message");
+
+ int secType = secTypeInvalid;
+
+ // legacy 3.3 server may only offer "vnc authentication" or "none"
+ secType = is->readU32();
+ if (secType == secTypeInvalid) {
+ int reasonLen = is->readU32();
+ char *reason = new char[reasonLen];
+ is->readBytes(reason, reasonLen);
+ throw rfb::Exception(reason);
+ }
+
+ if (secType != secTypeNone) {
+ throw rfb::Exception("Wrong authentication type in the session file");
+ }
+
+ state_ = RFBSTATE_INITIALISATION;
+}
+
+void RfbProto::processInitMsg() {
+ vlog.debug("reading server initialisation");
+ reader->readServerInit();
+}
+
+void RfbProto::serverInit()
+{
+ state_ = RFBSTATE_NORMAL;
+ vlog.debug("initialisation done");
+}
diff --git a/win/rfbplayer/RfbProto.h b/win/rfbplayer/RfbProto.h
new file mode 100644
index 00000000..316ea269
--- /dev/null
+++ b/win/rfbplayer/RfbProto.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- RfbProto.h
+
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+
+#include <rfbplayer/FbsInputStream.h>
+
+using namespace rfb;
+
+class RfbProto : public CMsgHandler {
+ public:
+
+ RfbProto(char *fileName);
+ ~RfbProto();
+
+ void newSession(char *filename);
+ void initialiseProtocol();
+ void interruptFrameDelay() { is->interruptFrameDelay(); };
+ const rdr::InStream* getInStream() { return is; }
+
+ virtual void processMsg();
+
+ // serverInit() is called when the ServerInit message is received. The
+ // derived class must call on to CMsgHandler::serverInit().
+ void serverInit();
+
+ enum stateEnum {
+ RFBSTATE_PROTOCOL_VERSION,
+ RFBSTATE_SECURITY,
+ RFBSTATE_INITIALISATION,
+ RFBSTATE_NORMAL,
+ RFBSTATE_INVALID
+ };
+
+ stateEnum state() { return state_; }
+
+ protected:
+ void setState(stateEnum s) { state_ = s; }
+ virtual void framebufferUpdateEnd() {};
+
+ FbsInputStream* is;
+ CMsgReaderV3* reader;
+ stateEnum state_;
+
+ private:
+ void processVersionMsg();
+ void processSecurityMsg();
+ void processInitMsg();
+};
diff --git a/win/rfbplayer/SessionInfoDialog.h b/win/rfbplayer/SessionInfoDialog.h
new file mode 100644
index 00000000..2c036db0
--- /dev/null
+++ b/win/rfbplayer/SessionInfoDialog.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- SessionInfoDialog.h
+
+#include <math.h>
+
+#include <rfb/ConnParams.h>
+
+#include <rfb_win32/Dialog.h>
+
+#define log2(n) log(n) / 0.693147180559945
+
+int max3(int v1, int v2, int v3) {
+ return max(v1, max(v2, v3));
+}
+
+class SessionInfoDialog : public rfb::win32::Dialog {
+public:
+ SessionInfoDialog(ConnParams *_cp, int _currentEncoding)
+ : Dialog(GetModuleHandle(0)), cp(_cp), currentEncoding(_currentEncoding) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent = 0) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_SESSION_INFO), parent);
+ }
+protected:
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ char strValue[255] = "\0";
+ setItemString(IDC_DESKTOP_NAME, cp->name());
+
+ sprintf(strValue, "%ix%i", cp->width, cp->height);
+ setItemString(IDC_DESKTOP_SIZE, strValue);
+
+ int r = cp->pf().redShift, g = cp->pf().greenShift, b = cp->pf().blueShift;
+ int i = 3;
+ char buffer[10];
+ sprintf(strValue, "depth %i(%ibpp), ", cp->pf().depth, cp->pf().bpp);
+ while (i) {
+ if (r == max3(r, g, b)) {
+ strcat(strValue, "r");
+ _itoa(ceil(log2(cp->pf().redMax)), buffer, 10);
+ strcat(strValue, buffer);
+ r = -1;
+ i--;
+ continue;
+ } else if (g == max3(r, g, b)) {
+ strcat(strValue, "g");
+ _itoa(ceil(log2(cp->pf().greenMax)), buffer, 10);
+ strcat(strValue, buffer);
+ g = -1;
+ i--;
+ continue;
+ } else if (b == max3(r, g, b)) {
+ strcat(strValue, "b");
+ _itoa(ceil(log2(cp->pf().blueMax)), buffer, 10);
+ strcat(strValue, buffer);
+ b = -1;
+ i--;
+ continue;
+ } else break;
+ }
+ if (cp->pf().bigEndian) strcat(strValue, ", big-endian");
+ else strcat(strValue, ", little-endian");
+ setItemString(IDC_PIXEL_FORMAT, strValue);
+
+ switch (currentEncoding) {
+ case encodingRaw: strcpy(strValue, "Raw"); break;
+ case encodingCopyRect: strcpy(strValue, "CopyRect"); break;
+ case encodingRRE: strcpy(strValue, "RRE"); break;
+ case encodingCoRRE: strcpy(strValue, "CoRRE"); break;
+ case encodingHextile: strcpy(strValue, "Hextile"); break;
+ case encodingTight: strcpy(strValue, "Tight"); break;
+ case encodingZRLE: strcpy(strValue, "ZRLE"); break;
+ default: strcpy(strValue, "Unknown");
+ }
+ setItemString(IDC_CURRENT_ENCODING, strValue);
+
+ sprintf(strValue, "%i.%i", cp->majorVersion, cp->minorVersion);
+ setItemString(IDC_VERSION, strValue);
+ }
+ ConnParams *cp;
+ int currentEncoding;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/UserPixelFormatsDialog.h b/win/rfbplayer/UserPixelFormatsDialog.h
new file mode 100644
index 00000000..fe2ad223
--- /dev/null
+++ b/win/rfbplayer/UserPixelFormatsDialog.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- UserPixelFormatsDialog.h
+
+#include <rfbplayer/EditPixelFormatDialog.h>
+
+#define UPF_REGISTRY_PATH "Software\\TightVnc\\RfbPlayer\\UserDefinedPF"
+
+class UserPixelFormatsDialog : public rfb::win32::Dialog {
+public:
+ UserPixelFormatsDialog(PixelFormatList *_supportedPF)
+ : Dialog(GetModuleHandle(0)), supportedPF(_supportedPF), pfList(0) {}
+ // - Show the dialog and return true if OK was clicked,
+ // false in case of error or Cancel
+ virtual bool showDialog(HWND parent) {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_USERPF_LIST), parent);
+ }
+
+protected:
+ // Dialog methods (protected)
+ virtual void initDialog() {
+ pfList = GetDlgItem(handle, IDC_PF_LIST);
+ for (int i = supportedPF->getDefaultPFCount(); i < supportedPF->count(); i++) {
+ SendMessage(pfList, LB_ADDSTRING,
+ 0, (LPARAM)(LPCTSTR)(((*supportedPF)[i])->format_name));
+ }
+ SendMessage(pfList, LB_SETCURSEL, 0, 0);
+ }
+ virtual bool onCommand(int item, int cmd) {
+ switch (item) {
+ case IDC_ADD_BUTTON:
+ {
+ char format_name[MAX_STR_LEN] = "";
+ PixelFormat pf(32, 24, 0, 1, 0, 0, 0, 0, 0, 0);
+ EditPixelFormatDialog edit(supportedPF, format_name, &pf);
+ if (edit.showDialog(handle)) {
+ supportedPF->add(format_name, pf);
+ SendMessage(pfList, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)format_name);
+ }
+ }
+ break;
+ case IDC_REMOVE_BUTTON:
+ {
+ int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+ if (index == LB_ERR) {
+ MessageBox(handle, "You must select the pixel format for remove.",
+ "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return false;
+ } else {
+ supportedPF->remove(supportedPF->getDefaultPFCount() + index);
+ SendMessage(pfList, LB_DELETESTRING, index, 0);
+ }
+ }
+ break;
+ case IDC_PF_LIST:
+ if (cmd != LBN_DBLCLK) break;
+ case IDC_EDIT_BUTTON:
+ {
+ int index = SendMessage(pfList, LB_GETCURSEL, 0, 0);
+ if (index == LB_ERR) {
+ MessageBox(handle, "You must select the pixel format for remove.",
+ "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return false;
+ }
+ PixelFormat *pf =
+ &(supportedPF->operator[](index + supportedPF->getDefaultPFCount())->PF);
+ char *format_name =
+ (supportedPF)->operator[](index + supportedPF->getDefaultPFCount())->format_name;
+ EditPixelFormatDialog edit(supportedPF, format_name, pf);
+ if (edit.showDialog(handle)) {
+ SendMessage(pfList, LB_DELETESTRING, index, 0);
+ SendMessage(pfList, LB_INSERTSTRING, index, (LPARAM)(LPCTSTR)format_name);
+ SendMessage(pfList, LB_SETCURSEL, index, 0);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+ virtual bool onOk() {
+ supportedPF->writeUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ return true;
+ }
+
+ HWND pfList;
+ PixelFormatList *supportedPF;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/buildTime.cxx b/win/rfbplayer/buildTime.cxx
new file mode 100644
index 00000000..bab2e137
--- /dev/null
+++ b/win/rfbplayer/buildTime.cxx
@@ -0,0 +1 @@
+const char* buildTime = "Built on " __DATE__ " at " __TIME__; \ No newline at end of file
diff --git a/win/rfbplayer/resource.h b/win/rfbplayer/resource.h
new file mode 100644
index 00000000..90a057fe
--- /dev/null
+++ b/win/rfbplayer/resource.h
@@ -0,0 +1,81 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by rfbplayer.rc
+//
+#define IDI_ICON 105
+#define IDR_MENU 128
+#define IDR_ACCELERATOR 131
+#define IDB_TOOLBAR 132
+#define IDD_GOTO 133
+#define IDD_PIXELFORMAT 134
+#define IDD_OPTIONS 137
+#define IDD_ABOUT 138
+#define IDD_USERPF_LIST 139
+#define IDD_UPF_EDIT 140
+#define IDD_INFO 141
+#define IDD_SESSION_INFO 142
+#define IDC_GOTO_EDIT 1003
+#define IDC_PIXELFORMAT 1004
+#define IDC_ASK_PF 1006
+#define IDC_DEFAULT 1008
+#define IDC_VERSION 1008
+#define IDC_ACCEPT_BELL 1009
+#define IDC_BUILDTIME 1009
+#define IDC_ACCEPT_CUT_TEXT 1010
+#define IDC_AUTO_STORE_PARAM 1011
+#define IDC_AUTOPLAY 1012
+#define IDC_BIG_ENDIAN 1013
+#define IDC_EDIT_UPF 1015
+#define IDC_PF_LIST 1016
+#define IDC_BPP_COMBO 1016
+#define IDC_ADD_BUTTON 1017
+#define IDC_NAME_EDIT 1017
+#define IDC_REMOVE_BUTTON 1018
+#define IDC_EDIT_BUTTON 1019
+#define IDC_COPYRIGHT 1021
+#define IDC_DEPTH_EDIT 1021
+#define IDC_DESCRIPTION 1022
+#define IDC_BIGENDIAN_COMBO 1022
+#define IDC_REDMAX_EDIT 1023
+#define IDC_GREENMAX_EDIT 1024
+#define IDC_BLUEMAX_EDIT 1025
+#define IDC_REDSHIFT_EDIT 1026
+#define IDC_DESKTOP_NAME 1026
+#define IDC_GREENSHIFT_EDIT 1027
+#define IDC_DESKTOP_SIZE 1027
+#define IDC_BLUESHIFT_EDIT 1028
+#define IDC_CURRENT_ENCODING 1029
+#define IDC_PIXEL_FORMAT 1030
+#define IDC_INFO_EDIT 1076
+#define ID_OPENFILE 40011
+#define ID_CLOSEFILE 40012
+#define ID_EXIT 40013
+#define ID_FULLSCREEN 40014
+#define ID_ZOOM_50 40015
+#define ID_ZOOM_100 40016
+#define ID_ZOOM_200 40017
+#define ID_PLAYPAUSE 40018
+#define ID_STOP 40019
+#define ID_GOTO 40020
+#define ID_LOOP 40022
+#define ID_COPYTOCLIPBOARD 40023
+#define ID_FRAMEEXTRACT 40024
+#define ID_HELP_HOMEPAGE 40025
+#define ID_HOMEPAGE 40025
+#define ID_HELP_COMMANDLINESWITCHES 40026
+#define ID_HELP_ABOUT 40027
+#define ID_ABOUT 40027
+#define ID_OPTIONS 40029
+#define ID_RETURN 40044
+#define ID_SESSION_INFO 40045
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 143
+#define _APS_NEXT_COMMAND_VALUE 40046
+#define _APS_NEXT_CONTROL_VALUE 1031
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/win/rfbplayer/rfbSessionReader.h b/win/rfbplayer/rfbSessionReader.h
new file mode 100644
index 00000000..31985bc5
--- /dev/null
+++ b/win/rfbplayer/rfbSessionReader.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- rfbSessionReader.h
+
+#include <rfb/Threading.h>
+
+#include <rfbplayer/RfbProto.h>
+
+using namespace rfb;
+
+class rfbSessionReader : public Thread {
+public:
+ rfbSessionReader(RfbProto *_rfbSession) {
+ rfbSession = _rfbSession;
+ fStop = false;
+ rfbSession->interruptFrameDelay();
+ };
+
+ ~rfbSessionReader() {
+ }
+
+ virtual Thread* join() {
+ ((FbsInputStream*)(rfbSession->getInStream()))->resumePlayback();
+ fStop = true;
+ return Thread::join();
+ }
+
+ virtual void rfbSessionReader::run() {
+ // Process the rfb messages
+ while (!fStop) {
+ try {
+ rfbSession->processMsg();
+ } catch (rdr::Exception e) {
+ MessageBox(0, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ break;
+ }
+ }
+ }
+
+protected:
+ bool fStop;
+ RfbProto *rfbSession;
+}; \ No newline at end of file
diff --git a/win/rfbplayer/rfbplayer.cxx b/win/rfbplayer/rfbplayer.cxx
new file mode 100644
index 00000000..b304aece
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.cxx
@@ -0,0 +1,1294 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- RFB Player for Win32
+#include <windows.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#include <rfb/LogWriter.h>
+
+#include <rfb_win32/AboutDialog.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/Win32Util.h>
+
+#include <rfbplayer/rfbplayer.h>
+#include <rfbplayer/ChoosePixelFormatDialog.h>
+#include <rfbplayer/GotoPosDialog.h>
+#include <rfbplayer/InfoDialog.h>
+#include <rfbplayer/SessionInfoDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+// -=- Variables & consts
+
+static LogWriter vlog("RfbPlayer");
+
+TStr rfb::win32::AppName("RfbPlayer");
+extern const char* buildTime;
+HFONT hFont = 0;
+
+char wrong_cmd_msg[] =
+ "Wrong command-line parameters!\n"
+ "Use for help: rfbplayer -help";
+
+char usage_msg[] =
+ "usage: rfbplayer <options> <filename>\r\n"
+ "Command-line options:\r\n"
+ " -help \t- Provide usage information.\r\n"
+ " -pf <mode> \t- Forces the pixel format for the session.\r\n"
+ " \t <mode>=r<r_bits>g<g_bits>b<b_bits>[le|be],\r\n"
+ " \t r_bits - size the red component, in bits,\r\n"
+ " \t g_bits - size the green component, in bits,\r\n"
+ " \t b_bits - size the blue component, in bits,\r\n"
+ " \t le - little endian byte order (default),\r\n"
+ " \t be - big endian byte order.\r\n"
+ " \t The r, g, b component is in any order.\r\n"
+ " \t Default: auto detect the pixel format.\r\n"
+ " -upf <name> \t- Forces the user defined pixel format for\r\n"
+ " \t the session. If <name> is empty then application\r\n"
+ " \t shows the list of user defined pixel formats.\r\n"
+ " \t Don't use this option with -pf.\r\n"
+ " -speed <value>\t- Sets playback speed, where 1 is normal speed,\r\n"
+ " \t is double speed, 0.5 is half speed. Default: 1.0.\r\n"
+ " -pos <ms> \t- Sets initial time position in the session file,\r\n"
+ " \t in milliseconds. Default: 0.\r\n"
+ " -autoplay \t- Runs the player in the playback mode.\r\n"
+ " -loop \t- Replays the rfb session.";
+
+// -=- RfbPlayer's defines and consts
+
+#define strcasecmp _stricmp
+#define DEFAULT_PLAYER_WIDTH 640
+#define DEFAULT_PLAYER_HEIGHT 480
+
+//
+// -=- AboutDialog global values
+//
+
+const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
+const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
+const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
+const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
+const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
+
+//
+// -=- RfbPlayerClass
+
+//
+// Window class used as the basis for RfbPlayer instance
+//
+
+class RfbPlayerClass {
+public:
+ RfbPlayerClass();
+ ~RfbPlayerClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK RfbPlayerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+
+ if (msg == WM_CREATE)
+ SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY) {
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ SetWindowLong(hwnd, GWL_USERDATA, 0);
+ }
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", hwnd, msg);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processMainMessage(hwnd, msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+};
+
+RfbPlayerClass::RfbPlayerClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = RfbPlayerProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+ if (!wndClass.hIcon)
+ printf("unable to load icon:%ld", GetLastError());
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = HBRUSH(COLOR_WINDOW);
+ wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
+ wndClass.lpszClassName = _T("RfbPlayerClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register RfbPlayer window class",
+ GetLastError());
+ }
+}
+
+RfbPlayerClass::~RfbPlayerClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+RfbPlayerClass baseClass;
+
+//
+// -=- RfbFrameClass
+
+//
+// Window class used to displaying the rfb data
+//
+
+class RfbFrameClass {
+public:
+ RfbFrameClass();
+ ~RfbFrameClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+
+ if (msg == WM_CREATE)
+ SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(hwnd, GWL_USERDATA, 0);
+ RfbPlayer* _this = (RfbPlayer*) GetWindowLong(hwnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", hwnd, msg);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processFrameMessage(hwnd, msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+}
+
+RfbFrameClass::RfbFrameClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = FrameProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = 0;
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = 0;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("RfbPlayerClass1");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register RfbPlayer window class",
+ GetLastError());
+ }
+}
+
+RfbFrameClass::~RfbFrameClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+RfbFrameClass frameClass;
+
+//
+// -=- RfbPlayer instance implementation
+//
+
+RfbPlayer::RfbPlayer(char *_fileName, PlayerOptions *_options)
+: RfbProto(_fileName), fileName(_fileName), buffer(0), client_size(0, 0, 32, 32),
+ window_size(0, 0, 32, 32), cutText(0), seekMode(false), lastPos(0),
+ rfbReader(0), sessionTimeMs(0), sliderStepMs(0), imageDataStartTime(0),
+ rewindFlag(false), stopped(false), currentEncoding(-1) {
+
+ // Save the player options
+ memcpy(&options, _options, sizeof(options));
+
+ // Reset the full session time
+ strcpy(fullSessionTime, "00m:00s");
+
+ // Load the user defined pixel formats from the registry
+ supportedPF.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+
+ // Create the main window
+ const TCHAR* name = _T("RfbPlayer");
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+ mainHwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW,
+ x, y, DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT, 0, 0, baseClass.instance, this);
+ if (!mainHwnd) {
+ throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+ }
+ vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), getMainHandle());
+
+ // Create the backing buffer
+ buffer = new win32::DIBSectionBuffer(getFrameHandle());
+ setVisible(true);
+
+ // If run with command-line parameters,
+ // open the session file with default settings, otherwise
+ // restore player settings from the registry
+ if (fileName) {
+ openSessionFile(fileName);
+ if (options.initTime > 0) setPos(options.initTime);
+ setSpeed(options.playbackSpeed);
+ } else {
+ options.readFromRegistry();
+ disableTBandMenuItems();
+ setTitle("None");
+ }
+ init();
+}
+
+RfbPlayer::~RfbPlayer() {
+ vlog.debug("~RfbPlayer");
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ }
+ if (mainHwnd) {
+ setVisible(false);
+ DestroyWindow(mainHwnd);
+ mainHwnd = 0;
+ }
+ if (buffer) delete buffer;
+ if (cutText) delete [] cutText;
+ if (fileName) delete [] fileName;
+ if (hFont) DeleteObject(hFont);
+ vlog.debug("~RfbPlayer done");
+}
+
+LRESULT
+RfbPlayer::processMainMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+
+ switch (msg) {
+
+ // -=- Process standard window messages
+
+ case WM_CREATE:
+ {
+ tb.create(this, hwnd);
+
+ // Create the frame window
+ frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+ 0, WS_CHILD | WS_VISIBLE, 0, tb.getHeight(), 10, tb.getHeight() + 10,
+ hwnd, 0, frameClass.instance, this);
+
+ hMenu = GetMenu(hwnd);
+
+ return 0;
+ }
+
+ // Process the main menu and toolbar's messages
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+ case ID_OPENFILE:
+ {
+ char curDir[_MAX_DIR];
+ static char filename[_MAX_PATH];
+ OPENFILENAME ofn;
+ memset((void *) &ofn, 0, sizeof(OPENFILENAME));
+ GetCurrentDirectory(sizeof(curDir), curDir);
+
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = getMainHandle();
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof(filename);
+ ofn.lpstrInitialDir = curDir;
+ ofn.lpstrFilter = "Rfb Session files (*.rfb, *.fbs)\0*.rfb;*.fbs\0" \
+ "All files (*.*)\0*.*\0";
+ ofn.lpstrDefExt = "rfb";
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ if (GetOpenFileName(&ofn)) {
+ openSessionFile(filename);
+ }
+ }
+ break;
+ case ID_CLOSEFILE:
+ closeSessionFile();
+ break;
+ case ID_SESSION_INFO:
+ {
+ SessionInfoDialog sessionInfo(&cp, currentEncoding);
+ sessionInfo.showDialog(getMainHandle());
+ }
+ break;
+ case ID_PLAY:
+ setPaused(false);
+ break;
+ case ID_PAUSE:
+ setPaused(true);
+ break;
+ case ID_STOP:
+ stopPlayback();
+ break;
+ case ID_PLAYPAUSE:
+ if (rfbReader) {
+ if (isPaused()) {
+ setPaused(false);
+ } else {
+ setPaused(true);
+ }
+ }
+ break;
+ case ID_GOTO:
+ {
+ GotoPosDialog gotoPosDlg;
+ if (gotoPosDlg.showDialog(getMainHandle())) {
+ long gotoTime = min(gotoPosDlg.getPos(), sessionTimeMs);
+ setPos(gotoTime);
+ tb.updatePos(gotoTime);
+ setPaused(isPaused());;
+ }
+ }
+ break;
+ case ID_LOOP:
+ options.loopPlayback = !options.loopPlayback;
+ if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+ else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+ break;
+ case ID_RETURN:
+ tb.processWM_COMMAND(wParam, lParam);
+ break;
+ case ID_OPTIONS:
+ {
+ OptionsDialog optionsDialog(&options, &supportedPF);
+ optionsDialog.showDialog(getMainHandle());
+ }
+ break;
+ case ID_EXIT:
+ PostQuitMessage(0);
+ break;
+ case ID_HOMEPAGE:
+ ShellExecute(getMainHandle(), _T("open"), _T("http://www.tightvnc.com/"),
+ NULL, NULL, SW_SHOWDEFAULT);
+ break;
+ case ID_HELP_COMMANDLINESWITCHES:
+ {
+ InfoDialog usageDialog(usage_msg);
+ usageDialog.showDialog(getMainHandle());
+ }
+ break;
+ case ID_ABOUT:
+ AboutDialog::instance.showDialog();
+ break;
+ }
+ break;
+
+ // Update frame's window size and add scrollbars if required
+
+ case WM_SIZE:
+ {
+
+ Point old_offset = bufferToClient(Point(0, 0));
+
+ // Update the cached sizing information
+ RECT r;
+ GetClientRect(getMainHandle(), &r);
+ MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right - r.left,
+ r.bottom - r.top - tb.getHeight(), TRUE);
+
+ GetWindowRect(getFrameHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Determine whether scrollbars are required
+ calculateScrollBars();
+
+ // Resize the ToolBar
+ tb.autoSize();
+
+ // Redraw if required
+ if (!old_offset.equals(bufferToClient(Point(0, 0))))
+ InvalidateRect(getFrameHandle(), 0, TRUE);
+ }
+ break;
+
+ case WM_HSCROLL:
+ tb.processWM_HSCROLL(wParam, lParam);
+ break;
+
+ case WM_NOTIFY:
+ return tb.processWM_NOTIFY(wParam, lParam);
+
+ case WM_CLOSE:
+ vlog.debug("WM_CLOSE %x", getMainHandle());
+ PostQuitMessage(0);
+ break;
+ }
+
+ return rfb::win32::SafeDefWindowProc(getMainHandle(), msg, wParam, lParam);
+}
+
+LRESULT RfbPlayer::processFrameMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ case WM_PAINT:
+ {
+ if (isSeeking() || rewindFlag) {
+ seekMode = true;
+ return 0;
+ } else {
+ if (seekMode) {
+ seekMode = false;
+ InvalidateRect(getFrameHandle(), 0, true);
+ UpdateWindow(getFrameHandle());
+ return 0;
+ }
+ }
+
+ PAINTSTRUCT ps;
+ HDC paintDC = BeginPaint(getFrameHandle(), &ps);
+ if (!paintDC)
+ throw SystemException("unable to BeginPaint", GetLastError());
+ Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+ if (!pr.is_empty()) {
+
+ if (buffer->bitmap) {
+
+ // Get device context
+ BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+ // Blit the border if required
+ Rect bufpos = bufferToClient(buffer->getRect());
+ if (!pr.enclosed_by(bufpos)) {
+ vlog.debug("draw border");
+ HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ RECT r;
+ SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+ }
+
+ // Do the blit
+ Point buf_pos = clientToBuffer(pr.tl);
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+ throw SystemException("unable to BitBlt to window", GetLastError());
+
+ } else {
+ // Blit a load of black
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ 0, 0, 0, BLACKNESS))
+ throw SystemException("unable to BitBlt to blank window", GetLastError());
+ }
+ }
+ EndPaint(getFrameHandle(), &ps);
+ }
+ return 0;
+
+ // Process play/pause by the left mouse button
+ case WM_LBUTTONDOWN:
+ SendMessage(getMainHandle(), WM_COMMAND, ID_PLAYPAUSE, 0);
+ return 0;
+
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ Point delta;
+ int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+ switch (LOWORD(wParam)) {
+ case SB_PAGEUP: newpos -= 50; break;
+ case SB_PAGEDOWN: newpos += 50; break;
+ case SB_LINEUP: newpos -= 5; break;
+ case SB_LINEDOWN: newpos += 5; break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+ default: vlog.info("received unknown scroll message");
+ };
+
+ if (msg == WM_HSCROLL)
+ setViewportOffset(Point(newpos, scrolloffset.y));
+ else
+ setViewportOffset(Point(scrolloffset.x, newpos));
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ si.nPos = newpos;
+ SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
+ }
+ break;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void RfbPlayer::disableTBandMenuItems() {
+ // Disable the menu items
+ EnableMenuItem(hMenu, ID_CLOSEFILE, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_SESSION_INFO, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_GOTO, MF_GRAYED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_LOOP, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_GRAYED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_GRAYED | MF_BYCOMMAND);
+
+ // Disable the toolbar buttons and child controls
+ tb.disable();
+}
+
+void RfbPlayer::enableTBandMenuItems() {
+ // Enable the menu items
+ EnableMenuItem(hMenu, ID_CLOSEFILE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_SESSION_INFO, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FULLSCREEN, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(GetSubMenu(hMenu, 1), 1, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(hMenu, ID_PLAYPAUSE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_GOTO, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(hMenu, ID_LOOP, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_COPYTOCLIPBOARD, MF_ENABLED | MF_BYCOMMAND);
+ ///EnableMenuItem(hMenu, ID_FRAMEEXTRACT, MF_ENABLED | MF_BYCOMMAND);
+
+ // Enable the toolbar buttons and child controls
+ tb.enable();
+}
+
+void RfbPlayer::setVisible(bool visible) {
+ ShowWindow(getMainHandle(), visible ? SW_SHOW : SW_HIDE);
+ if (visible) {
+ // When the window becomes visible, make it active
+ SetForegroundWindow(getMainHandle());
+ SetActiveWindow(getMainHandle());
+ }
+}
+
+void RfbPlayer::setTitle(const char *title) {
+ char _title[256];
+ strcpy(_title, AppName);
+ strcat(_title, " - ");
+ strcat(_title, title);
+ SetWindowText(getMainHandle(), _title);
+}
+
+void RfbPlayer::setFrameSize(int width, int height) {
+ // Calculate and set required size for main window
+ RECT r = {0, 0, width, height};
+ AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), TRUE,
+ GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+ r.bottom += tb.getHeight(); // Include RfbPlayr's controls area
+ AdjustWindowRect(&r, GetWindowLong(getMainHandle(), GWL_STYLE), FALSE);
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2);
+ SetWindowPos(getMainHandle(), 0, x, y, r.right-r.left, r.bottom-r.top,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+
+ // Enable/disable scrollbars as appropriate
+ calculateScrollBars();
+}
+
+void RfbPlayer::calculateScrollBars() {
+ // Calculate the required size of window
+ DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD old_style;
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Work out whether scroll bars are required
+ do {
+ old_style = style;
+
+ if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+ style |= WS_HSCROLL;
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+ }
+ if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+ style |= WS_VSCROLL;
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ }
+ } while (style != old_style);
+
+ // Tell Windows to update the window style & cached settings
+ if (style != current_style) {
+ SetWindowLong(getFrameHandle(), GWL_STYLE, style);
+ SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+
+ // Update the scroll settings
+ SCROLLINFO si;
+ if (style & WS_VSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->height();
+ si.nPage = buffer->height() - (reqd_size.height() - window_size.height());
+ maxscrolloffset.y = max(0, si.nMax-si.nPage);
+ scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+ si.nPos = scrolloffset.y;
+ SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE);
+ }
+ if (style & WS_HSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->width();
+ si.nPage = buffer->width() - (reqd_size.width() - window_size.width());
+ maxscrolloffset.x = max(0, si.nMax-si.nPage);
+ scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+ si.nPos = scrolloffset.x;
+ SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE);
+ }
+
+ // Update the cached client size
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+bool RfbPlayer::setViewportOffset(const Point& tl) {
+/* ***
+ Point np = Point(max(0, min(maxscrolloffset.x, tl.x)),
+ max(0, min(maxscrolloffset.y, tl.y)));
+ */
+ Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+ max(0, min(tl.y, buffer->height()-client_size.height())));
+ Point delta = np.translate(scrolloffset.negate());
+ if (!np.equals(scrolloffset)) {
+ scrolloffset = np;
+ ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+ UpdateWindow(getFrameHandle());
+ return true;
+ }
+ return false;
+}
+
+void RfbPlayer::close(const char* reason) {
+ setVisible(false);
+ if (reason) {
+ vlog.info("closing - %s", reason);
+ MessageBox(NULL, TStr(reason), "RfbPlayer", MB_ICONINFORMATION | MB_OK);
+ }
+ SendMessage(getFrameHandle(), WM_CLOSE, 0, 0);
+}
+
+void RfbPlayer::blankBuffer() {
+ fillRect(buffer->getRect(), 0);
+}
+
+void RfbPlayer::rewind() {
+ bool paused = isPaused();
+ blankBuffer();
+ newSession(fileName);
+ skipHandshaking();
+ is->setSpeed(options.playbackSpeed);
+ if (paused) is->pausePlayback();
+ else is->resumePlayback();
+}
+
+void RfbPlayer::processMsg() {
+ // Perform return if waitWhilePaused processed because
+ // rfbReader thread could receive the signal to close
+ if (waitWhilePaused()) return;
+
+ static long update_time = GetTickCount();
+ try {
+ if ((!isSeeking()) && ((GetTickCount() - update_time) > 250)
+ && (!tb.isPosSliderDragging())) {
+ // Update pos in the toolbar 4 times in 1 second
+ tb.updatePos(getTimeOffset());
+ update_time = GetTickCount();
+ }
+ RfbProto::processMsg();
+ } catch (rdr::Exception e) {
+ if (strcmp(e.str(), "[End Of File]") == 0) {
+ rewind();
+ setPaused(!options.loopPlayback);
+ tb.updatePos(getTimeOffset());
+ return;
+ }
+ // It's a special exception to perform backward seeking.
+ // We only rewind the stream and seek the offset
+ if (strcmp(e.str(), "[REWIND]") == 0) {
+ rewindFlag = true;
+ long seekOffset = max(getSeekOffset(), imageDataStartTime);
+ rewind();
+ if (!stopped) setPos(seekOffset);
+ else stopped = false;
+ tb.updatePos(seekOffset);
+ rewindFlag = false;
+ return;
+ }
+ // It's a special exception which is used to terminate the playback
+ if (strcmp(e.str(), "[TERMINATE]") == 0) {
+ sessionTerminateThread *terminate = new sessionTerminateThread(this);
+ terminate->start();
+ } else {
+ // Show the exception message and close the session playback
+ is->pausePlayback();
+ char message[256] = "\0";
+ strcat(message, e.str());
+ strcat(message, "\nMaybe you force wrong the pixel format for this session");
+ MessageBox(getMainHandle(), message, "RFB Player", MB_OK | MB_ICONERROR);
+ sessionTerminateThread *terminate = new sessionTerminateThread(this);
+ terminate->start();
+ return;
+ }
+ }
+}
+
+long ChoosePixelFormatDialog::pfIndex = DEFAULT_PF_INDEX;
+bool ChoosePixelFormatDialog::bigEndian = false;
+
+void RfbPlayer::serverInit() {
+ RfbProto::serverInit();
+
+ // Save the image data start time
+ imageDataStartTime = is->getTimeOffset();
+
+ // Resize the backing buffer
+ buffer->setSize(cp.width, cp.height);
+
+ // Check on the true colour mode
+ if (!(cp.pf()).trueColour)
+ throw rdr::Exception("This version plays only true color session!");
+
+ // Set the session pixel format
+ if (options.askPixelFormat) {
+ ChoosePixelFormatDialog choosePixelFormatDialog(&supportedPF);
+ if (choosePixelFormatDialog.showDialog(getMainHandle())) {
+ long pixelFormatIndex = choosePixelFormatDialog.getPFIndex();
+ if (pixelFormatIndex < 0) {
+ options.autoDetectPF = true;
+ options.setPF((PixelFormat *)&cp.pf());
+ } else {
+ options.autoDetectPF = false;
+ options.setPF(&supportedPF[pixelFormatIndex]->PF);
+ options.pixelFormat.bigEndian = choosePixelFormatDialog.isBigEndian();
+ }
+ } else {
+ is->pausePlayback();
+ throw rdr::Exception("[TERMINATE]");
+ }
+ } else {
+ if (!options.commandLineParam) {
+ if (options.autoDetectPF) {
+ options.setPF((PixelFormat *)&cp.pf());
+ } else {
+ options.setPF(&supportedPF[options.pixelFormatIndex]->PF);
+ options.pixelFormat.bigEndian = options.bigEndianFlag;
+ }
+ } else if (options.autoDetectPF) {
+ options.setPF((PixelFormat *)&cp.pf());
+ }
+ }
+ cp.setPF(options.pixelFormat);
+ buffer->setPF(options.pixelFormat);
+
+ // If the window is not maximised then resize it
+ if (!(GetWindowLong(getMainHandle(), GWL_STYLE) & WS_MAXIMIZE))
+ setFrameSize(cp.width, cp.height);
+
+ // Set the window title and show it
+ setTitle(cp.name());
+
+ // Calculate the full session time and update posTrackBar control in toolbar
+ sessionTimeMs = calculateSessionTime(fileName);
+ tb.init(sessionTimeMs);
+ tb.updatePos(getTimeOffset());
+
+ setPaused(!options.autoPlay);
+ // Restore the parameters from registry,
+ // which was replaced by command-line parameters.
+ if (options.commandLineParam) {
+ options.readFromRegistry();
+ options.commandLineParam = false;
+ }
+}
+
+void RfbPlayer::setColourMapEntries(int first, int count, U16* rgbs) {
+ vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+ throw rdr::Exception("Can't handle SetColourMapEntries message");
+/* int i;
+ for (i=0;i<count;i++) {
+ buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+ }
+ // *** change to 0, 256?
+ refreshWindowPalette(first, count);
+ palette_changed = true;
+ InvalidateRect(getFrameHandle(), 0, FALSE);*/
+}
+
+void RfbPlayer::bell() {
+ if (options.acceptBell)
+ MessageBeep(-1);
+}
+
+void RfbPlayer::serverCutText(const char* str, int len) {
+ if (cutText != NULL)
+ delete [] cutText;
+ cutText = new char[len + 1];
+ memcpy(cutText, str, len);
+ cutText[len] = '\0';
+}
+
+void RfbPlayer::frameBufferUpdateEnd() {
+};
+
+void RfbPlayer::beginRect(const Rect& r, unsigned int encoding) {
+ currentEncoding = encoding;
+}
+
+void RfbPlayer::endRect(const Rect& r, unsigned int encoding) {
+}
+
+
+void RfbPlayer::fillRect(const Rect& r, Pixel pix) {
+ buffer->fillRect(r, pix);
+ invalidateBufferRect(r);
+}
+
+void RfbPlayer::imageRect(const Rect& r, void* pixels) {
+ buffer->imageRect(r, pixels);
+ invalidateBufferRect(r);
+}
+
+void RfbPlayer::copyRect(const Rect& r, int srcX, int srcY) {
+ buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+ invalidateBufferRect(r);
+}
+
+bool RfbPlayer::invalidateBufferRect(const Rect& crect) {
+ Rect rect = bufferToClient(crect);
+ if (rect.intersect(client_size).is_empty()) return false;
+ RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+ InvalidateRect(getFrameHandle(), &invalid, FALSE);
+ return true;
+}
+
+bool RfbPlayer::waitWhilePaused() {
+ bool result = false;
+ while(isPaused() && !isSeeking()) {
+ Sleep(20);
+ result = true;
+ }
+ return result;
+}
+
+long RfbPlayer::calculateSessionTime(char *filename) {
+ FbsInputStream sessionFile(filename);
+ sessionFile.setTimeOffset(100000000);
+ try {
+ while (TRUE) {
+ sessionFile.skip(1024);
+ }
+ } catch (rdr::Exception e) {
+ if (strcmp(e.str(), "[End Of File]") == 0) {
+ return sessionFile.getTimeOffset();
+ } else {
+ MessageBox(getMainHandle(), e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void RfbPlayer::init() {
+ if (options.loopPlayback) CheckMenuItem(hMenu, ID_LOOP, MF_CHECKED);
+ else CheckMenuItem(hMenu, ID_LOOP, MF_UNCHECKED);
+}
+
+void RfbPlayer::closeSessionFile() {
+ DWORD dwStyle;
+ RECT r;
+
+ // Uncheck all toolbar buttons
+ if (tb.getHandle()) {
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_PAUSE, false);
+ tb.checkButton(ID_STOP, false);
+ }
+
+ // Stop playback and update the player state
+ disableTBandMenuItems();
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ delete [] fileName;
+ fileName = 0;
+ }
+ blankBuffer();
+ setTitle("None");
+ options.playbackSpeed = 1.0;
+ tb.init(0);
+
+ // Change the player window size and frame size to default
+ if ((dwStyle = GetWindowLong(getMainHandle(), GWL_STYLE)) & WS_MAXIMIZE) {
+ dwStyle &= ~WS_MAXIMIZE;
+ SetWindowLong(getMainHandle(), GWL_STYLE, dwStyle);
+ }
+ int x = max(0, (GetSystemMetrics(SM_CXSCREEN) - DEFAULT_PLAYER_WIDTH) / 2);
+ int y = max(0, (GetSystemMetrics(SM_CYSCREEN) - DEFAULT_PLAYER_HEIGHT) / 2);
+ SetWindowPos(getMainHandle(), 0, x, y,
+ DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT,
+ SWP_NOZORDER | SWP_FRAMECHANGED);
+ buffer->setSize(32, 32);
+ calculateScrollBars();
+
+ // Update the cached sizing information and repaint the frame window
+ GetWindowRect(getFrameHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getFrameHandle(), &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+ InvalidateRect(getFrameHandle(), 0, TRUE);
+ UpdateWindow(getFrameHandle());
+}
+
+void RfbPlayer::openSessionFile(char *_fileName) {
+ fileName = strDup(_fileName);
+
+ // Close the previous reading thread
+ if (rfbReader) {
+ delete rfbReader->join();
+ rfbReader = 0;
+ }
+ blankBuffer();
+ newSession(fileName);
+ setSpeed(options.playbackSpeed);
+ rfbReader = new rfbSessionReader(this);
+ rfbReader->start();
+ tb.setTimePos(0);
+ enableTBandMenuItems();
+}
+
+void RfbPlayer::setPaused(bool paused) {
+ if (paused) {
+ is->pausePlayback();
+ tb.checkButton(ID_PAUSE, true);
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_STOP, false);
+ } else {
+ if (is) is->resumePlayback();
+ tb.checkButton(ID_PLAY, true);
+ tb.checkButton(ID_STOP, false);
+ tb.checkButton(ID_PAUSE, false);
+ }
+ tb.enableButton(ID_PAUSE, true);
+ EnableMenuItem(hMenu, ID_STOP, MF_ENABLED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::stopPlayback() {
+ stopped = true;
+ setPos(0);
+ if (is) {
+ is->pausePlayback();
+ is->interruptFrameDelay();
+ }
+ tb.checkButton(ID_STOP, true);
+ tb.checkButton(ID_PLAY, false);
+ tb.checkButton(ID_PAUSE, false);
+ tb.enableButton(ID_PAUSE, false);
+ tb.setTimePos(0);
+ EnableMenuItem(hMenu, ID_STOP, MF_GRAYED | MF_BYCOMMAND);
+}
+
+void RfbPlayer::setSpeed(double speed) {
+ if (speed > 0) {
+ char speedStr[20] = "\0";
+ double newSpeed = min(speed, MAX_SPEED);
+ is->setSpeed(newSpeed);
+ options.playbackSpeed = newSpeed;
+ SendMessage(tb.getSpeedUpDownHwnd(), UDM_SETPOS,
+ 0, MAKELONG((short)(newSpeed / 0.5), 0));
+ sprintf(speedStr, "%.2f", newSpeed);
+ SetWindowText(tb.getSpeedEditHwnd(), speedStr);
+ }
+}
+
+double RfbPlayer::getSpeed() {
+ return is->getSpeed();
+}
+
+void RfbPlayer::setPos(long pos) {
+ is->setTimeOffset(max(pos, imageDataStartTime));
+}
+
+long RfbPlayer::getSeekOffset() {
+ return is->getSeekOffset();
+}
+
+bool RfbPlayer::isSeeking() {
+ if (is) return is->isSeeking();
+ else return false;
+}
+
+bool RfbPlayer::isSeekMode() {
+ return seekMode;
+}
+
+bool RfbPlayer::isPaused() {
+ return is->isPaused();
+}
+
+long RfbPlayer::getTimeOffset() {
+ return max(is->getTimeOffset(), is->getSeekOffset());
+}
+
+void RfbPlayer::skipHandshaking() {
+ int skipBytes = 12 + 4 + 24 + strlen(cp.name());
+ is->skip(skipBytes);
+ state_ = RFBSTATE_NORMAL;
+}
+
+void programInfo() {
+ win32::FileVersionInfo inf;
+ _tprintf(_T("%s - %s, Version %s\n"),
+ inf.getVerString(_T("ProductName")),
+ inf.getVerString(_T("FileDescription")),
+ inf.getVerString(_T("FileVersion")));
+ printf("%s\n", buildTime);
+ _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
+}
+
+void programUsage() {
+ InfoDialog usageDialog(usage_msg);
+ usageDialog.showDialog();
+}
+
+char *fileName = 0;
+
+// playerOptions is the player options with default parameters values,
+// it is used only for run the player with command-line parameters
+PlayerOptions playerOptions;
+bool print_usage = false;
+bool print_upf_list = false;
+
+bool processParams(int argc, char* argv[]) {
+ playerOptions.commandLineParam = true;
+ for (int i = 1; i < argc; i++) {
+ if ((strcasecmp(argv[i], "-help") == 0) ||
+ (strcasecmp(argv[i], "--help") == 0) ||
+ (strcasecmp(argv[i], "/help") == 0) ||
+ (strcasecmp(argv[i], "-h") == 0) ||
+ (strcasecmp(argv[i], "/h") == 0) ||
+ (strcasecmp(argv[i], "/?") == 0) ||
+ (strcasecmp(argv[i], "-?") == 0)) {
+ print_usage = true;
+ return true;
+ }
+
+ if ((strcasecmp(argv[i], "-pf") == 0) ||
+ (strcasecmp(argv[i], "/pf") == 0) && (i < argc-1)) {
+ char *pf = argv[++i];
+ char rgb_order[4] = "\0";
+ int order = RGB_ORDER;
+ int r = -1, g = -1, b = -1;
+ bool big_endian = false;
+ if (strlen(pf) < 6) return false;
+ while (strlen(pf)) {
+ if ((pf[0] == 'r') || (pf[0] == 'R')) {
+ if (r >=0 ) return false;
+ r = atoi(++pf);
+ strcat(rgb_order, "r");
+ continue;
+ }
+ if ((pf[0] == 'g') || (pf[0] == 'G')) {
+ if (g >=0 ) return false;
+ g = atoi(++pf);
+ strcat(rgb_order, "g");
+ continue;
+ }
+ if (((pf[0] == 'b') || (pf[0] == 'B')) &&
+ (pf[1] != 'e') && (pf[1] != 'E')) {
+ if (b >=0 ) return false;
+ b = atoi(++pf);
+ strcat(rgb_order, "b");
+ continue;
+ }
+ if ((pf[0] == 'l') || (pf[0] == 'L') ||
+ (pf[0] == 'b') || (pf[0] == 'B')) {
+ if (strcasecmp(pf, "le") == 0) break;
+ if (strcasecmp(pf, "be") == 0) { big_endian = true; break;}
+ return false;
+ }
+ pf++;
+ }
+ if ((r < 0) || (g < 0) || (b < 0) || (r + g + b > 32)) return false;
+ if (strcasecmp(rgb_order, "rgb") == 0) { order = RGB_ORDER; }
+ else if (strcasecmp(rgb_order, "rbg") == 0) { order = RBG_ORDER; }
+ else if (strcasecmp(rgb_order, "grb") == 0) { order = GRB_ORDER; }
+ else if (strcasecmp(rgb_order, "gbr") == 0) { order = GBR_ORDER; }
+ else if (strcasecmp(rgb_order, "bgr") == 0) { order = BGR_ORDER; }
+ else if (strcasecmp(rgb_order, "brg") == 0) { order = BRG_ORDER; }
+ else return false;
+ playerOptions.autoDetectPF = false;
+ playerOptions.setPF(order, r, g, b, big_endian);
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-upf") == 0) ||
+ (strcasecmp(argv[i], "/upf") == 0) && (i < argc-1)) {
+ if ((i == argc - 1) || (argv[++i][0] == '-')) {
+ print_upf_list = true;
+ return true;
+ }
+ PixelFormatList userPfList;
+ userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ int index = userPfList.getIndexByPFName(argv[i]);
+ if (index > 0) {
+ playerOptions.autoDetectPF = false;
+ playerOptions.setPF(&userPfList[index]->PF);
+ } else {
+ return false;
+ }
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-speed") == 0) ||
+ (strcasecmp(argv[i], "/speed") == 0) && (i < argc-1)) {
+ double playbackSpeed = atof(argv[++i]);
+ if (playbackSpeed <= 0) {
+ return false;
+ }
+ playerOptions.playbackSpeed = playbackSpeed;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-pos") == 0) ||
+ (strcasecmp(argv[i], "/pos") == 0) && (i < argc-1)) {
+ long initTime = atol(argv[++i]);
+ if (initTime <= 0)
+ return false;
+ playerOptions.initTime = initTime;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-autoplay") == 0) ||
+ (strcasecmp(argv[i], "/autoplay") == 0) && (i < argc-1)) {
+ playerOptions.autoPlay = true;
+ continue;
+ }
+
+ if ((strcasecmp(argv[i], "-loop") == 0) ||
+ (strcasecmp(argv[i], "/loop") == 0) && (i < argc-1)) {
+ playerOptions.loopPlayback = true;
+ continue;
+ }
+
+ if (i != argc - 1)
+ return false;
+ }
+
+ fileName = strDup(argv[argc-1]);
+ if (fileName[0] == '-') return false;
+ else return true;
+}
+
+//
+// -=- WinMain
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+
+ // - Process the command-line
+
+ int argc = __argc;
+ char** argv = __argv;
+ if ((argc > 1) && (!processParams(argc, argv))) {
+ MessageBox(0, wrong_cmd_msg, "RfbPlayer", MB_OK | MB_ICONWARNING);
+ return 0;
+ }
+
+ if (print_usage) {
+ programUsage();
+ return 0;
+ }
+ // Show the user defined pixel formats if required
+ if (print_upf_list) {
+ int list_size = 256;
+ char *upf_list = new char[list_size];
+ PixelFormatList userPfList;
+ userPfList.readUserDefinedPF(HKEY_CURRENT_USER, UPF_REGISTRY_PATH);
+ strcpy(upf_list, "The list of the user defined pixel formats:\r\n");
+ for (int i = userPfList.getDefaultPFCount(); i < userPfList.count(); i++) {
+ if ((list_size - strlen(upf_list) - 1) <
+ (strlen(userPfList[i]->format_name) + 2)) {
+ char *tmpStr = new char[list_size =
+ list_size + strlen(userPfList[i]->format_name) + 2];
+ strcpy(tmpStr, upf_list);
+ delete [] upf_list;
+ upf_list = new char[list_size];
+ strcpy(upf_list, tmpStr);
+ delete [] tmpStr;
+ }
+ strcat(upf_list, userPfList[i]->format_name);
+ strcat(upf_list, "\r\n");
+ }
+ InfoDialog upfInfoDialog(upf_list);
+ upfInfoDialog.showDialog();
+ delete [] upf_list;
+ return 0;
+ }
+
+ // Create the player
+ RfbPlayer *player = NULL;
+ try {
+ player = new RfbPlayer(fileName, &playerOptions);
+ } catch (rdr::Exception e) {
+ MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ delete player;
+ return 0;
+ }
+
+ // Run the player
+ HACCEL hAccel = LoadAccelerators(inst, MAKEINTRESOURCE(IDR_ACCELERATOR));
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ if(!TranslateAccelerator(player->getMainHandle(), hAccel, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ // Destroy the player
+ try{
+ if (player) delete player;
+ } catch (rdr::Exception e) {
+ MessageBox(NULL, e.str(), "RFB Player", MB_OK | MB_ICONERROR);
+ }
+
+ return 0;
+};
diff --git a/win/rfbplayer/rfbplayer.dsp b/win/rfbplayer/rfbplayer.dsp
new file mode 100644
index 00000000..90685369
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.dsp
@@ -0,0 +1,207 @@
+# Microsoft Developer Studio Project File - Name="rfbplayer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=rfbplayer - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "rfbplayer.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "rfbplayer.mak" CFG="rfbplayer - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "rfbplayer - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "rfbplayer - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "rfbplayer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\rfbplayer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 user32.lib gdi32.lib Advapi32.lib comctl32.lib shell32.lib comdlg32.lib version.lib /nologo /subsystem:windows /machine:I386
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\rfbplayer /MTd buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "rfbplayer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\rfbplayer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\rfbplayer /MTd buildTime.cxx
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "rfbplayer - Win32 Release"
+# Name "rfbplayer - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\buildTime.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FbsInputStream.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelFormatList.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerOptions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerToolBar.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbplayer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbplayer.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\RfbProto.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\ChoosePixelFormatDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\EditPixelFormatDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FbsInputStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\GotoPosDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelFormatList.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PlayerToolBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbplayer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RfbProto.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rfbSessionReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SessionInfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPixelFormatsDialog.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\rfbplayer.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\toolbar.bmp
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win/rfbplayer/rfbplayer.h b/win/rfbplayer/rfbplayer.h
new file mode 100644
index 00000000..c5c5da8d
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.h
@@ -0,0 +1,195 @@
+/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- RfbPlayer.h
+
+#include <windows.h>
+
+#include <rfb_win32/DIBSectionBuffer.h>
+
+#include <rfbplayer/resource.h>
+#include <rfbplayer/PixelFormatList.h>
+#include <rfbplayer/PlayerToolBar.h>
+#include <rfbplayer/OptionsDialog.h>
+#include <rfbplayer/rfbSessionReader.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+class PlayerToolBar;
+
+class RfbPlayer : public RfbProto {
+ public:
+ RfbPlayer(char *fileName, PlayerOptions *options);
+ ~RfbPlayer();
+
+ // -=- Window Message handling
+
+ LRESULT processMainMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ LRESULT processFrameMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+ // -=- Window interface
+
+ HWND getMainHandle() const {return mainHwnd;}
+ HWND getFrameHandle() const {return frameHwnd;}
+ void disableTBandMenuItems();
+ void enableTBandMenuItems();
+ void setFrameSize(int width, int height);
+ void setVisible(bool visible);
+ void setTitle(const char *title);
+ void calculateScrollBars();
+ void close(const char* reason=0);
+ void init();
+
+ // -=- Coordinate conversions
+
+ inline Point bufferToClient(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x += (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x -= scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y += (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y -= scrolloffset.y;
+ return pos;
+ }
+ inline Rect bufferToClient(const Rect& r) {
+ return Rect(bufferToClient(r.tl), bufferToClient(r.br));
+ }
+
+ inline Point clientToBuffer(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x -= (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x += scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y -= (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y += scrolloffset.y;
+ return pos;
+ }
+ inline Rect clientToBuffer(const Rect& r) {
+ return Rect(clientToBuffer(r.tl), clientToBuffer(r.br));
+ }
+
+ bool setViewportOffset(const Point& tl);
+
+ // -=- RfbProto interface overrides
+
+ virtual void processMsg();
+ virtual void serverInit();
+ virtual void frameBufferUpdateEnd();
+ virtual void setColourMapEntries(int first, int count, U16* rgbs);
+ virtual void serverCutText(const char* str, int len);
+ virtual void bell();
+
+ virtual void beginRect(const Rect& r, unsigned int encoding);
+ virtual void endRect(const Rect& r, unsigned int encoding);
+ virtual void fillRect(const Rect& r, Pixel pix);
+ virtual void imageRect(const Rect& r, void* pixels);
+ virtual void copyRect(const Rect& r, int srcX, int srcY);
+
+ // -=- Player functions
+
+ // calculateSessionTime() calculates the full session time in sec
+ long calculateSessionTime(char *fileName);
+
+ // closeSessionFile() closes the session file and blanks the frame buffer
+ void closeSessionFile();
+
+ // openSessionFile() opens the new session file and starts play it
+ void openSessionFile(char *fileName);
+
+ // skipHandshaking() - is implemented to skip the initial handshaking when
+ // perform backward seeking OR replaying.
+ void skipHandshaking();
+
+ void blankBuffer();
+ void rewind();
+ void setPaused(bool paused);
+ void stopPlayback();
+ long getTimeOffset();
+ bool isSeekMode();
+ bool isSeeking();
+ bool isPaused();
+ long getSeekOffset();
+ void setPos(long pos);
+ void setSpeed(double speed);
+ double getSpeed();
+
+ protected:
+ bool seekMode;
+ bool stopped;
+ long lastPos;
+ long sliderStepMs;
+ char fullSessionTime[20];
+ int time_pos_m;
+ int time_pos_s;
+ char *fileName;
+
+ // rfbReader is a class which used to reading the rfb data from the file
+ rfbSessionReader *rfbReader;
+
+ // Returns true if part of the supplied rect is visible, false otherwise
+ bool invalidateBufferRect(const Rect& crect);
+
+ bool waitWhilePaused();
+
+ // rewindFlag is a flag wich disable the update of the frame buffer window
+ // while the rewind is performing.
+ bool rewindFlag;
+
+ // Local window state
+ HWND mainHwnd;
+ HWND frameHwnd;
+ HMENU hMenu;
+ Rect window_size;
+ Rect client_size;
+ Point scrolloffset;
+ Point maxscrolloffset;
+ char *cutText;
+ win32::DIBSectionBuffer* buffer;
+ PlayerToolBar tb;
+
+ // The player's parameters
+ PlayerOptions options;
+ PixelFormatList supportedPF;
+ long imageDataStartTime;
+ long sessionTimeMs;
+ int currentEncoding;
+};
+
+// -=- sessionTerminateThread class
+
+// It is a special thread class, wich is allow the rfbSessionReader class
+// terminate itself.
+
+class sessionTerminateThread : public rfb::Thread {
+public:
+ sessionTerminateThread(RfbPlayer *_player) : player(_player) {
+ setDeleteAfterRun();
+ }
+ virtual void run() {
+ player->closeSessionFile();
+ }
+protected:
+ RfbPlayer *player;
+};
diff --git a/win/rfbplayer/rfbplayer.ico b/win/rfbplayer/rfbplayer.ico
new file mode 100644
index 00000000..c9136bfe
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.ico
Binary files differ
diff --git a/win/rfbplayer/rfbplayer.rc b/win/rfbplayer/rfbplayer.rc
new file mode 100644
index 00000000..169d8502
--- /dev/null
+++ b/win/rfbplayer/rfbplayer.rc
@@ -0,0 +1,466 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON ICON DISCARDABLE "rfbplayer.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "TightVNC Team\0"
+ VALUE "FileDescription", "RFB Session Player for Win32\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "rfbplayer\0"
+ VALUE "LegalCopyright", "Copyright (C) 2004-2005 TightVNC Team.\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "rfbplayer.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Rfb Session Player 1.0\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "File"
+ BEGIN
+ MENUITEM "Open File...\tCtrl+O", ID_OPENFILE
+ MENUITEM "Close File...\tCtrl+Q", ID_CLOSEFILE
+ MENUITEM SEPARATOR
+ MENUITEM "Info...\tCtrl+I", ID_SESSION_INFO
+ MENUITEM SEPARATOR
+ MENUITEM "Exit\tAlt+X", ID_EXIT
+ END
+ POPUP "Play"
+ BEGIN
+ MENUITEM "Play/Pause\tSpace", ID_PLAYPAUSE
+ MENUITEM "Stop\tC", ID_STOP
+ MENUITEM "Go To...\tCtrl+G", ID_GOTO
+ MENUITEM SEPARATOR
+ MENUITEM "Loop\tCtrl+L", ID_LOOP
+ MENUITEM SEPARATOR
+ MENUITEM "Options...\tO", ID_OPTIONS
+ END
+ POPUP "Help"
+ BEGIN
+ MENUITEM "Home Page", ID_HOMEPAGE
+ MENUITEM "Command Line Switches", ID_HELP_COMMANDLINESWITCHES
+ MENUITEM SEPARATOR
+ MENUITEM "About RfbPlayer...", ID_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR ACCELERATORS DISCARDABLE
+BEGIN
+ "C", ID_STOP, VIRTKEY, NOINVERT
+ "C", ID_COPYTOCLIPBOARD, VIRTKEY, CONTROL, NOINVERT
+ "C", ID_FRAMEEXTRACT, VIRTKEY, ALT, NOINVERT
+ "G", ID_GOTO, VIRTKEY, CONTROL, NOINVERT
+ "I", ID_SESSION_INFO, VIRTKEY, CONTROL, NOINVERT
+ "L", ID_LOOP, VIRTKEY, CONTROL, NOINVERT
+ "O", ID_OPTIONS, VIRTKEY, NOINVERT
+ "O", ID_OPENFILE, VIRTKEY, CONTROL, NOINVERT
+ "P", ID_OPTIONS, VIRTKEY, CONTROL, NOINVERT
+ "Q", ID_CLOSEFILE, VIRTKEY, CONTROL, NOINVERT
+ VK_F5, ID_ZOOM_50, VIRTKEY, NOINVERT
+ VK_F6, ID_ZOOM_100, VIRTKEY, NOINVERT
+ VK_F7, ID_ZOOM_200, VIRTKEY, NOINVERT
+ VK_RETURN, ID_RETURN, VIRTKEY, NOINVERT
+ VK_RETURN, ID_FULLSCREEN, VIRTKEY, ALT, NOINVERT
+ VK_SPACE, ID_PLAYPAUSE, VIRTKEY, NOINVERT
+ "X", ID_EXIT, VIRTKEY, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_GOTO DIALOG DISCARDABLE 0, 0, 153, 54
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Go to position"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_GOTO_EDIT,40,9,106,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,40,33,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,95,33,51,14
+ LTEXT "Pos (ms):",IDC_STATIC,7,9,33,15,SS_CENTERIMAGE
+END
+
+IDD_PIXELFORMAT DIALOG DISCARDABLE 0, 0, 144, 78
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RfbPlayer : Pixel Format"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_PIXELFORMAT,7,20,130,98,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDOK,20,57,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,75,57,50,14
+ LTEXT "Choose the pixel format:",IDC_STATIC,7,7,130,13
+ CONTROL "Big endian flag",IDC_BIG_ENDIAN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,40,63,12
+END
+
+IDD_OPTIONS DIALOG DISCARDABLE 0, 0, 187, 180
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Options"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_PIXELFORMAT,15,30,157,75,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Big endian flag",IDC_BIG_ENDIAN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,52,60,10
+ CONTROL "Ask the pixel format before playing",IDC_ASK_PF,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,67,157,10
+ CONTROL "Accept the bells",IDC_ACCEPT_BELL,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,105,157,15
+ CONTROL "Accept the cut text",IDC_ACCEPT_CUT_TEXT,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,120,157,15
+ CONTROL "Start play the session when it is opened",IDC_AUTOPLAY,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,15,135,
+ 157,9
+ DEFPUSHBUTTON "OK",IDOK,20,161,50,13
+ PUSHBUTTON "Cancel",IDCANCEL,75,161,50,13
+ PUSHBUTTON "Default",IDC_DEFAULT,130,161,50,13
+ PUSHBUTTON "Edit User PF",IDC_EDIT_UPF,110,52,62,14
+ GROUPBOX "Pixel format",IDC_STATIC,7,6,173,79
+ LTEXT "Forces the pixel format for the rfb session:",
+ IDC_STATIC,15,17,157,13
+ GROUPBOX "Other",IDC_STATIC,7,90,173,65
+END
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 251, 95
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Rfb Session Player for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,195,70,47,15
+ ICON IDI_ICON,IDC_STATIC,7,10,20,20
+ LTEXT ">appname<",IDC_DESCRIPTION,40,10,125,15
+ LTEXT ">version<",IDC_VERSION,165,10,77,15
+ LTEXT ">buildtime<",IDC_BUILDTIME,40,25,202,15
+ LTEXT ">copyright<",IDC_COPYRIGHT,40,40,202,15
+ LTEXT "See http://www.tightvnc.com for more information on TightVNC.",
+ IDC_STATIC,40,55,202,15
+END
+
+IDD_USERPF_LIST DIALOG DISCARDABLE 0, 0, 207, 162
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Add / Remove the user pixel formats"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LISTBOX IDC_PF_LIST,7,7,136,148,LBS_NOINTEGRALHEIGHT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Add",IDC_ADD_BUTTON,150,7,50,14
+ PUSHBUTTON "Remove",IDC_REMOVE_BUTTON,150,26,50,14
+ PUSHBUTTON "Edit",IDC_EDIT_BUTTON,150,45,50,14
+ PUSHBUTTON "Close",IDOK,150,64,50,14
+END
+
+IDD_UPF_EDIT DIALOG DISCARDABLE 0, 0, 204, 126
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit the user pixel format"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_NAME_EDIT,68,7,129,13,ES_AUTOHSCROLL
+ COMBOBOX IDC_BPP_COMBO,68,23,39,45,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ EDITTEXT IDC_DEPTH_EDIT,157,22,40,13,ES_AUTOHSCROLL | ES_NUMBER
+ COMBOBOX IDC_BIGENDIAN_COMBO,68,38,39,45,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_REDMAX_EDIT,68,54,39,13,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_GREENMAX_EDIT,68,70,39,13,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_BLUEMAX_EDIT,68,86,39,13,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_REDSHIFT_EDIT,157,54,39,13,ES_AUTOHSCROLL |
+ ES_NUMBER
+ EDITTEXT IDC_GREENSHIFT_EDIT,157,70,40,13,ES_AUTOHSCROLL |
+ ES_NUMBER
+ EDITTEXT IDC_BLUESHIFT_EDIT,157,86,40,13,ES_AUTOHSCROLL |
+ ES_NUMBER
+ PUSHBUTTON "OK",IDOK,93,105,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,147,105,50,14
+ LTEXT "Pixel format name:",IDC_STATIC,7,7,57,13,SS_CENTERIMAGE
+ LTEXT "Bit per pixel:",IDC_STATIC,7,23,38,12,SS_CENTERIMAGE
+ LTEXT "Big endian flag :",IDC_STATIC,7,38,53,13,SS_CENTERIMAGE
+ LTEXT "Red max :",IDC_STATIC,7,54,33,13,SS_CENTERIMAGE
+ LTEXT "Green max :",IDC_STATIC,7,70,38,13,SS_CENTERIMAGE
+ LTEXT "Blue max :",IDC_STATIC,7,86,38,13,SS_CENTERIMAGE
+ LTEXT "Depth:",IDC_STATIC,112,23,21,12,SS_CENTERIMAGE
+ LTEXT "Red shifts :",IDC_STATIC,112,54,36,13,SS_CENTERIMAGE
+ LTEXT "Green shifts :",IDC_STATIC,112,70,43,13,SS_CENTERIMAGE
+ LTEXT "Blue shifts :",IDC_STATIC,112,86,43,13,SS_CENTERIMAGE
+END
+
+IDD_INFO DIALOG DISCARDABLE 0, 0, 295, 207
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Information"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "&OK",IDOK,122,186,50,14
+ EDITTEXT IDC_INFO_EDIT,7,7,281,172,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN |
+ WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_SESSION_INFO DIALOG DISCARDABLE 0, 0, 239, 106
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "RFB Session Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,182,85,50,14
+ LTEXT "Desktop Name:",IDC_STATIC,7,10,73,15
+ LTEXT "Desktop Size:",IDC_STATIC,7,25,73,15
+ LTEXT "Pixel Format:",IDC_STATIC,7,40,73,15
+ LTEXT "Current Encoding:",IDC_STATIC,7,55,73,15
+ LTEXT "RFB Protocol Version:",IDC_STATIC,7,70,73,15
+ LTEXT "",IDC_DESKTOP_NAME,80,10,152,15
+ LTEXT "",IDC_DESKTOP_SIZE,80,25,152,15
+ LTEXT "",IDC_CURRENT_ENCODING,80,55,152,15
+ LTEXT "",IDC_VERSION,80,70,152,15
+ LTEXT "",IDC_PIXEL_FORMAT,80,40,152,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_GOTO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 146
+ VERTGUIDE, 40
+ VERTGUIDE, 90
+ VERTGUIDE, 95
+ TOPMARGIN, 9
+ BOTTOMMARGIN, 47
+ HORZGUIDE, 9
+ HORZGUIDE, 24
+ HORZGUIDE, 35
+ END
+
+ IDD_PIXELFORMAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 137
+ VERTGUIDE, 20
+ VERTGUIDE, 70
+ VERTGUIDE, 75
+ VERTGUIDE, 125
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 71
+ HORZGUIDE, 7
+ HORZGUIDE, 20
+ HORZGUIDE, 35
+ HORZGUIDE, 40
+ HORZGUIDE, 49
+ HORZGUIDE, 57
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 180
+ VERTGUIDE, 15
+ VERTGUIDE, 20
+ VERTGUIDE, 70
+ VERTGUIDE, 75
+ VERTGUIDE, 125
+ VERTGUIDE, 130
+ VERTGUIDE, 172
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 174
+ HORZGUIDE, 17
+ HORZGUIDE, 30
+ HORZGUIDE, 42
+ HORZGUIDE, 52
+ HORZGUIDE, 67
+ HORZGUIDE, 85
+ HORZGUIDE, 90
+ HORZGUIDE, 105
+ HORZGUIDE, 120
+ HORZGUIDE, 135
+ HORZGUIDE, 144
+ HORZGUIDE, 150
+ HORZGUIDE, 155
+ HORZGUIDE, 161
+ END
+
+ IDD_USERPF_LIST, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 200
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 155
+ HORZGUIDE, 21
+ HORZGUIDE, 26
+ HORZGUIDE, 40
+ HORZGUIDE, 45
+ HORZGUIDE, 59
+ HORZGUIDE, 64
+ END
+
+ IDD_UPF_EDIT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 197
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 119
+ END
+
+ IDD_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 288
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 200
+ END
+
+ IDD_SESSION_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 232
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 99
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/win/rfbplayer/toolbar.bmp b/win/rfbplayer/toolbar.bmp
new file mode 100644
index 00000000..9347a738
--- /dev/null
+++ b/win/rfbplayer/toolbar.bmp
Binary files differ
diff --git a/win/vnc.dsw b/win/vnc.dsw
new file mode 100644
index 00000000..686cc692
--- /dev/null
+++ b/win/vnc.dsw
@@ -0,0 +1,248 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Xregion"=..\common\Xregion\Xregion.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "logmessages"=.\logmessages\logmessages.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "network"=..\common\network\network.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "rdr"=..\common\rdr\rdr.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "rfb"=..\common\rfb\rfb.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name rdr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name Xregion
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "rfb_win32"=.\rfb_win32\rfb_win32.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name rfb
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "rfbplayer"=.\rfbplayer\rfbplayer.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name rdr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name rfb
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name rfb_win32
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name Xregion
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name jpeg
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "vncconfig"=.\vncconfig\vncconfig.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name rfb
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name rfb_win32
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name network
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name Xregion
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "vncviewer"=.\vncviewer\vncviewer.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name rfb
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name jpeg
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name rfb_win32
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name network
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name rdr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name Xregion
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "winvnc"=.\winvnc\winvnc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name network
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name rfb_win32
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name jpeg
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name Xregion
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "wm_hooks"=.\wm_hooks\wm_hooks.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlib"=..\common\zlib\zlib.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "jpeg"=..\common\jpeg\jpeg.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/win/vncconfig/Authentication.h b/win/vncconfig/Authentication.h
new file mode 100644
index 00000000..f4b38f8c
--- /dev/null
+++ b/win/vncconfig/Authentication.h
@@ -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
index 00000000..7512cc65
--- /dev/null
+++ b/win/vncconfig/Connections.h
@@ -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
index 00000000..164269a2
--- /dev/null
+++ b/win/vncconfig/Desktop.h
@@ -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
index 00000000..9be82f3a
--- /dev/null
+++ b/win/vncconfig/Hooking.h
@@ -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
index 00000000..1e0b4bac
--- /dev/null
+++ b/win/vncconfig/Inputs.h
@@ -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
index 00000000..ae5d7166
--- /dev/null
+++ b/win/vncconfig/Legacy.cxx
@@ -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
index 00000000..02059a64
--- /dev/null
+++ b/win/vncconfig/Legacy.h
@@ -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
index 00000000..d26d86f6
--- /dev/null
+++ b/win/vncconfig/PasswordDialog.cxx
@@ -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
index 00000000..dd23f8e3
--- /dev/null
+++ b/win/vncconfig/PasswordDialog.h
@@ -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
index 00000000..872ae133
--- /dev/null
+++ b/win/vncconfig/Sharing.h
@@ -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
index 00000000..ca1fbf5a
--- /dev/null
+++ b/win/vncconfig/resource.h
@@ -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
index 00000000..6c9e1c5a
--- /dev/null
+++ b/win/vncconfig/vncconfig.cxx
@@ -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
index 00000000..b096ded0
--- /dev/null
+++ b/win/vncconfig/vncconfig.dsp
@@ -0,0 +1,196 @@
+# Microsoft Developer Studio Project File - Name="vncconfig" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=vncconfig - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "vncconfig.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "vncconfig.mak" CFG="vncconfig - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "vncconfig - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "vncconfig - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "vncconfig - Win32 Debug Unicode" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "vncconfig - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\vncconfig"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib version.lib shell32.lib comctl32.lib ws2_32.lib ole32.lib /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "vncconfig - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "vncconfig___Win32_Debug"
+# PROP BASE Intermediate_Dir "vncconfig___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\vncconfig"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# 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
+
+!ELSEIF "$(CFG)" == "vncconfig - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "vncconfig___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "vncconfig___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\vncconfig"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".." /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_WINDOWS" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib version.lib shell32.lib comctl32.lib ws2_32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# 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
+
+!ENDIF
+
+# Begin Target
+
+# Name "vncconfig - Win32 Release"
+# Name "vncconfig - Win32 Debug"
+# Name "vncconfig - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\Legacy.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PasswordDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncconfig.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\Authentication.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Connections.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Desktop.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Hooking.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Inputs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Legacy.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PasswordDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Sharing.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\connected.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncconfig.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncconfig.rc
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\vncconfig.exe.manifest
+# End Source File
+# End Target
+# End Project
diff --git a/win/vncconfig/vncconfig.exe.manifest b/win/vncconfig/vncconfig.exe.manifest
new file mode 100644
index 00000000..77cb1b9a
--- /dev/null
+++ b/win/vncconfig/vncconfig.exe.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+ version="4.0.0.26"
+ processorArchitecture="X86"
+ name="TightVNC.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
index 00000000..1b42416c
--- /dev/null
+++ b/win/vncconfig/vncconfig.ico
Binary files differ
diff --git a/win/vncconfig/vncconfig.rc b/win/vncconfig/vncconfig.rc
new file mode 100644
index 00000000..bf2f9696
--- /dev/null
+++ b/win/vncconfig/vncconfig.rc
@@ -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
index 00000000..73597f52
--- /dev/null
+++ b/win/vncviewer/CConn.cxx
@@ -0,0 +1,712 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/resource.h>
+#include <rfb/encodings.h>
+#include <rfb/secTypes.h>
+#include <rfb/CSecurityNone.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/CMsgWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/AboutDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+
+// - Statics & consts
+
+static LogWriter vlog("CConn");
+
+
+const int IDM_FULLSCREEN = ID_FULLSCREEN;
+const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY;
+const int IDM_SEND_CAD = ID_SEND_CAD;
+const int IDM_SEND_CTLESC = ID_SEND_CTLESC;
+const int IDM_ABOUT = ID_ABOUT;
+const int IDM_OPTIONS = ID_OPTIONS;
+const int IDM_INFO = ID_INFO;
+const int IDM_NEWCONN = ID_NEW_CONNECTION;
+const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH;
+const int IDM_CTRL_KEY = ID_CTRL_KEY;
+const int IDM_ALT_KEY = ID_ALT_KEY;
+const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER;
+const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS;
+
+
+static IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
+ "pixel data - a debugging feature", 0);
+
+
+//
+// -=- CConn implementation
+//
+
+RegKey CConn::userConfigKey;
+
+
+CConn::CConn()
+ : window(0), sock(0), sockEvent(CreateEvent(0, TRUE, FALSE, 0)), requestUpdate(false),
+ sameMachine(false), encodingChange(false), formatChange(false),
+ reverseConnection(false), lastUsedEncoding_(encodingRaw), isClosed_(false) {
+}
+
+CConn::~CConn() {
+ delete window;
+}
+
+bool CConn::initialise(network::Socket* s, bool reverse) {
+ // Set the server's name for MRU purposes
+ CharArray endpoint(s->getPeerEndpoint());
+ setServerName(endpoint.buf);
+ if (!options.host.buf)
+ options.setHost(endpoint.buf);
+
+ // Initialise the underlying CConnection
+ setStreams(&s->inStream(), &s->outStream());
+
+ // Enable processing of window messages while blocked on I/O
+ s->inStream().setBlockCallback(this);
+
+ // Initialise the viewer options
+ applyOptions(options);
+
+ // - Set which auth schemes we support, in order of preference
+ addSecType(secTypeVncAuth);
+ addSecType(secTypeNone);
+
+ // Start the RFB protocol
+ sock = s;
+ reverseConnection = reverse;
+ initialiseProtocol();
+
+ m_fileTransfer.initialize(&s->inStream(), &s->outStream());
+
+ return true;
+}
+
+
+void
+CConn::applyOptions(CConnOptions& opt) {
+ // - If any encoding-related settings have changed then we must
+ // notify the server of the new settings
+ encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) ||
+ (options.useDesktopResize != opt.useDesktopResize) ||
+ (options.customCompressLevel != opt.customCompressLevel) ||
+ (options.compressLevel != opt.compressLevel) ||
+ (options.noJpeg != opt.noJpeg) ||
+ (options.qualityLevel != opt.qualityLevel) ||
+ (options.preferredEncoding != opt.preferredEncoding));
+
+ // - If the preferred pixel format has changed then notify the server
+ formatChange |= (options.fullColour != opt.fullColour);
+ if (!opt.fullColour)
+ formatChange |= (options.lowColourLevel != opt.lowColourLevel);
+
+ // - Save the new set of options
+ options = opt;
+
+ // - Set optional features in ConnParams
+ cp.supportsLocalCursor = options.useLocalCursor;
+ cp.supportsDesktopResize = options.useDesktopResize;
+ cp.customCompressLevel = options.customCompressLevel;
+ cp.compressLevel = options.compressLevel;
+ cp.noJpeg = options.noJpeg;
+ cp.qualityLevel = options.qualityLevel;
+
+ // - Configure connection sharing on/off
+ setShared(options.shared);
+
+ // - Whether to use protocol 3.3 for legacy compatibility
+ setProtocol3_3(options.protocol3_3);
+
+ // - Apply settings that affect the window, if it is visible
+ if (window) {
+ window->setMonitor(options.monitor.buf);
+ window->setFullscreen(options.fullScreen);
+ window->setEmulate3(options.emulate3);
+ window->setPointerEventInterval(options.pointerEventInterval);
+ window->setMenuKey(options.menuKey);
+ window->setDisableWinKeys(options.disableWinKeys);
+ window->setShowToolbar(options.showToolbar);
+ if (!options.useLocalCursor)
+ window->setCursor(0, 0, Point(), 0, 0);
+ }
+}
+
+
+void
+CConn::displayChanged() {
+ // Display format has changed - recalculate the full-colour pixel format
+ calculateFullColourPF();
+}
+
+void
+CConn::paintCompleted() {
+ // A repaint message has just completed - request next update if necessary
+ requestNewUpdate();
+}
+
+bool
+CConn::sysCommand(WPARAM wParam, LPARAM lParam) {
+ // - If it's one of our (F8 Menu) messages
+ switch (wParam) {
+ case IDM_FULLSCREEN:
+ options.fullScreen = !window->isFullscreen();
+ window->setFullscreen(options.fullScreen);
+ return true;
+ case IDM_SHOW_TOOLBAR:
+ options.showToolbar = !window->isToolbarEnabled();
+ window->setShowToolbar(options.showToolbar);
+ return true;
+ case IDM_CTRL_KEY:
+ window->kbd.keyEvent(this, VK_CONTROL, 0, !window->kbd.keyPressed(VK_CONTROL));
+ return true;
+ case IDM_ALT_KEY:
+ window->kbd.keyEvent(this, VK_MENU, 0, !window->kbd.keyPressed(VK_MENU));
+ return true;
+ case IDM_SEND_MENU_KEY:
+ window->kbd.keyEvent(this, options.menuKey, 0, true);
+ window->kbd.keyEvent(this, options.menuKey, 0, false);
+ return true;
+ case IDM_SEND_CAD:
+ window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+ window->kbd.keyEvent(this, VK_MENU, 0, true);
+ window->kbd.keyEvent(this, VK_DELETE, 0x1000000, true);
+ window->kbd.keyEvent(this, VK_DELETE, 0x1000000, false);
+ window->kbd.keyEvent(this, VK_MENU, 0, false);
+ window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+ return true;
+ case IDM_SEND_CTLESC:
+ window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+ window->kbd.keyEvent(this, VK_ESCAPE, 0, true);
+ window->kbd.keyEvent(this, VK_ESCAPE, 0, false);
+ window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+ return true;
+ case IDM_REQUEST_REFRESH:
+ try {
+ writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false);
+ requestUpdate = false;
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+ return true;
+ case IDM_NEWCONN:
+ {
+ Thread* newThread = new CConnThread;
+ }
+ return true;
+ case IDM_OPTIONS:
+ // Update the monitor device name in the CConnOptions instance
+ options.monitor.replaceBuf(window->getMonitor());
+ showOptionsDialog();
+ return true;
+ case IDM_INFO:
+ infoDialog.showDialog(this);
+ return true;
+ case IDM_ABOUT:
+ AboutDialog::instance.showDialog();
+ return true;
+ case IDM_FILE_TRANSFER:
+ m_fileTransfer.show(window->getHandle());
+ return true;
+ case IDM_CONN_SAVE_AS:
+ return true;
+ case ID_CLOSE:
+ // FIXME: Remove the corresponding toolbar button.
+ return true;
+ };
+ return false;
+}
+
+
+void
+CConn::closeWindow() {
+ vlog.info("window closed");
+ close();
+}
+
+
+void
+CConn::refreshMenu(bool enableSysItems) {
+ HMENU menu = GetSystemMenu(window->getHandle(), FALSE);
+
+ if (!enableSysItems) {
+ // Gray out menu items that might cause a World Of Pain
+ EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
+ EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
+ EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);
+ }
+
+ // Update the modifier key menu items
+ UINT ctrlCheckFlags = window->kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED;
+ UINT altCheckFlags = window->kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED;
+ CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags);
+ CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags);
+
+ // Ensure that the Send <MenuKey> menu item has the correct text
+ if (options.menuKey) {
+ TCharArray menuKeyStr(options.menuKeyName());
+ TCharArray tmp(_tcslen(menuKeyStr.buf) + 6);
+ _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf);
+ if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf))
+ InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf);
+ } else {
+ RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND);
+ }
+
+ // Set the menu fullscreen option tick
+ CheckMenuItem(menu, IDM_FULLSCREEN, (window->isFullscreen() ? MF_CHECKED : 0) | MF_BYCOMMAND);
+
+ // Set the menu toolbar option tick
+ int toolbarFlags = window->isToolbarEnabled() ? MF_CHECKED : 0;
+ CheckMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+
+ // In the full-screen mode, "Show toolbar" should be grayed.
+ toolbarFlags = window->isFullscreen() ? MF_GRAYED : MF_ENABLED;
+ EnableMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+}
+
+
+void
+CConn::blockCallback() {
+ // - An InStream has blocked on I/O while processing an RFB message
+ // We re-enable socket event notifications, so we'll know when more
+ // data is available, then we sit and dispatch window events until
+ // the notification arrives.
+ if (!isClosed()) {
+ if (WSAEventSelect(sock->getFd(), sockEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
+ throw rdr::SystemException("Unable to wait for sokcet data", WSAGetLastError());
+ }
+ while (true) {
+ // If we have closed then we can't block waiting for data
+ if (isClosed())
+ throw rdr::EndOfStream();
+
+ // Wait for socket data, or a message to process
+ DWORD result = MsgWaitForMultipleObjects(1, &sockEvent.h, FALSE, INFINITE, QS_ALLINPUT);
+ if (result == WAIT_OBJECT_0) {
+ // - Network event notification. Return control to I/O routine.
+ break;
+ } else if (result == WAIT_FAILED) {
+ // - The wait operation failed - raise an exception
+ throw rdr::SystemException("blockCallback wait error", GetLastError());
+ }
+
+ // - There should be a message in the message queue
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ // IMPORTANT: We mustn't call TranslateMessage() here, because instead we
+ // call ToAscii() in CKeyboard::keyEvent(). ToAscii() stores dead key
+ // state from one call to the next, which would be messed up by calls to
+ // TranslateMessage() (actually it looks like TranslateMessage() calls
+ // ToAscii() internally).
+ DispatchMessage(&msg);
+ }
+ }
+
+ // Before we return control to the InStream, reset the network event
+ WSAEventSelect(sock->getFd(), sockEvent, 0);
+ ResetEvent(sockEvent);
+}
+
+
+void CConn::keyEvent(rdr::U32 key, bool down) {
+ if (!options.sendKeyEvents) return;
+ try {
+ writer()->keyEvent(key, down);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+void CConn::pointerEvent(const Point& pos, int buttonMask) {
+ if (!options.sendPtrEvents) return;
+ try {
+ writer()->pointerEvent(pos, buttonMask);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+void CConn::clientCutText(const char* str, int len) {
+ if (!options.clientCutText) return;
+ if (state() != RFBSTATE_NORMAL) return;
+ try {
+ writer()->clientCutText(str, len);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+
+CSecurity* CConn::getCSecurity(int secType)
+{
+ switch (secType) {
+ case secTypeNone:
+ return new CSecurityNone();
+ case secTypeVncAuth:
+ return new CSecurityVncAuth(this);
+ default:
+ throw Exception("Unsupported secType?");
+ }
+}
+
+
+void
+CConn::setColourMapEntries(int first, int count, U16* rgbs) {
+ vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+ int i;
+ for (i=0;i<count;i++)
+ window->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+ // *** change to 0, 256?
+ window->refreshWindowPalette(first, count);
+}
+
+void
+CConn::bell() {
+ if (options.acceptBell)
+ MessageBeep(-1);
+}
+
+
+void
+CConn::setDesktopSize(int w, int h) {
+ vlog.debug("setDesktopSize %dx%d", w, h);
+
+ // Resize the window's buffer
+ if (window)
+ window->setSize(w, h);
+
+ // Tell the underlying CConnection
+ CConnection::setDesktopSize(w, h);
+}
+
+void
+CConn::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+ if (!options.useLocalCursor) return;
+
+ // Set the window to use the new cursor
+ window->setCursor(w, h, hotspot, data, mask);
+}
+
+
+void
+CConn::close(const char* reason) {
+ // If already closed then ignore this
+ if (isClosed())
+ return;
+
+ // Hide the window, if it exists
+ if (window)
+ ShowWindow(window->getHandle(), SW_HIDE);
+
+ // Save the reason & flag that we're closed & shutdown the socket
+ isClosed_ = true;
+ closeReason_.replaceBuf(strDup(reason));
+ sock->shutdown();
+}
+
+
+void
+CConn::showOptionsDialog() {
+ optionsDialog.showDialog(this);
+}
+
+
+void
+CConn::framebufferUpdateEnd() {
+ if (debugDelay != 0) {
+ vlog.debug("debug delay %d",(int)debugDelay);
+ UpdateWindow(window->getHandle());
+ Sleep(debugDelay);
+ std::list<rfb::Rect>::iterator i;
+ for (i = debugRects.begin(); i != debugRects.end(); i++) {
+ window->invertRect(*i);
+ }
+ debugRects.clear();
+ }
+ if (options.autoSelect)
+ autoSelectFormatAndEncoding();
+
+ // Always request the next update
+ requestUpdate = true;
+
+ // Check that at least part of the window has changed
+ if (!GetUpdateRect(window->getHandle(), 0, FALSE)) {
+ if (!(GetWindowLong(window->getHandle(), GWL_STYLE) & WS_MINIMIZE))
+ requestNewUpdate();
+ }
+
+ // Make sure the local cursor is shown
+ window->showCursor();
+}
+
+
+// Note: The method below is duplicated in vncviewer_unix/CConn.cxx!
+
+// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+// to the connection speed:
+//
+// Above 16Mbps (timing for at least a second), switch to hextile
+// Otherwise, switch to ZRLE
+//
+// Above 256Kbps, use full colour mode
+//
+void
+CConn::autoSelectFormatAndEncoding() {
+ int kbitsPerSecond = sock->inStream().kbitsPerSecond();
+ unsigned int newEncoding = options.preferredEncoding;
+
+ bool newFullColour = options.fullColour;
+ unsigned int timeWaited = sock->inStream().timeWaited();
+
+ // Select best encoding
+ if (kbitsPerSecond > 16000 && timeWaited >= 10000) {
+ newEncoding = encodingHextile;
+ } else {
+ newEncoding = encodingZRLE;
+ }
+
+ if (newEncoding != options.preferredEncoding) {
+ vlog.info("Throughput %d kbit/s - changing to %s encoding",
+ kbitsPerSecond, encodingName(newEncoding));
+ options.preferredEncoding = newEncoding;
+ encodingChange = true;
+ }
+
+ if (kbitsPerSecond == 0) {
+ return;
+ }
+
+ if (cp.beforeVersion(3, 8)) {
+ // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+ // cursors "asynchronously". If this happens in the middle of a
+ // pixel format change, the server will encode the cursor with
+ // the old format, but the client will try to decode it
+ // according to the new format. This will lead to a
+ // crash. Therefore, we do not allow automatic format change for
+ // old servers.
+ return;
+ }
+
+ // Select best color level
+ newFullColour = (kbitsPerSecond > 256);
+ if (newFullColour != options.fullColour) {
+ vlog.info("Throughput %d kbit/s - full color is now %s",
+ kbitsPerSecond,
+ newFullColour ? "enabled" : "disabled");
+ options.fullColour = newFullColour;
+ formatChange = true;
+ }
+}
+
+void
+CConn::requestNewUpdate() {
+ if (!requestUpdate) return;
+
+ if (formatChange) {
+ // Select the required pixel format
+ if (options.fullColour) {
+ window->setPF(fullColourPF);
+ } else {
+ switch (options.lowColourLevel) {
+ case 0:
+ window->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0));
+ break;
+ case 1:
+ window->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0));
+ break;
+ case 2:
+ window->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0));
+ break;
+ }
+ }
+
+ // Print the current pixel format
+ char str[256];
+ window->getPF().print(str, 256);
+ vlog.info("Using pixel format %s",str);
+
+ // Save the connection pixel format and tell server to use it
+ cp.setPF(window->getPF());
+ writer()->writeSetPixelFormat(cp.pf());
+
+ // Correct the local window's palette
+ if (!window->getNativePF().trueColour)
+ window->refreshWindowPalette(0, 1 << cp.pf().depth);
+ }
+
+ if (encodingChange) {
+ vlog.info("Using %s encoding",encodingName(options.preferredEncoding));
+ writer()->writeSetEncodings(options.preferredEncoding, true);
+ }
+
+ writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
+ !formatChange);
+
+ encodingChange = formatChange = requestUpdate = false;
+}
+
+
+void
+CConn::calculateFullColourPF() {
+ // If the server is palette based then use palette locally
+ // Also, don't bother doing bgr222
+ if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) {
+ fullColourPF = serverDefaultPF;
+ options.fullColour = true;
+ } else {
+ // If server is trueColour, use lowest depth PF
+ PixelFormat native = window->getNativePF();
+ if ((serverDefaultPF.bpp < native.bpp) ||
+ ((serverDefaultPF.bpp == native.bpp) &&
+ (serverDefaultPF.depth < native.depth)))
+ fullColourPF = serverDefaultPF;
+ else
+ fullColourPF = window->getNativePF();
+ }
+ formatChange = true;
+}
+
+
+void
+CConn::setName(const char* name) {
+ if (window)
+ window->setName(name);
+ CConnection::setName(name);
+}
+
+
+void CConn::serverInit() {
+ CConnection::serverInit();
+
+ // If using AutoSelect with old servers, start in FullColor
+ // mode. See comment in autoSelectFormatAndEncoding.
+ if (cp.beforeVersion(3, 8) && options.autoSelect) {
+ options.fullColour = true;
+ }
+
+ // Show the window
+ window = new DesktopWindow(this);
+ window->setName(cp.name());
+ window->setSize(cp.width, cp.height);
+ applyOptions(options);
+
+ // Save the server's current format
+ serverDefaultPF = cp.pf();
+
+ // Calculate the full-colour format to use
+ calculateFullColourPF();
+
+ // Request the initial update
+ vlog.info("requesting initial update");
+ formatChange = encodingChange = requestUpdate = true;
+ requestNewUpdate();
+
+ // Update the window menu
+ HMENU wndmenu = GetSystemMenu(window->getHandle(), FALSE);
+ int toolbarChecked = options.showToolbar ? MF_CHECKED : 0;
+
+ AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+ AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen"));
+ AppendMenu(wndmenu, MF_STRING | toolbarChecked, IDM_SHOW_TOOLBAR,
+ _T("Show tool&bar"));
+ AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+ AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l"));
+ AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t"));
+ AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del"));
+ AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc"));
+ AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen"));
+ AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+ AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection..."));
+ AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options..."));
+ AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info..."));
+ AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About..."));
+}
+
+void
+CConn::serverCutText(const char* str, int len) {
+ if (!options.serverCutText) return;
+ window->serverCutText(str, len);
+}
+
+
+void CConn::beginRect(const Rect& r, unsigned int encoding) {
+ sock->inStream().startTiming();
+}
+
+void CConn::endRect(const Rect& r, unsigned int encoding) {
+ sock->inStream().stopTiming();
+ lastUsedEncoding_ = encoding;
+ if (debugDelay != 0) {
+ window->invertRect(r);
+ debugRects.push_back(r);
+ }
+}
+
+void CConn::fillRect(const Rect& r, Pixel pix) {
+ window->fillRect(r, pix);
+}
+void CConn::imageRect(const Rect& r, void* pixels) {
+ window->imageRect(r, pixels);
+}
+void CConn::copyRect(const Rect& r, int srcX, int srcY) {
+ window->copyRect(r, srcX, srcY);
+}
+
+void CConn::getUserPasswd(char** user, char** password) {
+ if (!user && options.passwordFile.buf[0]) {
+ FILE* fp = fopen(options.passwordFile.buf, "rb");
+ if (fp) {
+ char data[256];
+ int datalen = fread(data, 1, 256, fp);
+ fclose(fp);
+ if (datalen == 8) {
+ ObfuscatedPasswd obfPwd;
+ obfPwd.buf = data;
+ obfPwd.length = datalen;
+ PlainPasswd passwd(obfPwd);
+ *password = strDup(passwd.buf);
+ memset(data, 0, strlen(data));
+ }
+ }
+ }
+ if (user && options.userName.buf)
+ *user = strDup(options.userName.buf);
+ if (password && options.password.buf)
+ *password = strDup(options.password.buf);
+ if ((user && !*user) || (password && !*password)) {
+ // Missing username or password - prompt the user
+ UserPasswdDialog userPasswdDialog;
+ userPasswdDialog.setCSecurity(getCurrentCSecurity());
+ userPasswdDialog.getUserPasswd(user, password);
+ }
+ if (user) options.setUserName(*user);
+ if (password) options.setPassword(*password);
+}
+
+bool CConn::processFTMsg(int type) {
+ return m_fileTransfer.processFTMsg(type);
+}
diff --git a/win/vncviewer/CConn.h b/win/vncviewer/CConn.h
new file mode 100644
index 00000000..29023f39
--- /dev/null
+++ b/win/vncviewer/CConn.h
@@ -0,0 +1,165 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConn.h
+
+// Windows-specific implementation of CConnection
+
+#ifndef __RFB_WIN32_CCONN_H__
+#define __RFB_WIN32_CCONN_H__
+
+#include <network/Socket.h>
+#include <rfb/CConnection.h>
+#include <rfb/Cursor.h>
+#include <rfb/UserPasswdGetter.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Handle.h>
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConnOptions.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/FileTransfer.h>
+#include <list>
+
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConn : public CConnection,
+ UserPasswdGetter,
+ DesktopWindow::Callback,
+ rdr::FdInStreamBlockCallback
+ {
+ public:
+ CConn();
+ ~CConn();
+
+ // - Start the VNC session on the supplied socket
+ // The socket must already be connected to a host
+ bool initialise(network::Socket* s, bool reverse=false);
+
+ // - Set/get the session options
+ void applyOptions(CConnOptions& opt);
+ const CConnOptions& getOptions() const { return options; };
+
+ // - Show the options dialog for the connection
+ void showOptionsDialog();
+
+ // - Close the socket & set the reason for closure
+ void close(const char* reason=0);
+ bool isClosed() const { return isClosed_; }
+ const char* closeReason() const { return closeReason_.buf; }
+
+ // - Last received encoding, for the Info dialog
+ int lastUsedEncoding() const { return lastUsedEncoding_; }
+
+ // - Get at the DesktopWindow, if any
+ DesktopWindow* getWindow() { return window; }
+
+ // - Get at the underlying Socket
+ network::Socket* getSocket() { return sock; }
+
+ // - Get the server's preferred format
+ const PixelFormat& getServerDefaultPF() const { return serverDefaultPF; }
+
+ // Global user-config registry key
+ static RegKey userConfigKey;
+
+ bool processFTMsg(int type);
+
+ protected:
+ // InputHandler interface (via DesktopWindow::Callback)
+ void keyEvent(rdr::U32 key, bool down);
+ void pointerEvent(const Point& pos, int buttonMask);
+ void clientCutText(const char* str, int len);
+
+ // DesktopWindow::Callback interface
+ void displayChanged();
+ void paintCompleted();
+ bool sysCommand(WPARAM wParam, LPARAM lParam);
+ void closeWindow();
+ void refreshMenu(bool enableSysCommands);
+
+ // CConnection interface
+ CSecurity* getCSecurity(int secType);
+ void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
+ void bell();
+ void framebufferUpdateEnd();
+ void setDesktopSize(int w, int h);
+ void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+ void setName(const char* name);
+ void serverInit();
+ void serverCutText(const char* str, int len);
+ void beginRect(const Rect& r, unsigned int encoding);
+ void endRect(const Rect& r, unsigned int encoding);
+ void fillRect(const Rect& r, Pixel pix);
+ void imageRect(const Rect& r, void* pixels);
+ void copyRect(const Rect& r, int srcX, int srcY);
+
+ // rdr::FdInStreamBlockCallback interface
+ void blockCallback();
+
+ // UserPasswdGetter interface
+ // (overridden to allow a pre-supplied username & password)
+ void getUserPasswd(char** user, char** password);
+
+ // CConn-specific internal interface
+ void autoSelectFormatAndEncoding();
+ void requestNewUpdate();
+ void calculateFullColourPF();
+
+ // The desktop window
+ DesktopWindow* window;
+
+ // Info and Options dialogs
+ OptionsDialog optionsDialog;
+ InfoDialog infoDialog;
+
+ // VNC Viewer options
+ CConnOptions options;
+
+ // Pixel format and encoding
+ PixelFormat serverDefaultPF;
+ PixelFormat fullColourPF;
+ bool sameMachine;
+ bool encodingChange;
+ bool formatChange;
+ int lastUsedEncoding_;
+
+ // Networking and RFB protocol
+ network::Socket* sock;
+ Handle sockEvent;
+ bool reverseConnection;
+ bool requestUpdate;
+
+ // Debugging/logging
+ std::list<Rect> debugRects;
+ CharArray closeReason_;
+ bool isClosed_;
+
+ FileTransfer m_fileTransfer;
+ };
+
+ };
+
+};
+
+#endif
+
+
diff --git a/win/vncviewer/CConnOptions.cxx b/win/vncviewer/CConnOptions.cxx
new file mode 100644
index 00000000..4ea0ada1
--- /dev/null
+++ b/win/vncviewer/CConnOptions.cxx
@@ -0,0 +1,450 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/CConnOptions.h>
+#include <rfb/Configuration.h>
+#include <rfb/encodings.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/Registry.h>
+#include <rdr/HexInStream.h>
+#include <rdr/HexOutStream.h>
+#include <stdlib.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static StringParameter passwordFile("PasswordFile",
+ "Password file for VNC authentication", "");
+
+// - Settings stored in the registry & in .vnc files, by Save Defaults and
+// Save Configuration respectively.
+
+static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
+static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
+
+static BoolParameter fullColour("FullColor",
+ "Use full color", true);
+static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
+
+static IntParameter lowColourLevel("LowColorLevel",
+ "Color level to use on slow connections. "
+ "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
+ 2);
+static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
+
+static BoolParameter fullScreen("FullScreen",
+ "Use the whole display to show the remote desktop."
+ "(Press F8 to access the viewer menu)",
+ false);
+static StringParameter preferredEncoding("PreferredEncoding",
+ "Preferred encoding to use (Tight, ZRLE, Hextile or"
+ " Raw)", "Tight");
+static BoolParameter autoSelect("AutoSelect",
+ "Auto select pixel format and encoding. "
+ "Default if PreferredEncoding and FullColor are not specified.",
+ true);
+static BoolParameter sharedConnection("Shared",
+ "Allow existing connections to the server to continue."
+ "(Default is to disconnect all other clients)",
+ false);
+
+static BoolParameter sendPtrEvents("SendPointerEvents",
+ "Send pointer (mouse) events to the server.", true);
+static BoolParameter sendKeyEvents("SendKeyEvents",
+ "Send key presses (and releases) to the server.", true);
+
+static BoolParameter clientCutText("ClientCutText",
+ "Send clipboard changes to the server.", true);
+static BoolParameter serverCutText("ServerCutText",
+ "Accept clipboard changes from the server.", true);
+
+static BoolParameter disableWinKeys("DisableWinKeys",
+ "Pass special Windows keys directly to the server.", true);
+
+static BoolParameter protocol3_3("Protocol3.3",
+ "Only use protocol version 3.3", false);
+
+static IntParameter ptrEventInterval("PointerEventInterval",
+ "The interval to delay between sending one pointer event "
+ "and the next.", 0);
+static BoolParameter emulate3("Emulate3",
+ "Emulate middle mouse button when left and right buttons "
+ "are used simulatenously.", false);
+
+static BoolParameter acceptBell("AcceptBell",
+ "Produce a system beep when requested to by the server.",
+ true);
+
+static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true);
+
+static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
+static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
+static BoolParameter autoReconnect("AutoReconnect", "Offer to reconnect to the remote server if the connection"
+ "is dropped because an error occurs.", true);
+
+static BoolParameter customCompressLevel("CustomCompressLevel",
+ "Use custom compression level. "
+ "Default if CompressLevel is specified.", false);
+
+static IntParameter compressLevel("CompressLevel",
+ "Use specified compression level"
+ "0 = Low, 9 = High",
+ 6);
+
+static BoolParameter noJpeg("NoJPEG",
+ "Disable lossy JPEG compression in Tight encoding.",
+ false);
+
+static IntParameter qualityLevel("QualityLevel",
+ "JPEG quality level. "
+ "0 = Low, 9 = High",
+ 6);
+
+CConnOptions::CConnOptions()
+: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
+autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
+preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
+disableWinKeys(::disableWinKeys), protocol3_3(::protocol3_3), acceptBell(::acceptBell),
+lowColourLevel(::lowColourLevel), pointerEventInterval(ptrEventInterval),
+emulate3(::emulate3), monitor(::monitor.getData()), showToolbar(::showToolbar),
+customCompressLevel(::customCompressLevel), compressLevel(::compressLevel),
+noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData()),
+autoReconnect(::autoReconnect)
+{
+ if (autoSelect) {
+ preferredEncoding = encodingZRLE;
+ } else {
+ CharArray encodingName(::preferredEncoding.getData());
+ preferredEncoding = encodingNum(encodingName.buf);
+ }
+ setMenuKey(CharArray(::menuKey.getData()).buf);
+
+ if (!::autoSelect.hasBeenSet()) {
+ // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
+ autoSelect = (!::preferredEncoding.hasBeenSet()
+ && !::fullColour.hasBeenSet()
+ && !::fullColourAlias.hasBeenSet());
+ }
+ if (!::customCompressLevel.hasBeenSet()) {
+ // Default to CustomCompressLevel=1 if CompressLevel is used.
+ customCompressLevel = ::compressLevel.hasBeenSet();
+ }
+}
+
+
+void CConnOptions::readFromFile(const char* filename) {
+ FILE* f = fopen(filename, "r");
+ if (!f)
+ throw rdr::Exception("Failed to read configuration file");
+
+ try {
+ char line[4096];
+ CharArray section;
+
+ CharArray hostTmp;
+ int portTmp = 0;
+
+ while (!feof(f)) {
+ // Read the next line
+ if (!fgets(line, sizeof(line), f)) {
+ if (feof(f))
+ break;
+ throw rdr::SystemException("fgets", ferror(f));
+ }
+ int len=strlen(line);
+ if (line[len-1] == '\n') {
+ line[len-1] = 0;
+ len--;
+ }
+
+ // Process the line
+ if (line[0] == ';') {
+ // Comment
+ } else if (line[0] == '[') {
+ // Entering a new section
+ if (!strSplit(&line[1], ']', &section.buf, 0))
+ throw rdr::Exception("bad Section");
+ } else {
+ // Reading an option
+ CharArray name;
+ CharArray value;
+ if (!strSplit(line, '=', &name.buf, &value.buf))
+ throw rdr::Exception("bad Name/Value pair");
+
+ if (stricmp(section.buf, "Connection") == 0) {
+ if (stricmp(name.buf, "Host") == 0) {
+ hostTmp.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "Port") == 0) {
+ portTmp = atoi(value.buf);
+ } else if (stricmp(name.buf, "UserName") == 0) {
+ userName.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "Password") == 0) {
+ ObfuscatedPasswd obfPwd;
+ rdr::HexInStream::hexStrToBin(value.buf, (char**)&obfPwd.buf, &obfPwd.length);
+ PlainPasswd passwd(obfPwd);
+ password.replaceBuf(passwd.takeBuf());
+ }
+ } else if (stricmp(section.buf, "Options") == 0) {
+ // V4 options
+ if (stricmp(name.buf, "UseLocalCursor") == 0) {
+ useLocalCursor = atoi(value.buf);
+ } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
+ useDesktopResize = atoi(value.buf);
+ } else if (stricmp(name.buf, "FullScreen") == 0) {
+ fullScreen = atoi(value.buf);
+ } else if (stricmp(name.buf, "FullColour") == 0) {
+ fullColour = atoi(value.buf);
+ } else if (stricmp(name.buf, "LowColourLevel") == 0) {
+ lowColourLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
+ preferredEncoding = encodingNum(value.buf);
+ } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
+ (stricmp(name.buf, "AutoSelect") == 0)) {
+ autoSelect = atoi(value.buf);
+ } else if (stricmp(name.buf, "Shared") == 0) {
+ shared = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
+ sendPtrEvents = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
+ sendKeyEvents = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendCutText") == 0) {
+ clientCutText = atoi(value.buf);
+ } else if (stricmp(name.buf, "AcceptCutText") == 0) {
+ serverCutText = atoi(value.buf);
+ } else if (stricmp(name.buf, "DisableWinKeys") == 0) {
+ disableWinKeys = atoi(value.buf);
+ } else if (stricmp(name.buf, "AcceptBell") == 0) {
+ acceptBell = atoi(value.buf);
+ } else if (stricmp(name.buf, "Emulate3") == 0) {
+ emulate3 = atoi(value.buf);
+ } else if (stricmp(name.buf, "ShowToolbar") == 0) {
+ showToolbar = atoi(value.buf);
+ } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
+ pointerEventInterval = atoi(value.buf);
+ } else if (stricmp(name.buf, "Monitor") == 0) {
+ monitor.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "MenuKey") == 0) {
+ setMenuKey(value.buf);
+ } else if (stricmp(name.buf, "AutoReconnect") == 0) {
+ autoReconnect = atoi(value.buf);
+
+ } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
+ customCompressLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "CompressLevel") == 0) {
+ compressLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "NoJPEG") == 0) {
+ noJpeg = atoi(value.buf);
+ } else if (stricmp(name.buf, "QualityLevel") == 0) {
+ qualityLevel = atoi(value.buf);
+ // Legacy options
+ } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
+ preferredEncoding = atoi(value.buf);
+ } else if (stricmp(name.buf, "8bit") == 0) {
+ fullColour = !atoi(value.buf);
+ } else if (stricmp(name.buf, "FullScreen") == 0) {
+ fullScreen = atoi(value.buf);
+ } else if (stricmp(name.buf, "ViewOnly") == 0) {
+ sendPtrEvents = sendKeyEvents = !atoi(value.buf);
+ } else if (stricmp(name.buf, "DisableClipboard") == 0) {
+ clientCutText = serverCutText = !atoi(value.buf);
+ }
+ }
+ }
+ }
+ fclose(f); f=0;
+
+ // Process the Host and Port
+ if (hostTmp.buf) {
+ int hostLen = strlen(hostTmp.buf) + 2 + 17;
+ host.replaceBuf(new char[hostLen]);
+ strCopy(host.buf, hostTmp.buf, hostLen);
+ if (portTmp) {
+ strncat(host.buf, "::", hostLen-1);
+ char tmp[16];
+ sprintf(tmp, "%d", portTmp);
+ strncat(host.buf, tmp, hostLen-1);
+ }
+ }
+
+ // If AutoSelect is enabled then override the preferred encoding
+ if (autoSelect)
+ preferredEncoding = encodingZRLE;
+
+ setConfigFileName(filename);
+ } catch (rdr::Exception&) {
+ if (f) fclose(f);
+ throw;
+ }
+}
+
+void CConnOptions::writeToFile(const char* filename) {
+ FILE* f = fopen(filename, "w");
+ if (!f)
+ throw rdr::Exception("Failed to write configuration file");
+
+ try {
+ // - Split server into host and port and save
+ fprintf(f, "[Connection]\n");
+
+ fprintf(f, "Host=%s\n", host.buf);
+ if (userName.buf)
+ fprintf(f, "UserName=%s\n", userName.buf);
+ if (password.buf) {
+ // - Warn the user before saving the password
+ if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
+ _T("Storing the password is more convenient but poses a security risk."),
+ MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
+ ObfuscatedPasswd obfPwd(password);
+ CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length);
+ fprintf(f, "Password=%s\n", obfuscatedHex.buf);
+ }
+ }
+
+ // - Save the other options
+ fprintf(f, "[Options]\n");
+
+ fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
+ fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
+ fprintf(f, "FullScreen=%d\n", (int)fullScreen);
+ fprintf(f, "FullColour=%d\n", (int)fullColour);
+ fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
+ fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
+ fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
+ fprintf(f, "Shared=%d\n", (int)shared);
+ fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
+ fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
+ fprintf(f, "SendCutText=%d\n", (int)clientCutText);
+ fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
+ fprintf(f, "DisableWinKeys=%d\n", (int)disableWinKeys);
+ fprintf(f, "AcceptBell=%d\n", (int)acceptBell);
+ fprintf(f, "Emulate3=%d\n", (int)emulate3);
+ fprintf(f, "ShowToolbar=%d\n", (int)showToolbar);
+ fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
+ if (monitor.buf)
+ fprintf(f, "Monitor=%s\n", monitor.buf);
+ fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
+ fprintf(f, "AutoReconnect=%d\n", (int)autoReconnect);
+ fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
+ fprintf(f, "CompressLevel=%d\n", compressLevel);
+ fprintf(f, "NoJPEG=%d\n", noJpeg);
+ fprintf(f, "QualityLevel=%d\n", qualityLevel);
+ fclose(f); f=0;
+
+ setConfigFileName(filename);
+ } catch (rdr::Exception&) {
+ if (f) fclose(f);
+ throw;
+ }
+}
+
+
+void CConnOptions::writeDefaults() {
+ RegKey key;
+ key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
+ key.setBool(_T("UseLocalCursor"), useLocalCursor);
+ key.setBool(_T("UseDesktopResize"), useDesktopResize);
+ key.setBool(_T("FullScreen"), fullScreen);
+ key.setBool(_T("FullColour"), fullColour);
+ key.setInt(_T("LowColourLevel"), lowColourLevel);
+ key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
+ key.setBool(_T("AutoSelect"), autoSelect);
+ key.setBool(_T("Shared"), shared);
+ key.setBool(_T("SendPointerEvents"), sendPtrEvents);
+ key.setBool(_T("SendKeyEvents"), sendKeyEvents);
+ key.setBool(_T("ClientCutText"), clientCutText);
+ key.setBool(_T("ServerCutText"), serverCutText);
+ key.setBool(_T("DisableWinKeys"), disableWinKeys);
+ key.setBool(_T("Protocol3.3"), protocol3_3);
+ key.setBool(_T("AcceptBell"), acceptBell);
+ key.setBool(_T("ShowToolbar"), showToolbar);
+ key.setBool(_T("Emulate3"), emulate3);
+ key.setInt(_T("PointerEventInterval"), pointerEventInterval);
+ if (monitor.buf)
+ key.setString(_T("Monitor"), TStr(monitor.buf));
+ key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
+ key.setBool(_T("AutoReconnect"), autoReconnect);
+ key.setInt(_T("CustomCompressLevel"), customCompressLevel);
+ key.setInt(_T("CompressLevel"), compressLevel);
+ key.setInt(_T("NoJPEG"), noJpeg);
+ key.setInt(_T("QualityLevel"), qualityLevel);
+}
+
+
+void CConnOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
+void CConnOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
+void CConnOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
+void CConnOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
+void CConnOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
+
+void CConnOptions::setMenuKey(const char* keyName) {
+ if (!keyName[0]) {
+ menuKey = 0;
+ } else {
+ menuKey = VK_F8;
+ if (keyName[0] == 'F') {
+ UINT fKey = atoi(&keyName[1]);
+ if (fKey >= 1 && fKey <= 12)
+ menuKey = fKey-1 + VK_F1;
+ }
+ }
+}
+char* CConnOptions::menuKeyName() {
+ int fNum = (menuKey-VK_F1)+1;
+ if (fNum<1 || fNum>12)
+ return strDup("");
+ CharArray menuKeyStr(4);
+ sprintf(menuKeyStr.buf, "F%d", fNum);
+ return menuKeyStr.takeBuf();
+}
+
+
+CConnOptions& CConnOptions::operator=(const CConnOptions& o) {
+ useLocalCursor = o.useLocalCursor;
+ useDesktopResize = o.useDesktopResize;
+ fullScreen = o.fullScreen;
+ fullColour = o.fullColour;
+ lowColourLevel = o.lowColourLevel;
+ preferredEncoding = o.preferredEncoding;
+ autoSelect = o.autoSelect;
+ shared = o.shared;
+ sendPtrEvents = o.sendPtrEvents;
+ sendKeyEvents = o.sendKeyEvents;
+ clientCutText = o.clientCutText;
+ serverCutText = o.serverCutText;
+ disableWinKeys = o.disableWinKeys;
+ emulate3 = o.emulate3;
+ pointerEventInterval = o.pointerEventInterval;
+ protocol3_3 = o.protocol3_3;
+ acceptBell = o.acceptBell;
+ showToolbar = o.showToolbar;
+ setUserName(o.userName.buf);
+ setPassword(o.password.buf);
+ setConfigFileName(o.configFileName.buf);
+ setHost(o.host.buf);
+ setMonitor(o.monitor.buf);
+ menuKey = o.menuKey;
+ autoReconnect = o.autoReconnect;
+ customCompressLevel = o.customCompressLevel;
+ compressLevel = o.compressLevel;
+ noJpeg = o.noJpeg;
+ qualityLevel = o.qualityLevel;
+
+ return *this;
+}
diff --git a/win/vncviewer/CConnOptions.h b/win/vncviewer/CConnOptions.h
new file mode 100644
index 00000000..59fd0a3c
--- /dev/null
+++ b/win/vncviewer/CConnOptions.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConnOptions.h
+
+// Definition of the CConnOptions class, responsible for storing the
+// current & requested VNC Viewer options.
+
+#ifndef __RFB_WIN32_CCONN_OPTIONS_H__
+#define __RFB_WIN32_CCONN_OPTIONS_H__
+
+#include <rfb/Password.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ //
+ // -=- Options structure. Each viewer option has a corresponding
+ // entry in CConnOptions. The viewer options are set by calling
+ // CConn::applyOptions(...)
+ // The CConnOptions structure automatically picks up the default
+ // value of each option from the Configuration system
+ // The readFromFile and writeFromFile methods can be used to load
+ // and save VNC configuration files. readFromFile is backwards
+ // compatible with 3.3 releases, while writeToFile is not.
+
+ class CConnOptions {
+ public:
+ CConnOptions();
+ CConnOptions(const CConnOptions& o) {operator=(o);}
+ CConnOptions& operator=(const CConnOptions& o);
+ void readFromFile(const char* filename_);
+ void writeToFile(const char* filename_);
+ void writeDefaults();
+ bool useLocalCursor;
+ bool useDesktopResize;
+ bool fullScreen;
+ bool fullColour;
+ int lowColourLevel;
+ int preferredEncoding;
+ bool autoSelect;
+ bool shared;
+ bool sendPtrEvents;
+ bool sendKeyEvents;
+ bool showToolbar;
+ bool clientCutText;
+ bool serverCutText;
+ bool disableWinKeys;
+ bool emulate3;
+ int pointerEventInterval;
+ bool protocol3_3;
+ bool acceptBell;
+ CharArray userName;
+ void setUserName(const char* user);
+ PlainPasswd password;
+ void setPassword(const char* pwd);
+ CharArray configFileName;
+ void setConfigFileName(const char* cfn);
+ CharArray host;
+ void setHost(const char* h);
+ CharArray monitor;
+ void setMonitor(const char* m);
+ unsigned int menuKey;
+ void setMenuKey(const char* keyName);
+ char* menuKeyName();
+ bool autoReconnect;
+
+ bool customCompressLevel;
+ int compressLevel;
+ bool noJpeg;
+ int qualityLevel;
+
+ CharArray passwordFile;
+ };
+
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/CConnThread.cxx b/win/vncviewer/CConnThread.cxx
new file mode 100644
index 00000000..cfd26952
--- /dev/null
+++ b/win/vncviewer/CConnThread.cxx
@@ -0,0 +1,198 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConnThread.cxx
+
+// A CConnThread instance is created for each new connection.
+// The CConnThread creates the corresponding CConn instance
+// and manages it.
+
+#include <stdlib.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Hostname.h>
+#include <rfb_win32/MsgBox.h>
+#include <network/TcpSocket.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <set>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CConnThread");
+
+static std::set<CConnThread*> threads;
+static Mutex threadsLock;
+static Handle noMoreThreads(CreateEvent(0, TRUE, FALSE, 0));
+
+
+CConnThread::CConnThread() : Thread("CConnThread"), isConfig(false),
+ sock(0), reverse(false) {
+ vlog.info("CConnThread (dialog)");
+ setDeleteAfterRun();
+ Lock l(threadsLock);
+ threads.insert(this);
+ start();
+}
+
+CConnThread::CConnThread(const char* hostOrConfig_, bool isConfig_)
+ : Thread("CConnThread"), hostOrConfig(strDup(hostOrConfig_)),
+ isConfig(isConfig_), sock(0), reverse(false) {
+ vlog.info("CConnThread (host/port)");
+ setDeleteAfterRun();
+ Lock l(threadsLock);
+ threads.insert(this);
+ start();
+}
+
+CConnThread::CConnThread(network::Socket* sock_, bool reverse_)
+ : Thread("CConnThread"), isConfig(false), sock(sock_), reverse(reverse_) {
+ vlog.info("CConnThread (reverse connection)");
+ setDeleteAfterRun();
+ Lock l(threadsLock);
+ threads.insert(this);
+ start();
+}
+
+CConnThread::~CConnThread() {
+ Lock l(threadsLock);
+ threads.erase(this);
+ if (threads.empty())
+ SetEvent(noMoreThreads);
+ delete sock;
+}
+
+
+void CConnThread::run() {
+ CConnOptions options;
+ bool reconnect;
+
+ do {
+ {
+ CConn conn;
+ reconnect = false;
+
+ // If there is no socket object then set the host & port info
+ if (!sock && !options.host.buf) {
+ try {
+ if (isConfig) {
+ // A configuration file name was specified - load it
+ CharArray filename = hostOrConfig.takeBuf();
+ options.readFromFile(filename.buf);
+ } else {
+ // An actual hostname (and possibly port) was specified
+ options.host.replaceBuf(hostOrConfig.takeBuf());
+ }
+
+ if (!options.host.buf) {
+ // No host was specified - prompt for one
+ ConnectionDialog connDlg(&conn);
+ if (!connDlg.showDialog())
+ return;
+ options = conn.getOptions();
+ options.setHost(CStr(connDlg.hostname.buf));
+ }
+ } catch (rdr::Exception& e) {
+ MsgBox(0, TStr(e.str()), MB_ICONERROR | MB_OK);
+ return;
+ }
+ }
+
+ // Apply the connection options to the CConn
+ conn.applyOptions(options);
+
+ if (!sock) {
+ // There is no existing connection - better make one
+ const char* hostAndPort = conn.getOptions().host.buf;
+
+ try {
+ ConnectingDialog dlg;
+ sock = dlg.connect(hostAndPort);
+
+ // If the connection was cancelled by the user, just quit
+ if (!sock)
+ return;
+ } catch(rdr::Exception& e) {
+ MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ // Try to add the caller to the MRU
+ MRU::addToMRU(hostAndPort);
+ }
+
+ // Run the RFB protocol over the connected socket
+ conn.initialise(sock, reverse);
+ while (!conn.isClosed()) {
+ try {
+ conn.getInStream()->check(1,1);
+ conn.processMsg();
+ } catch (rdr::EndOfStream) {
+ if (conn.state() == CConnection::RFBSTATE_NORMAL)
+ conn.close();
+ else
+ conn.close("The connection closed unexpectedly");
+ } catch (rfb::AuthCancelledException) {
+ conn.close();
+ } catch (rfb::AuthFailureException& e) {
+ // Clear the password, in case we auto-reconnect
+ options = conn.getOptions();
+ options.password.replaceBuf(0);
+ conn.applyOptions(options);
+ conn.close(e.str());
+ } catch (rdr::Exception& e) {
+ conn.close(e.str());
+ }
+ }
+
+ // If there is a cause for closing the connection logged then display it
+ if (conn.closeReason()) {
+ reconnect = !reverse && conn.getOptions().autoReconnect;
+ if (!reconnect) {
+ MsgBox(0, TStr(conn.closeReason()), MB_ICONINFORMATION | MB_OK);
+ } else {
+ options = conn.getOptions();
+ const char* format = "%s\nDo you wish to attempt to reconnect to %s?";
+ CharArray message(strlen(conn.closeReason()) + strlen(format) +
+ strlen(conn.getOptions().host.buf));
+ sprintf(message.buf, format, conn.closeReason(), conn.getOptions().host.buf);
+ if (MsgBox(0, TStr(message.buf), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
+ reconnect = false;
+ }
+ }
+ } // Exit the CConn's scope, implicitly destroying it & making it safe to delete the TcpSocket
+
+ // Clean up the old socket, if any
+ delete sock; sock = 0;
+ } while (reconnect);
+}
+
+
+BOOL CConnThread::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
+ while (!PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE)) {
+ DWORD result = MsgWaitForMultipleObjects(1, &noMoreThreads.h, FALSE, INFINITE, QS_ALLINPUT);
+ if (result == WAIT_OBJECT_0)
+ return FALSE;
+ else if (result == WAIT_FAILED)
+ throw rdr::SystemException("CConnThread::getMessage wait failed", GetLastError());
+ }
+ return msg->message != WM_QUIT;
+}
diff --git a/win/vncviewer/CConnThread.h b/win/vncviewer/CConnThread.h
new file mode 100644
index 00000000..7a8451c1
--- /dev/null
+++ b/win/vncviewer/CConnThread.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConnThread.h
+
+// CConn-managing Thread implementation.
+
+#ifndef __RFB_WIN32_CCONN_THREAD_H__
+#define __RFB_WIN32_CCONN_THREAD_H__
+
+#include <network/Socket.h>
+#include <rfb/Threading.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConnThread : public Thread {
+ public:
+ CConnThread();
+ CConnThread(const char* hostOrConfig, bool isConfig=false);
+ CConnThread(network::Socket* sock, bool reverse=false);
+ ~CConnThread();
+
+ void run();
+
+ // Special getMessage call that returns FALSE if message is WM_QUIT,
+ // OR if there are no more CConnThreads running.
+ static BOOL getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg);
+ protected:
+ CharArray hostOrConfig;
+ bool isConfig;
+ network::Socket* sock;
+ bool reverse;
+ };
+
+ };
+
+};
+
+#endif // __RFB_WIN32_CCONN_THREAD_H__
diff --git a/win/vncviewer/ConnectingDialog.cxx b/win/vncviewer/ConnectingDialog.cxx
new file mode 100644
index 00000000..60fcb661
--- /dev/null
+++ b/win/vncviewer/ConnectingDialog.cxx
@@ -0,0 +1,160 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ConnectingDialog.cxx
+
+#include <stdlib.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/resource.h>
+#include <network/TcpSocket.h>
+#include <rfb/Threading.h>
+#include <rfb/Hostname.h>
+#include <map>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// ConnectingDialog callback
+static BOOL CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+ bool* activePtr = (bool*)GetWindowLong(hwnd, GWL_USERDATA);
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwnd, GWL_USERDATA, lParam);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ if (activePtr)
+ *activePtr = false;
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ if (activePtr)
+ *activePtr = false;
+ return TRUE;
+ }
+ return 0;
+}
+
+
+// Global map, used by ConnectingDialog::Threads to call back to their owning
+// ConnectingDialogs, while coping with the fact that the owner may already have quit.
+static std::map<int, ConnectingDialog*> dialogs;
+static int nextDialogId = 0;
+static Mutex dialogsLock;
+
+
+// ConnectingDialog::Thread
+// Attempts to connect to the specified host. If the connection succeeds, the
+// socket is saved in the owning ConnectingDialog, if still available, and the
+// event is signalled. If the connection fails, the Exception text is returned
+// to the dialog. If the dialog is already gone, the Exception/socket are discarded.
+// NB: This thread class cleans itself up on exit - DO NOT join()!
+class ConnectingDialog::Thread : public rfb::Thread {
+public:
+ Thread(int dialogId_, const char* hostAndPort) : dialogId(dialogId_) {
+ setDeleteAfterRun();
+ getHostAndPort(hostAndPort, &host.buf, &port);
+ }
+ virtual void run() {
+ try {
+ returnSock(new network::TcpSocket(host.buf, port));
+ } catch (rdr::Exception& e) {
+ returnException(e);
+ }
+ }
+ void returnSock(network::Socket* s) {
+ Lock l(dialogsLock);
+ if (dialogs.count(dialogId)) {
+ dialogs[dialogId]->newSocket = s;
+ SetEvent(dialogs[dialogId]->readyEvent);
+ } else {
+ delete s;
+ }
+ }
+ void returnException(const rdr::Exception& e) {
+ Lock l(dialogsLock);
+ if (dialogs.count(dialogId)) {
+ dialogs[dialogId]->errMsg.replaceBuf(strDup(e.str()));
+ SetEvent(dialogs[dialogId]->readyEvent);
+ }
+ };
+ CharArray host;
+ int port;
+ int dialogId;
+};
+
+
+ConnectingDialog::ConnectingDialog() : dialog(0), readyEvent(CreateEvent(0, TRUE, FALSE, 0)),
+ newSocket(0), dialogId(0) {
+}
+
+network::Socket* ConnectingDialog::connect(const char* hostAndPort) {
+ Thread* connectThread = 0;
+ bool active = true;
+ errMsg.replaceBuf(0);
+ newSocket = 0;
+
+ // Get a unique dialog identifier and create the dialog window
+ {
+ Lock l(dialogsLock);
+ dialogId = ++nextDialogId;
+ dialogs[dialogId] = this;
+ dialog = CreateDialogParam(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDD_CONNECTING_DLG), 0, &ConnectingDlgProc, (long)&active);
+ ShowWindow(dialog, SW_SHOW);
+ ResetEvent(readyEvent);
+ }
+
+ // Create and start the connection thread
+ try {
+ connectThread = new Thread(dialogId, hostAndPort);
+ connectThread->start();
+ } catch (rdr::Exception& e) {
+ errMsg.replaceBuf(strDup(e.str()));
+ active = false;
+ }
+
+ // Process window messages until the connection thread signals readyEvent, or the dialog is cancelled
+ while (active && (MsgWaitForMultipleObjects(1, &readyEvent.h, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)) {
+ MSG msg;
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ DispatchMessage(&msg);
+ }
+
+ // Remove this dialog from the table
+ // NB: If the dialog was cancelled then the thread is still running, and will only
+ // discover that we're gone when it looks up our unique Id in the dialog table.
+ {
+ Lock l(dialogsLock);
+ dialogs.erase(dialogId);
+ }
+
+ // Close the dialog window
+ DestroyWindow(dialog); dialog=0;
+
+ // Throw the exception, if there was one
+ if (errMsg.buf)
+ throw rdr::Exception(errMsg.buf);
+
+ // Otherwise, return the socket
+ // NB: The socket will be null if the dialog was cancelled
+ return newSocket;
+}
diff --git a/win/vncviewer/ConnectingDialog.h b/win/vncviewer/ConnectingDialog.h
new file mode 100644
index 00000000..c38b3a1b
--- /dev/null
+++ b/win/vncviewer/ConnectingDialog.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ConnectingDialog.h
+
+// ConnectingDialog instances are used to display a status dialog while a
+// connection attempt is in progress. The connection attempt is performed
+// in a background thread by the ConnectingDialog, to allow the status dialog
+// to remain interactive. If the dialog is cancelled then it will close and
+// the connection dialog will eventually tidy itself up.
+
+#ifndef __RFB_WIN32_CONNECTING_DLG_H__
+#define __RFB_WIN32_CONNECTING_DLG_H__
+
+#include <windows.h>
+#include <network/Socket.h>
+#include <rfb/util.h>
+#include <rfb_win32/Handle.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class ConnectingDialog {
+ public:
+ ConnectingDialog();
+
+ // connect
+ // Show a Connecting dialog and attempt to connect to the specified host
+ // in the background.
+ // If the connection succeeds then the Socket is returned.
+ // If an error occurs, an Exception is thrown.
+ // If the dialog is cancelled then null is returned.
+ network::Socket* connect(const char* hostAndPort);
+ protected:
+ HWND dialog;
+ network::Socket* newSocket;
+ CharArray errMsg;
+ Handle readyEvent;
+ int dialogId;
+
+ class Thread;
+ friend class Thread;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/ConnectionDialog.cxx b/win/vncviewer/ConnectionDialog.cxx
new file mode 100644
index 00000000..e7c6b0a5
--- /dev/null
+++ b/win/vncviewer/ConnectionDialog.cxx
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/AboutDialog.h>
+
+#include <tchar.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+ConnectionDialog::ConnectionDialog(CConn* conn_) : Dialog(GetModuleHandle(0)), conn(conn_) {
+}
+
+
+bool ConnectionDialog::showDialog() {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_DLG));
+}
+
+void ConnectionDialog::initDialog() {
+ HWND box = GetDlgItem(handle, IDC_SERVER_EDIT);
+
+ std::list<char*> mru = MRU::getEntries();
+ std::list<char*>::iterator i;
+
+ // Locate the combo-box
+ // NB: TCharArray converts the supplied char* and assumes ownership!
+ for (i=mru.begin(); i!=mru.end(); i++) {
+ int index = SendMessage(box, CB_ADDSTRING, 0, (LPARAM)TCharArray(*i).buf);
+ }
+
+ // Select the first item in the list
+ SendMessage(box, CB_SETCURSEL, 0, 0);
+
+ // Fill out the Security: drop-down and select the preferred option
+ HWND security = GetDlgItem(handle, IDC_SECURITY_LEVEL);
+ LRESULT n = SendMessage(security, CB_ADDSTRING, 0, (LPARAM)_T("Always Off"));
+ if (n != CB_ERR)
+ SendMessage(security, CB_SETCURSEL, n, 0);
+ enableItem(IDC_SECURITY_LEVEL, false);
+}
+
+
+bool ConnectionDialog::onOk() {
+ delete [] hostname.buf;
+ hostname.buf = 0;
+ hostname.buf = getItemString(IDC_SERVER_EDIT);
+ return hostname.buf[0] != 0;
+}
+
+bool ConnectionDialog::onCommand(int id, int cmd) {
+ switch (id) {
+ case IDC_ABOUT:
+ AboutDialog::instance.showDialog();
+ return true;
+ case IDC_OPTIONS:
+ conn->showOptionsDialog();
+ return true;
+ };
+ return false;
+}
diff --git a/win/vncviewer/ConnectionDialog.h b/win/vncviewer/ConnectionDialog.h
new file mode 100644
index 00000000..f739280c
--- /dev/null
+++ b/win/vncviewer/ConnectionDialog.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ConnectionDialog.h
+
+// Connection dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_CONN_DIALOG_H__
+#define __RFB_WIN32_CONN_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <vncviewer/MRU.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConn;
+
+ class ConnectionDialog : Dialog {
+ public:
+ ConnectionDialog(CConn* view);
+ virtual bool showDialog();
+ virtual void initDialog();
+ virtual bool onOk();
+ virtual bool onCommand(int id, int cmd);
+ TCharArray hostname;
+ protected:
+ CConn* conn;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/DesktopWindow.cxx b/win/vncviewer/DesktopWindow.cxx
new file mode 100644
index 00000000..27ef2dc2
--- /dev/null
+++ b/win/vncviewer/DesktopWindow.cxx
@@ -0,0 +1,1103 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/LowLevelKeyEvents.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/Win32Util.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/resource.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// - Statics & consts
+
+static LogWriter vlog("DesktopWindow");
+
+const int TIMER_BUMPSCROLL = 1;
+const int TIMER_POINTER_INTERVAL = 2;
+const int TIMER_POINTER_3BUTTON = 3;
+
+
+//
+// -=- DesktopWindowClass
+
+//
+// Window class used as the basis for all DesktopWindow instances
+//
+
+class DesktopWindowClass {
+public:
+ DesktopWindowClass();
+ ~DesktopWindowClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK DesktopWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+ if (msg == WM_CREATE)
+ SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(wnd, GWL_USERDATA, 0);
+ DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", wnd, msg);
+ return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processMessage(msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+};
+
+static HCURSOR dotCursor = (HCURSOR)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDC_DOT_CURSOR), IMAGE_CURSOR, 0, 0, LR_SHARED);
+static HCURSOR arrowCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
+
+DesktopWindowClass::DesktopWindowClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = DesktopWindowProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+ if (!wndClass.hIcon)
+ printf("unable to load icon:%ld", GetLastError());
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("rfb::win32::DesktopWindowClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register DesktopWindow window class", GetLastError());
+ }
+}
+
+DesktopWindowClass::~DesktopWindowClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+DesktopWindowClass baseClass;
+
+//
+// -=- FrameClass
+
+//
+// Window class used for child windows that display pixel data
+//
+
+class FrameClass {
+public:
+ FrameClass();
+ ~FrameClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+ if (msg == WM_CREATE)
+ SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(wnd, GWL_USERDATA, 0);
+ DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", wnd, msg);
+ return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processFrameMessage(msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+}
+
+FrameClass::FrameClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = FrameProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = 0;
+ wndClass.hCursor = NULL;
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("rfb::win32::FrameClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register Frame window class", GetLastError());
+ }
+}
+
+FrameClass::~FrameClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+FrameClass frameClass;
+
+
+//
+// -=- DesktopWindow instance implementation
+//
+
+DesktopWindow::DesktopWindow(Callback* cb)
+ : buffer(0),
+ showToolbar(false),
+ client_size(0, 0, 16, 16), window_size(0, 0, 32, 32),
+ cursorVisible(false), cursorAvailable(false), cursorInBuffer(false),
+ systemCursorVisible(true), trackingMouseLeave(false),
+ handle(0), frameHandle(0), has_focus(false), palette_changed(false),
+ fullscreenActive(false), fullscreenRestore(false),
+ bumpScroll(false), callback(cb) {
+
+ // Create the window
+ const char* name = "DesktopWindow";
+ handle = CreateWindow((const TCHAR*)baseClass.classAtom, TStr(name),
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ 0, 0, 10, 10, 0, 0, baseClass.instance, this);
+ if (!handle)
+ throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+ vlog.debug("created window \"%s\" (%x)", name, handle);
+
+ // Create the toolbar
+ tb.create(handle);
+ vlog.debug("created toolbar window \"%s\" (%x)", "ViewerToolBar", tb.getHandle());
+
+ // Create the frame window
+ frameHandle = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+ 0, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, handle, 0, frameClass.instance, this);
+ if (!frameHandle) {
+ throw rdr::SystemException("unable to create rfb frame window instance", GetLastError());
+ }
+ vlog.debug("created window \"%s\" (%x)", "Frame Window", frameHandle);
+
+ // Initialise the CPointer pointer handler
+ ptr.setHWND(frameHandle);
+ ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL);
+ ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON);
+
+ // Initialise the bumpscroll timer
+ bumpScrollTimer.setHWND(handle);
+ bumpScrollTimer.setId(TIMER_BUMPSCROLL);
+
+ // Hook the clipboard
+ clipboard.setNotifier(this);
+
+ // Create the backing buffer
+ buffer = new win32::ScaledDIBSectionBuffer(frameHandle);
+
+ // Show the window
+ centerWindow(handle, 0);
+ ShowWindow(handle, SW_SHOW);
+}
+
+DesktopWindow::~DesktopWindow() {
+ vlog.debug("~DesktopWindow");
+ showSystemCursor();
+ if (handle) {
+ disableLowLevelKeyEvents(handle);
+ DestroyWindow(handle);
+ handle = 0;
+ }
+ delete buffer;
+ vlog.debug("~DesktopWindow done");
+}
+
+
+void DesktopWindow::setFullscreen(bool fs) {
+ if (fs && !fullscreenActive) {
+ fullscreenActive = bumpScroll = true;
+
+ // Un-minimize the window if required
+ if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE)
+ ShowWindow(handle, SW_RESTORE);
+
+ // Save the current window position
+ GetWindowRect(handle, &fullscreenOldRect);
+
+ // Find the size of the display the window is on
+ MonitorInfo mi(handle);
+
+ // Hide the toolbar
+ if (tb.isVisible())
+ tb.hide();
+ SetWindowLong(frameHandle, GWL_EXSTYLE, 0);
+
+ // Set the window full-screen
+ DWORD flags = GetWindowLong(handle, GWL_STYLE);
+ fullscreenOldFlags = flags;
+ flags = flags & ~(WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZE | WS_MINIMIZE);
+ vlog.debug("flags=%x", flags);
+
+ SetWindowLong(handle, GWL_STYLE, flags);
+ SetWindowPos(handle, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
+ mi.rcMonitor.right-mi.rcMonitor.left,
+ mi.rcMonitor.bottom-mi.rcMonitor.top,
+ SWP_FRAMECHANGED);
+ } else if (!fs && fullscreenActive) {
+ fullscreenActive = bumpScroll = false;
+
+ // Show the toolbar
+ if (showToolbar)
+ tb.show();
+ SetWindowLong(frameHandle, GWL_EXSTYLE, WS_EX_CLIENTEDGE);
+
+ // Set the window non-fullscreen
+ SetWindowLong(handle, GWL_STYLE, fullscreenOldFlags);
+
+ // Set the window position
+ SetWindowPos(handle, HWND_NOTOPMOST,
+ fullscreenOldRect.left, fullscreenOldRect.top,
+ fullscreenOldRect.right - fullscreenOldRect.left,
+ fullscreenOldRect.bottom - fullscreenOldRect.top,
+ SWP_FRAMECHANGED);
+ }
+
+ // Adjust the viewport offset to cope with change in size between FS
+ // and previous window state.
+ setViewportOffset(scrolloffset);
+}
+
+void DesktopWindow::setShowToolbar(bool st)
+{
+ showToolbar = st;
+
+ if (showToolbar && !tb.isVisible() && !fullscreenActive) {
+ tb.show();
+ } else if (!showToolbar && tb.isVisible()) {
+ tb.hide();
+ }
+}
+
+void DesktopWindow::setDisableWinKeys(bool dwk) {
+ // Enable low-level event hooking, so we get special keys directly
+ if (dwk)
+ enableLowLevelKeyEvents(handle);
+ else
+ disableLowLevelKeyEvents(handle);
+}
+
+
+void DesktopWindow::setMonitor(const char* monitor) {
+ MonitorInfo mi(monitor);
+ mi.moveTo(handle);
+}
+
+char* DesktopWindow::getMonitor() const {
+ MonitorInfo mi(handle);
+ return strDup(mi.szDevice);
+}
+
+
+bool DesktopWindow::setViewportOffset(const Point& tl) {
+ Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+ max(0, min(tl.y, buffer->height()-client_size.height())));
+ Point delta = np.translate(scrolloffset.negate());
+ if (!np.equals(scrolloffset)) {
+ scrolloffset = np;
+ ScrollWindowEx(frameHandle, -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+ UpdateWindow(frameHandle);
+ return true;
+ }
+ return false;
+}
+
+
+bool DesktopWindow::processBumpScroll(const Point& pos)
+{
+ if (!bumpScroll) return false;
+ int bumpScrollPixels = 20;
+ bumpScrollDelta = Point();
+
+ if (pos.x == client_size.width()-1)
+ bumpScrollDelta.x = bumpScrollPixels;
+ else if (pos.x == 0)
+ bumpScrollDelta.x = -bumpScrollPixels;
+ if (pos.y == client_size.height()-1)
+ bumpScrollDelta.y = bumpScrollPixels;
+ else if (pos.y == 0)
+ bumpScrollDelta.y = -bumpScrollPixels;
+
+ if (bumpScrollDelta.x || bumpScrollDelta.y) {
+ if (bumpScrollTimer.isActive()) return true;
+ if (setViewportOffset(scrolloffset.translate(bumpScrollDelta))) {
+ bumpScrollTimer.start(25);
+ return true;
+ }
+ }
+
+ bumpScrollTimer.stop();
+ return false;
+}
+
+
+LRESULT
+DesktopWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ // -=- Process standard window messages
+
+ case WM_NOTIFY:
+ if (wParam == ID_TOOLBAR)
+ tb.processWM_NOTIFY(wParam, lParam);
+ break;
+
+ case WM_DISPLAYCHANGE:
+ // Display format has changed - notify callback
+ callback->displayChanged();
+ break;
+
+ // -=- Window position
+
+ // Prevent the window from being resized to be too large if in normal mode.
+ // If maximized or fullscreen the allow oversized windows.
+
+ case WM_WINDOWPOSCHANGING:
+ {
+ WINDOWPOS* wpos = (WINDOWPOS*)lParam;
+ if (wpos->flags & SWP_NOSIZE)
+ break;
+
+ // Work out how big the window should ideally be
+ DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, style_ex);
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+ if (current_style & WS_VSCROLL)
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ if (current_style & WS_HSCROLL)
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+
+ SetRect(&r, reqd_size.tl.x, reqd_size.tl.y, reqd_size.br.x, reqd_size.br.y);
+ if (tb.isVisible())
+ r.bottom += tb.getHeight();
+ AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+ reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ RECT current;
+ GetWindowRect(handle, &current);
+
+ if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+ // Ensure that the window isn't resized too large
+ if (wpos->cx > reqd_size.width()) {
+ wpos->cx = reqd_size.width();
+ wpos->x = current.left;
+ }
+ if (wpos->cy > reqd_size.height()) {
+ wpos->cy = reqd_size.height();
+ wpos->y = current.top;
+ }
+ }
+ }
+ break;
+
+ // Resize child windows and update window size info we have cached.
+
+ case WM_SIZE:
+ {
+ Point old_offset = desktopToClient(Point(0, 0));
+ RECT r;
+
+ // Resize child windows
+ GetClientRect(handle, &r);
+ if (tb.isVisible()) {
+ MoveWindow(frameHandle, 0, tb.getHeight(),
+ r.right, r.bottom - tb.getHeight(), TRUE);
+ } else {
+ MoveWindow(frameHandle, 0, 0, r.right, r.bottom, TRUE);
+ }
+ tb.autoSize();
+
+ // Update the cached sizing information
+ GetWindowRect(frameHandle, &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(frameHandle, &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Determine whether scrollbars are required
+ calculateScrollBars();
+
+ // Redraw if required
+ if ((!old_offset.equals(desktopToClient(Point(0, 0)))))
+ InvalidateRect(frameHandle, 0, TRUE);
+ }
+ break;
+
+ // -=- Bump-scrolling
+
+ case WM_TIMER:
+ switch (wParam) {
+ case TIMER_BUMPSCROLL:
+ if (!setViewportOffset(scrolloffset.translate(bumpScrollDelta)))
+ bumpScrollTimer.stop();
+ break;
+ case TIMER_POINTER_INTERVAL:
+ case TIMER_POINTER_3BUTTON:
+ ptr.handleTimer(callback, wParam);
+ break;
+ }
+ break;
+
+ // -=- Track whether or not the window has focus
+
+ case WM_SETFOCUS:
+ has_focus = true;
+ break;
+ case WM_KILLFOCUS:
+ has_focus = false;
+ cursorOutsideBuffer();
+ // Restore the keyboard to a consistent state
+ kbd.releaseAllKeys(callback);
+ break;
+
+ // -=- If the menu is about to be shown, make sure it's up to date
+
+ case WM_INITMENU:
+ callback->refreshMenu(true);
+ break;
+
+ // -=- Handle the extra window menu items
+
+ // Pass system menu messages to the callback and only attempt
+ // to process them ourselves if the callback returns false.
+ case WM_SYSCOMMAND:
+ // Call the supplied callback
+ if (callback->sysCommand(wParam, lParam))
+ break;
+
+ // - Not processed by the callback, so process it as a system message
+ switch (wParam & 0xfff0) {
+
+ // When restored, ensure that full-screen mode is re-enabled if required.
+ case SC_RESTORE:
+ {
+ if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE) {
+ rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+ setFullscreen(fullscreenRestore);
+ }
+ else if (fullscreenActive)
+ setFullscreen(false);
+ else
+ rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+
+ return 0;
+ }
+
+ // If we are maximized or minimized then that cancels full-screen mode.
+ case SC_MINIMIZE:
+ case SC_MAXIMIZE:
+ fullscreenRestore = fullscreenActive;
+ setFullscreen(false);
+ break;
+
+ }
+ break;
+
+ // Treat all menu commands as system menu commands
+ case WM_COMMAND:
+ SendMessage(handle, WM_SYSCOMMAND, wParam, lParam);
+ return 0;
+
+ // -=- Handle keyboard input
+
+ case WM_KEYUP:
+ case WM_KEYDOWN:
+ // Hook the MenuKey to pop-up the window menu
+ if (menuKey && (wParam == menuKey)) {
+
+ bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
+ bool altDown = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
+ bool shiftDown = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0;
+ if (!(ctrlDown || altDown || shiftDown)) {
+
+ // If MenuKey is being released then pop-up the menu
+ if ((msg == WM_KEYDOWN)) {
+ // Make sure it's up to date
+ //
+ // NOTE: Here we call refreshMenu only to grey out Move and Size
+ // menu items. Other things will be refreshed once again
+ // while processing the WM_INITMENU message.
+ //
+ callback->refreshMenu(false);
+
+ // Show it under the pointer
+ POINT pt;
+ GetCursorPos(&pt);
+ cursorInBuffer = false;
+ TrackPopupMenu(GetSystemMenu(handle, FALSE),
+ TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, handle, 0);
+ }
+
+ // Ignore the MenuKey keypress for both press & release events
+ return 0;
+ }
+ }
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ kbd.keyEvent(callback, wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN));
+ return 0;
+
+ // -=- Handle the window closing
+
+ case WM_CLOSE:
+ vlog.debug("WM_CLOSE %x", handle);
+ callback->closeWindow();
+ break;
+
+ }
+
+ return rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+}
+
+LRESULT
+DesktopWindow::processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ // -=- Paint the remote frame buffer
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC paintDC = BeginPaint(frameHandle, &ps);
+ if (!paintDC)
+ throw rdr::SystemException("unable to BeginPaint", GetLastError());
+ Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+ if (!pr.is_empty()) {
+
+ // Draw using the correct palette
+ PaletteSelector pSel(paintDC, windowPalette.getHandle());
+
+ if (buffer->bitmap) {
+ // Update the bitmap's palette
+ if (palette_changed) {
+ palette_changed = false;
+ buffer->refreshPalette();
+ }
+
+ // Get device context
+ BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+ // Blit the border if required
+ Rect bufpos = desktopToClient(buffer->getRect());
+ if (!pr.enclosed_by(bufpos)) {
+ vlog.debug("draw border");
+ HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ RECT r;
+ SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+ }
+
+ // Do the blit
+ Point buf_pos = clientToDesktop(pr.tl);
+
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+ throw rdr::SystemException("unable to BitBlt to window", GetLastError());
+ }
+ }
+
+ EndPaint(frameHandle, &ps);
+
+ // - Notify the callback that a paint message has finished processing
+ callback->paintCompleted();
+ }
+ return 0;
+
+ // -=- Palette management
+
+ case WM_PALETTECHANGED:
+ vlog.debug("WM_PALETTECHANGED");
+ if ((HWND)wParam == frameHandle) {
+ vlog.debug("ignoring");
+ break;
+ }
+ case WM_QUERYNEWPALETTE:
+ vlog.debug("re-selecting palette");
+ {
+ WindowDC wdc(frameHandle);
+ PaletteSelector pSel(wdc, windowPalette.getHandle());
+ if (pSel.isRedrawRequired()) {
+ InvalidateRect(frameHandle, 0, FALSE);
+ UpdateWindow(frameHandle);
+ }
+ }
+ return TRUE;
+
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ Point delta;
+ int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+ switch (LOWORD(wParam)) {
+ case SB_PAGEUP: newpos -= 50; break;
+ case SB_PAGEDOWN: newpos += 50; break;
+ case SB_LINEUP: newpos -= 5; break;
+ case SB_LINEDOWN: newpos += 5; break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+ default: vlog.info("received unknown scroll message");
+ };
+
+ if (msg == WM_HSCROLL)
+ setViewportOffset(Point(newpos, scrolloffset.y));
+ else
+ setViewportOffset(Point(scrolloffset.x, newpos));
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ si.nPos = newpos;
+ SetScrollInfo(frameHandle, (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
+ }
+ break;
+
+ // -=- Cursor shape/visibility handling
+
+ case WM_SETCURSOR:
+ if (LOWORD(lParam) != HTCLIENT)
+ break;
+ SetCursor(cursorInBuffer ? dotCursor : arrowCursor);
+ return TRUE;
+
+ case WM_MOUSELEAVE:
+ trackingMouseLeave = false;
+ cursorOutsideBuffer();
+ return 0;
+
+ // -=- Mouse input handling
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+#ifdef WM_MOUSEWHEEL
+ case WM_MOUSEWHEEL:
+#endif
+ if (has_focus)
+ {
+ if (!trackingMouseLeave) {
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = frameHandle;
+ _TrackMouseEvent(&tme);
+ trackingMouseLeave = true;
+ }
+ int mask = 0;
+ if (LOWORD(wParam) & MK_LBUTTON) mask |= 1;
+ if (LOWORD(wParam) & MK_MBUTTON) mask |= 2;
+ if (LOWORD(wParam) & MK_RBUTTON) mask |= 4;
+
+#ifdef WM_MOUSEWHEEL
+ if (msg == WM_MOUSEWHEEL) {
+ int delta = (short)HIWORD(wParam);
+ int repeats = (abs(delta)+119) / 120;
+ int wheelMask = (delta > 0) ? 8 : 16;
+ vlog.debug("repeats %d, mask %d\n",repeats,wheelMask);
+ for (int i=0; i<repeats; i++) {
+ ptr.pointerEvent(callback, oldpos, mask | wheelMask);
+ ptr.pointerEvent(callback, oldpos, mask);
+ }
+ } else {
+#endif
+ Point clientPos = Point(LOWORD(lParam), HIWORD(lParam));
+ Point p = clientToDesktop(clientPos);
+
+ // If the mouse is not within the server buffer area, do nothing
+ cursorInBuffer = buffer->getRect().contains(p);
+ if (!cursorInBuffer) {
+ cursorOutsideBuffer();
+ break;
+ }
+
+ // If we're locally rendering the cursor then redraw it
+ if (cursorAvailable) {
+ // - Render the cursor!
+ if (!p.equals(cursorPos)) {
+ hideLocalCursor();
+ cursorPos = p;
+ showLocalCursor();
+ if (cursorVisible)
+ hideSystemCursor();
+ }
+ }
+
+ // If we are doing bump-scrolling then try that first...
+ if (processBumpScroll(clientPos))
+ break;
+
+ // Send a pointer event to the server
+ oldpos = p;
+ if (buffer->isScaling()) {
+ p.x /= double(buffer->getScale()) / 100.0;
+ p.y /= double(buffer->getScale()) / 100.0;
+ }
+ ptr.pointerEvent(callback, p, mask);
+#ifdef WM_MOUSEWHEEL
+ }
+#endif
+ } else {
+ cursorOutsideBuffer();
+ }
+ break;
+ }
+
+ return rfb::win32::SafeDefWindowProc(frameHandle, msg, wParam, lParam);
+}
+
+
+void
+DesktopWindow::hideLocalCursor() {
+ // - Blit the cursor backing store over the cursor
+ // *** ALWAYS call this BEFORE changing buffer PF!!!
+ if (cursorVisible) {
+ cursorVisible = false;
+ buffer->DIBSectionBuffer::imageRect(cursorBackingRect, cursorBacking.data);
+ invalidateDesktopRect(cursorBackingRect, false);
+ }
+}
+
+void
+DesktopWindow::showLocalCursor() {
+ if (cursorAvailable && !cursorVisible && cursorInBuffer) {
+ if (!buffer->getPF().equal(cursor.getPF()) ||
+ cursor.getRect().is_empty()) {
+ vlog.info("attempting to render invalid local cursor");
+ cursorAvailable = false;
+ showSystemCursor();
+ return;
+ }
+ cursorVisible = true;
+
+ cursorBackingRect = cursor.getRect().translate(cursorPos).translate(cursor.hotspot.negate());
+ cursorBackingRect = cursorBackingRect.intersect(buffer->getRect());
+ buffer->getImage(cursorBacking.data, cursorBackingRect);
+
+ renderLocalCursor();
+
+ invalidateDesktopRect(cursorBackingRect, false);
+ }
+}
+
+void DesktopWindow::cursorOutsideBuffer()
+{
+ cursorInBuffer = false;
+ hideLocalCursor();
+ showSystemCursor();
+}
+
+void
+DesktopWindow::renderLocalCursor()
+{
+ Rect r = cursor.getRect();
+ r = r.translate(cursorPos).translate(cursor.hotspot.negate());
+ buffer->DIBSectionBuffer::maskRect(r, cursor.data, cursor.mask.buf);
+}
+
+void
+DesktopWindow::hideSystemCursor() {
+ if (systemCursorVisible) {
+ vlog.debug("hide system cursor");
+ systemCursorVisible = false;
+ ShowCursor(FALSE);
+ }
+}
+
+void
+DesktopWindow::showSystemCursor() {
+ if (!systemCursorVisible) {
+ vlog.debug("show system cursor");
+ systemCursorVisible = true;
+ ShowCursor(TRUE);
+ }
+}
+
+
+bool
+DesktopWindow::invalidateDesktopRect(const Rect& crect, bool scaling) {
+ Rect rect;
+ if (buffer->isScaling() && scaling) {
+ rect = desktopToClient(buffer->calculateScaleBoundary(crect));
+ } else rect = desktopToClient(crect);
+ if (rect.intersect(client_size).is_empty()) return false;
+ RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+ InvalidateRect(frameHandle, &invalid, FALSE);
+ return true;
+}
+
+
+void
+DesktopWindow::notifyClipboardChanged(const char* text, int len) {
+ callback->clientCutText(text, len);
+}
+
+
+void
+DesktopWindow::setPF(const PixelFormat& pf) {
+ // If the cursor is the wrong format then clear it
+ if (!pf.equal(buffer->getPF()))
+ setCursor(0, 0, Point(), 0, 0);
+
+ // Update the desktop buffer
+ buffer->setPF(pf);
+
+ // Redraw the window
+ InvalidateRect(frameHandle, 0, FALSE);
+}
+
+void
+DesktopWindow::setSize(int w, int h) {
+ vlog.debug("setSize %dx%d", w, h);
+
+ // If the locally-rendered cursor is visible then remove it
+ hideLocalCursor();
+
+ // Resize the backing buffer
+ buffer->setSize(w, h);
+
+ // If the window is not maximised or full-screen then resize it
+ if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+ // Resize the window to the required size
+ RECT r = {0, 0, w, h};
+ AdjustWindowRectEx(&r, GetWindowLong(frameHandle, GWL_STYLE), FALSE,
+ GetWindowLong(frameHandle, GWL_EXSTYLE));
+ if (tb.isVisible())
+ r.bottom += tb.getHeight();
+ AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+
+ // Resize about the center of the window, and clip to current monitor
+ MonitorInfo mi(handle);
+ resizeWindow(handle, r.right-r.left, r.bottom-r.top);
+ mi.clipTo(handle);
+ } else {
+ // Ensure the screen contents are consistent
+ InvalidateRect(frameHandle, 0, FALSE);
+ }
+
+ // Enable/disable scrollbars as appropriate
+ calculateScrollBars();
+}
+
+void
+DesktopWindow::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+ hideLocalCursor();
+
+ cursor.hotspot = hotspot;
+
+ cursor.setSize(w, h);
+ cursor.setPF(buffer->getPF());
+ cursor.imageRect(cursor.getRect(), data);
+ memcpy(cursor.mask.buf, mask, cursor.maskLen());
+ cursor.crop();
+
+ cursorBacking.setSize(w, h);
+ cursorBacking.setPF(buffer->getPF());
+
+ cursorAvailable = true;
+
+ showLocalCursor();
+}
+
+PixelFormat
+DesktopWindow::getNativePF() const {
+ vlog.debug("getNativePF()");
+ return WindowDC(handle).getPF();
+}
+
+
+void
+DesktopWindow::refreshWindowPalette(int start, int count) {
+ vlog.debug("refreshWindowPalette(%d, %d)", start, count);
+
+ Colour colours[256];
+ if (count > 256) {
+ vlog.debug("%d palette entries", count);
+ throw rdr::Exception("too many palette entries");
+ }
+
+ // Copy the palette from the DIBSectionBuffer
+ ColourMap* cm = buffer->getColourMap();
+ if (!cm) return;
+ for (int i=0; i<count; i++) {
+ int r, g, b;
+ cm->lookup(i, &r, &g, &b);
+ colours[i].r = r;
+ colours[i].g = g;
+ colours[i].b = b;
+ }
+
+ // Set the window palette
+ windowPalette.setEntries(start, count, colours);
+
+ // Cause the window to be redrawn
+ palette_changed = true;
+ InvalidateRect(handle, 0, FALSE);
+}
+
+
+void DesktopWindow::calculateScrollBars() {
+ // Calculate the required size of window
+ DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+ DWORD old_style;
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, style_ex);
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ if (!bumpScroll) {
+ // We only enable scrollbars if bump-scrolling is not active.
+ // Effectively, this means if full-screen is not active,
+ // but I think it's better to make these things explicit.
+
+ // Work out whether scroll bars are required
+ do {
+ old_style = style;
+
+ if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+ style |= WS_HSCROLL;
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+ }
+ if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+ style |= WS_VSCROLL;
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ }
+ } while (style != old_style);
+ }
+
+ // Tell Windows to update the window style & cached settings
+ if (style != current_style) {
+ SetWindowLong(frameHandle, GWL_STYLE, style);
+ SetWindowPos(frameHandle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+
+ // Update the scroll settings
+ SCROLLINFO si;
+ if (style & WS_VSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->height();
+ si.nPage = buffer->height() - (reqd_size.height() - window_size.height());
+ maxscrolloffset.y = max(0, si.nMax-si.nPage);
+ scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+ si.nPos = scrolloffset.y;
+ SetScrollInfo(frameHandle, SB_VERT, &si, TRUE);
+ }
+ if (style & WS_HSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->width();
+ si.nPage = buffer->width() - (reqd_size.width() - window_size.width());
+ maxscrolloffset.x = max(0, si.nMax-si.nPage);
+ scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+ si.nPos = scrolloffset.x;
+ SetScrollInfo(frameHandle, SB_HORZ, &si, TRUE);
+ }
+
+ // Update the cached client size
+ GetClientRect(frameHandle, &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+
+void
+DesktopWindow::setName(const char* name) {
+ SetWindowText(handle, TStr(name));
+}
+
+
+void
+DesktopWindow::serverCutText(const char* str, int len) {
+ CharArray t(len+1);
+ memcpy(t.buf, str, len);
+ t.buf[len] = 0;
+ clipboard.setClipText(t.buf);
+}
+
+
+void DesktopWindow::fillRect(const Rect& r, Pixel pix) {
+ Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+ if (cursorBackingRect.overlaps(img_rect)) hideLocalCursor();
+ buffer->fillRect(r, pix);
+ invalidateDesktopRect(r);
+}
+void DesktopWindow::imageRect(const Rect& r, void* pixels) {
+ Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+ if (cursorBackingRect.overlaps(img_rect)) hideLocalCursor();
+ buffer->imageRect(r, pixels);
+ invalidateDesktopRect(r);
+}
+void DesktopWindow::copyRect(const Rect& r, int srcX, int srcY) {
+ Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+ if (cursorBackingRect.overlaps(img_rect) ||
+ cursorBackingRect.overlaps(Rect(srcX, srcY, srcX+img_rect.width(), srcY+img_rect.height())))
+ hideLocalCursor();
+ buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+ invalidateDesktopRect(r);
+}
+
+void DesktopWindow::invertRect(const Rect& r) {
+ int stride;
+ rdr::U8* p = buffer->isScaling() ? buffer->getPixelsRW(buffer->calculateScaleBoundary(r), &stride)
+ : buffer->getPixelsRW(r, &stride);
+ for (int y = 0; y < r.height(); y++) {
+ for (int x = 0; x < r.width(); x++) {
+ switch (buffer->getPF().bpp) {
+ case 8: ((rdr::U8* )p)[x+y*stride] ^= 0xff; break;
+ case 16: ((rdr::U16*)p)[x+y*stride] ^= 0xffff; break;
+ case 32: ((rdr::U32*)p)[x+y*stride] ^= 0xffffffff; break;
+ }
+ }
+ }
+ invalidateDesktopRect(r);
+}
diff --git a/win/vncviewer/DesktopWindow.h b/win/vncviewer/DesktopWindow.h
new file mode 100644
index 00000000..3d2211f8
--- /dev/null
+++ b/win/vncviewer/DesktopWindow.h
@@ -0,0 +1,254 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- DesktopWindow.h
+
+// Each VNC connection instance (CConn) creates a DesktopWindow the
+// server initialisation message has been received. The CConn is
+// responsible for all RFB-specific and network issues. The
+// DesktopWindow is responsible for all GUI management issues.
+//
+// DesktopWindow provides a FullFramePixelBuffer interface for the
+// CConn to render updates into. It also requires a callback object
+// to be supplied, which will be notified when various events occur.
+
+#ifndef __RFB_WIN32_DESKTOP_WINDOW_H__
+#define __RFB_WIN32_DESKTOP_WINDOW_H__
+
+#include <rfb/Cursor.h>
+#include <rfb_win32/CKeyboard.h>
+#include <rfb_win32/CPointer.h>
+#include <rfb_win32/Clipboard.h>
+#include <rfb_win32/ScaledDIBSectionBuffer.h>
+#include <rfb_win32/LogicalPalette.h>
+#include <vncviewer/ViewerToolBar.h>
+
+
+namespace rfb {
+
+ namespace win32 {
+
+ class DesktopWindow : rfb::win32::Clipboard::Notifier {
+ public:
+ class Callback;
+
+ DesktopWindow(Callback* cb_);
+ ~DesktopWindow();
+
+ // - Window message handling procedure
+ LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+ // - Window message handling procedure for the framebuffer window
+ LRESULT processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+ // - Determine the native pixel format of the window
+ // This can (and often will) differ from the PixelBuffer format
+ PixelFormat getNativePF() const;
+
+ // - Get the underlying window handle
+ // This is used by F8Menu to modify the window's menu
+ HWND getHandle() const {return handle;}
+
+ // - Get the framebuffer window handle
+ HWND getFrameHandle() const {return frameHandle;}
+
+ // - Set the window title
+ void setName(const char* name);
+
+ // - Set the key that causes the system/F8 menu to be displayed
+ void setMenuKey(rdr::U8 key) { menuKey = key; }
+
+ // - Pointer event handling
+ void setEmulate3(bool em3) { ptr.enableEmulate3(em3); }
+ void setPointerEventInterval(int interval) { ptr.enableInterval(interval); }
+
+ // - Set the pixel format, size etc of the underlying PixelBuffer
+ void setPF(const PixelFormat& pf);
+ PixelFormat getPF() const { return buffer->getPF(); }
+ void setSize(int w, int h);
+ void setColour(int i, int r, int g, int b) {buffer->setColour(i, r, g, b);}
+
+ // - Set the cursor to render when the pointer is within the desktop buffer
+ void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+ void showCursor() { showLocalCursor(); }
+
+ // - Set the window fullscreen / determine whether it is fullscreen
+ void setFullscreen(bool fs);
+ bool isFullscreen() { return fullscreenActive; }
+
+ // - Set/get the toolbar's state
+ void setShowToolbar(bool st);
+ bool isToolbarEnabled() { return showToolbar; }
+
+ // - Set whether to disable special Windows keys & pass them straight to server
+ void setDisableWinKeys(bool dwk);
+
+ // - Set/get which monitor the window should be displayed on
+ void setMonitor(const char* monitor);
+ char* getMonitor() const;
+
+ // - Set the local clipboard
+ void serverCutText(const char* str, int len);
+
+ // - Draw into the desktop buffer & update the window
+ void fillRect(const Rect& r, Pixel pix);
+ void imageRect(const Rect& r, void* pixels);
+ void copyRect(const Rect& r, int srcX, int srcY);
+
+ void invertRect(const Rect& r);
+
+ // - Update the window palette if the display is palette-based.
+ // Colours are pulled from the desktop buffer's ColourMap.
+ // Only the specified range of indexes is dealt with.
+ // After the update, the entire window is redrawn.
+ void refreshWindowPalette(int start, int count);
+
+ // Clipboard::Notifier interface
+ void notifyClipboardChanged(const char* text, int len);
+
+ // DesktopWindow Callback interface
+ class Callback : public InputHandler {
+ public:
+ virtual ~Callback() {}
+ virtual void displayChanged() = 0;
+ virtual void paintCompleted() = 0;
+ virtual bool sysCommand(WPARAM wParam, LPARAM lParam) = 0;
+ virtual void closeWindow() = 0;
+ virtual void refreshMenu(bool enableSysItems) = 0;
+ };
+
+ // Currently accessible so that the CConn can releaseAllKeys & check
+ // whether Ctrl and Alt are down...
+ rfb::win32::CKeyboard kbd;
+
+ protected:
+ // Routines to convert between Desktop and client (window) coordinates
+ Point desktopToClient(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x += (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x -= scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y += (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y -= scrolloffset.y;
+ return pos;
+ }
+ Rect desktopToClient(const Rect& r) {
+ return Rect(desktopToClient(r.tl), desktopToClient(r.br));
+ }
+ Point clientToDesktop(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x -= (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x += scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y -= (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y += scrolloffset.y;
+ return pos;
+ }
+ Rect clientToDesktop(const Rect& r) {
+ return Rect(clientToDesktop(r.tl), clientToDesktop(r.br));
+ }
+
+ // Internal routine used by the scrollbars & bump scroller to select
+ // the portion of the Desktop to display
+ bool setViewportOffset(const Point& tl);
+
+ // Bump scroll handling. Bump scrolling is used if the window is
+ // in fullscreen mode and the Desktop is larger than the window
+ bool processBumpScroll(const Point& cursorPos);
+ void setBumpScroll(bool on);
+ bool bumpScroll;
+ Point bumpScrollDelta;
+ IntervalTimer bumpScrollTimer;
+
+ // Locally-rendered VNC cursor
+ void hideLocalCursor();
+ void showLocalCursor();
+ void renderLocalCursor();
+
+ // The system-rendered cursor
+ void hideSystemCursor();
+ void showSystemCursor();
+
+ // cursorOutsideBuffer() is called whenever we detect that the mouse has
+ // moved outside the desktop. It restores the system arrow cursor.
+ void cursorOutsideBuffer();
+
+ // Returns true if part of the supplied rect is visible, false otherwise
+ bool invalidateDesktopRect(const Rect& crect, bool scaling=true);
+
+ // Determine whether or not we need to enable/disable scrollbars and set the
+ // window style accordingly
+ void calculateScrollBars();
+
+ // Win32-specific input handling
+ rfb::win32::CPointer ptr;
+ Point oldpos;
+ rfb::win32::Clipboard clipboard;
+
+ // Palette handling
+ LogicalPalette windowPalette;
+ bool palette_changed;
+
+ // - Full-screen mode
+ RECT fullscreenOldRect;
+ DWORD fullscreenOldFlags;
+ bool fullscreenActive;
+ bool fullscreenRestore;
+
+ // Cursor handling
+ Cursor cursor;
+ bool systemCursorVisible; // Should system-cursor be drawn?
+ bool trackingMouseLeave;
+ bool cursorInBuffer; // Is cursor position within server buffer? (ONLY for LocalCursor)
+ bool cursorVisible; // Is cursor currently rendered?
+ bool cursorAvailable; // Is cursor available for rendering?
+ Point cursorPos;
+ ManagedPixelBuffer cursorBacking;
+ Rect cursorBackingRect;
+
+ // ToolBar handling
+ ViewerToolBar tb;
+ bool showToolbar;
+
+ // Local window state
+ win32::ScaledDIBSectionBuffer* buffer;
+ bool has_focus;
+ Rect window_size;
+ Rect client_size;
+ Point scrolloffset;
+ Point maxscrolloffset;
+ HWND handle;
+ HWND frameHandle;
+ rdr::U8 menuKey;
+
+ Callback* callback;
+ };
+
+ };
+
+};
+
+#endif // __RFB_WIN32_DESKTOP_WINDOW_H__
+
+
diff --git a/win/vncviewer/FTBrowseDlg.cxx b/win/vncviewer/FTBrowseDlg.cxx
new file mode 100644
index 00000000..1b6dfb67
--- /dev/null
+++ b/win/vncviewer/FTBrowseDlg.cxx
@@ -0,0 +1,196 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTBrpwseDlg.cxx
+
+#include <vncviewer/FTBrowseDlg.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTBrowseDlg::FTBrowseDlg(FTDialog *pFTDlg)
+{
+ m_pFTDlg = pFTDlg;
+ m_hwndDlg = NULL;
+ m_hwndTree = NULL;
+ m_hParentItem = NULL;
+}
+
+FTBrowseDlg::~FTBrowseDlg()
+{
+ destroy();
+}
+
+bool
+FTBrowseDlg::create()
+{
+ m_hwndDlg = CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FTBROWSE),
+ m_pFTDlg->getWndHandle(), (DLGPROC) FTBrowseDlgProc,
+ (LONG) this);
+
+ if (m_hwndDlg == NULL) return false;
+
+ m_hwndTree = GetDlgItem(m_hwndDlg, IDC_FTBROWSETREE);
+
+ ShowWindow(m_hwndDlg, SW_SHOW);
+ UpdateWindow(m_hwndDlg);
+
+ return true;
+}
+
+void
+FTBrowseDlg::destroy()
+{
+ EndDialog(m_hwndDlg, 0);
+}
+
+void
+FTBrowseDlg::addItems(FileInfo *pFI)
+{
+ TVITEM tvi;
+ TVINSERTSTRUCT tvins;
+
+ if (pFI->getNumEntries() <= 0) return;
+
+ for (unsigned int i = 0; i < pFI->getNumEntries(); i++)
+ {
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = pFI->getNameAt(i);;
+ tvins.hParent = m_hParentItem;
+ tvins.item = tvi;
+ tvins.hParent = TreeView_InsertItem(m_hwndTree, &tvins);
+ TreeView_InsertItem(m_hwndTree, &tvins);
+ }
+}
+
+char *
+FTBrowseDlg::getTVPath(HTREEITEM hTItem)
+{
+ char path[FT_FILENAME_SIZE];
+ char szText[FT_FILENAME_SIZE];
+
+ TVITEM tvi;
+ path[0] = '\0';
+
+ do {
+ tvi.mask = TVIF_TEXT | TVIF_HANDLE;
+ tvi.hItem = hTItem;
+ tvi.pszText = szText;
+ tvi.cchTextMax = FT_FILENAME_SIZE;
+ TreeView_GetItem(m_hwndTree, &tvi);
+ sprintf(path, "%s\\%s", path, tvi.pszText);
+ hTItem = TreeView_GetParent(m_hwndTree, hTItem);
+ } while(hTItem != NULL);
+
+ return pathInvert(path);
+}
+
+char *
+FTBrowseDlg::pathInvert(char *pPath)
+{
+ int len = strlen(pPath);
+ m_szPath[0] = '\0';
+ char *pos = NULL;
+
+ while ((pos = strrchr(pPath, '\\')) != NULL) {
+ if (strlen(m_szPath) == 0) {
+ strcpy(m_szPath, (pos + 1));
+ } else {
+ sprintf(m_szPath, "%s\\%s", m_szPath, (pos + 1));
+ }
+ *pos = '\0';
+ }
+
+ m_szPath[len] = '\0';
+ return m_szPath;
+}
+
+char *
+FTBrowseDlg::getPath()
+{
+ GetDlgItemText(m_hwndDlg, IDC_FTBROWSEPATH, m_szPath, FT_FILENAME_SIZE);
+ return m_szPath;
+}
+
+void
+FTBrowseDlg::deleteChildItems()
+{
+ while (TreeView_GetChild(m_hwndTree, m_hParentItem) != NULL) {
+ TreeView_DeleteItem(m_hwndTree, TreeView_GetChild(m_hwndTree, m_hParentItem));
+ }
+}
+
+BOOL CALLBACK
+FTBrowseDlg::FTBrowseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FTBrowseDlg *_this = (FTBrowseDlg *) GetWindowLong(hwnd, GWL_USERDATA);
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SetWindowLong(hwnd, GWL_USERDATA, lParam);
+ return FALSE;
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ _this->m_pFTDlg->onEndBrowseDlg(true);
+ return FALSE;
+ case IDCANCEL:
+ _this->m_pFTDlg->onEndBrowseDlg(false);
+ return FALSE;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch (LOWORD(wParam))
+ {
+ case IDC_FTBROWSETREE:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case TVN_SELCHANGED:
+ SetDlgItemText(hwnd, IDC_FTBROWSEPATH, _this->getTVPath(((NMTREEVIEW *) lParam)->itemNew.hItem));
+ return FALSE;
+// case TVN_ITEMEXPANDING:
+ case TVN_ITEMEXPANDED:
+ {
+ NMTREEVIEW *nmCode = (NMTREEVIEW *) lParam;
+ if (nmCode->action == 2) {
+ _this->m_hParentItem = nmCode->itemNew.hItem;
+ _this->deleteChildItems();
+ _this->m_pFTDlg->getBrowseItems(_this->getTVPath(_this->m_hParentItem));
+ }
+ }
+ return FALSE;
+ }
+ break;
+ case WM_CLOSE:
+ _this->m_pFTDlg->onEndBrowseDlg(false);
+ return FALSE;
+ }
+ }
+ return 0;
+}
diff --git a/win/vncviewer/FTBrowseDlg.h b/win/vncviewer/FTBrowseDlg.h
new file mode 100644
index 00000000..5c9ba357
--- /dev/null
+++ b/win/vncviewer/FTBrowseDlg.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTBrowseDlg.h
+
+#ifndef __RFB_WIN32_FTBROWSEDLG_H__
+#define __RFB_WIN32_FTBROWSEDLG_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <vncviewer/FTDialog.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32 {
+ class FTDialog;
+
+ class FTBrowseDlg
+ {
+ public:
+ FTBrowseDlg(FTDialog *pFTDlg);
+ ~FTBrowseDlg();
+
+ static BOOL CALLBACK FTBrowseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ bool create();
+ void destroy();
+
+ void addItems(FileInfo *pFI);
+ char *getPath();
+
+ void deleteChildItems();
+
+ private:
+ HWND m_hwndDlg;
+ HWND m_hwndTree;
+ FTDialog *m_pFTDlg;
+ HTREEITEM m_hParentItem;
+
+ char m_szPath[FT_FILENAME_SIZE];
+
+ char *pathInvert(char *pPath);
+ char *getTVPath(HTREEITEM hTItem);
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTBROWSEDLG_H__
diff --git a/win/vncviewer/FTDialog.cxx b/win/vncviewer/FTDialog.cxx
new file mode 100644
index 00000000..5f71f7dd
--- /dev/null
+++ b/win/vncviewer/FTDialog.cxx
@@ -0,0 +1,1162 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTDialog.cxx
+
+#include <vncviewer/FTDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+const char FTDialog::szCheckDeleteQueueText[] = "TightVNC.Viewer.CheckDeleteQueue.Msg";
+const char FTDialog::szCheckTransferQueueText[] = "TightVNC.Viewer.CheckTransferQueue.Msg";
+const char FTDialog::szUploadFilePortionText[] = "TightVNC.Viewer.UploadFilePortion.Msg";
+
+FTDialog::FTDialog(HINSTANCE hInst, FileTransfer *pFT)
+{
+ m_pFileTransfer = pFT;
+ m_hInstance = hInst;
+
+ m_bDlgShown = false;
+ m_bLocalBrowsing = true;
+ m_bCloseDlgAfterCancel = false;
+
+ m_pLocalLV = NULL;
+ m_pRemoteLV = NULL;
+ m_pProgress = NULL;
+ m_pCancelingDlg = NULL;
+ m_pCreateFolderDlg = NULL;
+ m_pRenameDlg = NULL;
+ m_pBrowseDlg = NULL;
+
+ m_hwndFTDialog = NULL;
+ m_hwndLocalPath = NULL;
+ m_hwndRemotePath = NULL;
+
+ m_FTMenuSource = 0;
+ m_dwNumStatusStrings = 0;
+
+ m_szLocalPath[0] = '\0';
+ m_szRemotePath[0] = '\0';
+ m_szLocalPathTmp[0] = '\0';
+ m_szRemotePathTmp[0] = '\0';
+ m_szCreateFolderName[0] = '\0';
+}
+
+FTDialog::~FTDialog()
+{
+ destroyFTDialog();
+}
+
+bool
+FTDialog::createFTDialog(HWND hwndParent)
+{
+ if (m_hwndFTDialog != NULL) {
+ ShowWindow(m_hwndFTDialog, SW_SHOW);
+ m_bDlgShown = true;
+ showLocalLVItems();
+ showRemoteLVItems();
+ return true;
+ }
+
+ if (!initFTWndMsgs()) return false;
+
+ m_hwndFTDialog = CreateDialogParam(m_hInstance,
+ MAKEINTRESOURCE(IDD_FILETRANSFER_DLG),
+ hwndParent,
+ (DLGPROC) FTDialogProc,
+ (LONG) this);
+
+ if (m_hwndFTDialog == NULL) return false;
+
+ HWND hwndLocalList = GetDlgItem(m_hwndFTDialog, IDC_FTLOCALLIST);
+ HWND hwndRemoteList = GetDlgItem(m_hwndFTDialog, IDC_FTREMOTELIST);
+
+ if ((hwndLocalList == NULL) || (hwndRemoteList == NULL)) {
+ destroyFTDialog();
+ return false;
+ }
+
+ m_pLocalLV = new FTListView(hwndLocalList);
+ m_pRemoteLV = new FTListView(hwndRemoteList);
+
+ m_pProgress = new FTProgress(m_hwndFTDialog);
+
+ if ((m_pLocalLV == NULL) || (m_pRemoteLV == NULL) || (m_pProgress == NULL)) {
+ destroyFTDialog();
+ return false;
+ }
+
+ initFTDialog();
+
+ ShowWindow(m_hwndFTDialog, SW_SHOW);
+ UpdateWindow(m_hwndFTDialog);
+ m_bDlgShown = true;
+ return true;
+}
+
+bool
+FTDialog::initFTDialog()
+{
+ m_pLocalLV->initialize(m_hInstance);
+ m_pRemoteLV->initialize(m_hInstance);
+
+ m_hwndLocalPath = GetDlgItem(m_hwndFTDialog, IDC_FTLOCALPATH);
+ m_hwndRemotePath = GetDlgItem(m_hwndFTDialog, IDC_FTREMOTEPATH);
+
+ setIcon(IDC_FTLOCALUP, IDI_FTUP);
+ setIcon(IDC_FTREMOTEUP, IDI_FTUP);
+ setIcon(IDC_FTLOCALRELOAD, IDI_FTRELOAD);
+ setIcon(IDC_FTREMOTERELOAD, IDI_FTRELOAD);
+
+ showLocalLVItems();
+ showRemoteLVItems();
+
+ return true;
+}
+
+bool
+FTDialog::initFTWndMsgs()
+{
+ m_msgCheckDeleteQueue = RegisterWindowMessage(szCheckDeleteQueueText);
+ m_msgCheckTransferQueue = RegisterWindowMessage(szCheckTransferQueueText);
+ m_msgUploadFilePortion = RegisterWindowMessage(szUploadFilePortionText);
+
+ if ((m_msgCheckDeleteQueue) &&
+ (m_msgCheckTransferQueue) &&
+ (m_msgUploadFilePortion)) return true;
+
+ return false;
+}
+
+bool
+FTDialog::closeFTDialog()
+{
+ ShowWindow(m_hwndFTDialog, SW_HIDE);
+ m_bDlgShown = false;
+ return true;
+}
+
+void
+FTDialog::destroyFTDialog()
+{
+ if (m_pLocalLV != NULL) {
+ delete m_pLocalLV;
+ m_pLocalLV = NULL;
+ }
+
+ if (m_pRemoteLV != NULL) {
+ delete m_pRemoteLV;
+ m_pRemoteLV = NULL;
+ }
+
+ if (m_pProgress != NULL) {
+ delete m_pProgress;
+ m_pProgress = NULL;
+ }
+
+ if(m_pCancelingDlg != NULL) {
+ delete m_pCancelingDlg;
+ m_pCancelingDlg = NULL;
+ }
+
+ if (m_pCreateFolderDlg != NULL) {
+ delete m_pCreateFolderDlg;
+ m_pCreateFolderDlg = NULL;
+ }
+
+ if(m_pRenameDlg != NULL) {
+ delete m_pRenameDlg;
+ m_pRenameDlg = NULL;
+ }
+
+ if (DestroyWindow(m_hwndFTDialog)) m_hwndFTDialog = NULL;
+}
+
+BOOL CALLBACK
+FTDialog::FTDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FTDialog *_this = (FTDialog *) GetWindowLong(hwnd, GWL_USERDATA);
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ _this = (FTDialog*)lParam;
+ SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
+ SetForegroundWindow(hwnd);
+ return TRUE;
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_FTLOCALPATH:
+ switch (HIWORD (wParam))
+ {
+ case CBN_SETFOCUS:
+ _this->setButtonsState();
+ return FALSE;
+ }
+ break;
+ case IDC_FTREMOTEPATH:
+ switch (HIWORD (wParam))
+ {
+ case CBN_SETFOCUS:
+ _this->setButtonsState();
+ return FALSE;
+ }
+ break;
+ case IDC_FTCLOSE:
+ _this->onClose();
+ return FALSE;
+ case IDC_FTLOCALBROWSE:
+ _this->onLocalBrowse();
+ return FALSE;
+ case IDC_FTREMOTEBROWSE:
+ _this->onRemoteBrowse();
+ return FALSE;
+ case IDC_FTLOCALUP:
+ _this->setButtonsState();
+ _this->onLocalOneUpFolder();
+ return FALSE;
+ case IDC_FTREMOTEUP:
+ _this->setButtonsState();
+ _this->onRemoteOneUpFolder();
+ return FALSE;
+ case IDC_FTLOCALRELOAD:
+ _this->setButtonsState();
+ _this->onLocalReload();
+ return FALSE;
+ case IDC_FTREMOTERELOAD:
+ _this->setButtonsState();
+ _this->onRemoteReload();
+ return FALSE;
+ case IDC_FTUPLOAD:
+ _this->onUpload();
+ return FALSE;
+ case IDC_FTDOWNLOAD:
+ _this->onDownload();
+ return FALSE;
+ case IDC_FTCANCEL:
+ _this->onFTCancel();
+ return FALSE;
+ case IDM_FTCOPY:
+ case IDM_FTRENAME:
+ case IDM_FTDELETE:
+ case IDM_FTCANCEL:
+ case IDM_FTCREATEFOLDER:
+ _this->onFTMenuCommand(LOWORD(wParam));
+ return FALSE;
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (LOWORD(wParam))
+ {
+ case IDC_FTLOCALLIST:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case NM_CLICK:
+ case NM_SETFOCUS:
+ case LVN_ITEMCHANGED:
+ _this->setButtonsState();
+ return FALSE;
+ case LVN_GETDISPINFO:
+ _this->m_pLocalLV->onGetDispInfo((NMLVDISPINFO *) lParam);
+ return FALSE;
+ case LVN_ITEMACTIVATE:
+ _this->onLocalItemActivate((LPNMITEMACTIVATE) lParam);
+ return FALSE;
+ case NM_RCLICK:
+ _this->onLocalRButton();
+ return FALSE;
+ }
+ break;
+ case IDC_FTREMOTELIST:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case NM_CLICK:
+ case NM_SETFOCUS:
+ case LVN_ITEMCHANGED:
+ _this->setButtonsState();
+ case LVN_GETDISPINFO:
+ _this->m_pRemoteLV->onGetDispInfo((NMLVDISPINFO *) lParam);
+ return FALSE;
+ case LVN_ITEMACTIVATE:
+ _this->onRemoteItemActivate((LPNMITEMACTIVATE) lParam);
+ return FALSE;
+ case NM_RCLICK:
+ _this->onRemoteRButton();
+ return FALSE;
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ _this->onClose();
+ return FALSE;
+ }
+
+ if (_this != NULL) {
+ if (uMsg == _this->m_msgCheckTransferQueue)
+ _this->m_pFileTransfer->checkTransferQueue();
+
+ if (uMsg == _this->m_msgUploadFilePortion)
+ _this->m_pFileTransfer->uploadFilePortion();
+
+ if (uMsg == _this->m_msgCheckDeleteQueue)
+ _this->m_pFileTransfer->checkDeleteQueue();
+ }
+
+ return FALSE;
+}
+
+void
+FTDialog::onClose()
+{
+ if (m_pFileTransfer->isTransferEnable()) {
+ m_bCloseDlgAfterCancel = true;
+ onFTCancel();
+ } else {
+ closeFTDialog();
+ }
+}
+
+void
+FTDialog::onLocalItemActivate(LPNMITEMACTIVATE lpnmia)
+{
+ if (strlen(m_szLocalPath) == 0) {
+ strcpy(m_szLocalPathTmp, m_pLocalLV->getActivateItemName(lpnmia));
+ } else {
+ sprintf(m_szLocalPathTmp, "%s\\%s", m_szLocalPath, m_pLocalLV->getActivateItemName(lpnmia));
+ }
+ showLocalLVItems();
+}
+
+void
+FTDialog::onRemoteItemActivate(LPNMITEMACTIVATE lpnmia)
+{
+ if (strlen(m_szRemotePath) == 0) {
+ strcpy(m_szRemotePathTmp, m_pRemoteLV->getActivateItemName(lpnmia));
+ } else {
+ sprintf(m_szRemotePathTmp, "%s\\%s", m_szRemotePath, m_pRemoteLV->getActivateItemName(lpnmia));
+ }
+ showRemoteLVItems();
+}
+
+void
+FTDialog::onEndBrowseDlg(bool bResult)
+{
+ if (m_pBrowseDlg == NULL) return;
+
+ if (bResult) {
+ if (m_bLocalBrowsing) {
+ strcpy(m_szLocalPathTmp, m_pBrowseDlg->getPath());
+ showLocalLVItems();
+ } else {
+ strcpy(m_szRemotePathTmp, m_pBrowseDlg->getPath());
+ showRemoteLVItems();
+ }
+ }
+ delete m_pBrowseDlg;
+ m_pBrowseDlg = NULL;
+}
+
+void
+FTDialog::onLocalBrowse()
+{
+ if (m_pBrowseDlg != NULL) return;
+
+ m_bLocalBrowsing = true;
+
+ m_pBrowseDlg = new FTBrowseDlg(this);
+ m_pBrowseDlg->create();
+
+ getBrowseItems("");
+}
+
+void
+FTDialog::onRemoteBrowse()
+{
+ if (m_pBrowseDlg != NULL) return;
+
+ m_bLocalBrowsing = false;
+
+ m_pBrowseDlg = new FTBrowseDlg(this);
+ if (m_pBrowseDlg->create()) {
+ m_pFileTransfer->requestFileList("", FT_FLR_DEST_BROWSE, true);
+ } else {
+ delete m_pBrowseDlg;
+ m_pBrowseDlg = NULL;
+ }
+}
+
+void
+FTDialog::onLocalReload()
+{
+ strcpy(m_szLocalPathTmp, m_szLocalPath);
+ showLocalLVItems();
+}
+
+void
+FTDialog::onRemoteReload()
+{
+ strcpy(m_szRemotePathTmp, m_szRemotePath);
+ showRemoteLVItems();
+}
+
+void
+FTDialog::showLocalLVItems()
+{
+ FolderManager fm;
+ FileInfo fileInfo;
+ if (fm.getDirInfo(m_szLocalPathTmp, &fileInfo, 0)) {
+ fileInfo.sort();
+ m_pLocalLV->deleteAllItems();
+ m_pLocalLV->addItems(&fileInfo);
+ strcpy(m_szLocalPath, m_szLocalPathTmp);
+ SetWindowText(m_hwndLocalPath, m_szLocalPath);
+ }
+}
+
+void
+FTDialog::showRemoteLVItems()
+{
+ m_pFileTransfer->requestFileList(m_szRemotePathTmp, FT_FLR_DEST_MAIN, false);
+}
+
+void
+FTDialog::addRemoteLVItems(FileInfo *pFI)
+{
+ pFI->sort();
+ m_pRemoteLV->deleteAllItems();
+ m_pRemoteLV->addItems(pFI);
+ strcpy(m_szRemotePath, m_szRemotePathTmp);
+ SetWindowText(m_hwndRemotePath, m_szRemotePath);
+ UpdateWindow(m_hwndFTDialog);
+}
+
+void
+FTDialog::onLocalOneUpFolder()
+{
+ strcpy(m_szLocalPathTmp, m_szLocalPath);
+ makeOneUpFolder(m_szLocalPathTmp);
+ showLocalLVItems();
+}
+
+void
+FTDialog::onRemoteOneUpFolder()
+{
+ strcpy(m_szRemotePathTmp, m_szRemotePath);
+ makeOneUpFolder(m_szRemotePathTmp);
+ showRemoteLVItems();
+}
+
+void
+FTDialog::reqFolderUnavailable()
+{
+ strcpy(m_szRemotePathTmp, m_szRemotePath);
+ SetWindowText(m_hwndRemotePath, m_szRemotePath);
+ UpdateWindow(m_hwndFTDialog);
+}
+
+int
+FTDialog::makeOneUpFolder(char *pPath)
+{
+ if (strcmp(pPath, "") == 0) return strlen(pPath);
+ for (int i=(strlen(pPath)-2); i>=0; i--) {
+ if (pPath[i] == '\\') {
+ pPath[i] = '\0';
+ break;
+ }
+ if (i == 0) pPath[0] = '\0';
+ }
+ return strlen(pPath);
+}
+
+void
+FTDialog::onUpload()
+{
+ FileInfo fi;
+ char prefix[FT_FILENAME_SIZE];
+ prefix[0] = '\0';
+
+ if (m_pFileTransfer->isTransferEnable())
+ strcpy(prefix, "File Transfer is active.\nDo you want to add selected file(s)/folder(s) to transfer queue?\n\n");
+
+ int numSel = m_pLocalLV->getSelectedItems(&fi);
+ if (numSel > 0) {
+ char *pBuf = new char [(numSel + 4) * (MAX_PATH + 3) + strlen(prefix) + 1];
+ sprintf(pBuf, "%sFrom: Local Computer %s\\\n\n", prefix, m_szLocalPath);
+
+ for (unsigned int i = 0; i < fi.getNumEntries(); i++)
+ sprintf(pBuf, "%s%s, ", pBuf, fi.getNameAt(i));
+
+ sprintf(pBuf, "%s\n\nTo: Remote Computer %s\\", pBuf, m_szRemotePath);
+
+ if (strlen(pBuf) > 2048)
+ sprintf(pBuf, "%sFrom: Local Computer %s\\\n\nTo: Remote Computer %s\\\n\nTotal %d file(s)/folder(s)",
+ prefix, m_szLocalPath, m_szRemotePath, numSel);
+
+ if (MessageBox(m_hwndFTDialog, pBuf, "Copy Selected Files and Folders", MB_OKCANCEL) == IDOK)
+ m_pFileTransfer->addTransferQueue(m_szLocalPath, m_szRemotePath, &fi, FT_ATTR_COPY_UPLOAD);
+
+ setButtonsState();
+
+ delete [] pBuf;
+ return;
+ }
+
+ setButtonsState();
+ setStatusText("File Transfer Impossible. No file(s) selected for transfer");
+}
+
+void
+FTDialog::onDownload()
+{
+ FileInfo fi;
+ char prefix[FT_FILENAME_SIZE];
+ prefix[0] = '\0';
+
+ if (m_pFileTransfer->isTransferEnable())
+ strcpy(prefix, "File Transfer is active.\nDo you want to add selected file(s)/folder(s) to transfer queue?\n\n");
+
+ int numSel = m_pRemoteLV->getSelectedItems(&fi);
+ if (numSel > 0) {
+ char *pBuf = new char [(numSel + 4) * (MAX_PATH + 3) + strlen(prefix) + 1];
+ sprintf(pBuf, "%sFrom: Remote Computer %s\\\n\n", prefix, m_szRemotePath);
+
+ for (unsigned int i = 0; i < fi.getNumEntries(); i++)
+ sprintf(pBuf, "%s%s, ", pBuf, fi.getNameAt(i));
+
+ sprintf(pBuf, "%s\n\nTo: Local Computer %s\\", pBuf, m_szLocalPath);
+
+ if (strlen(pBuf) > 2048)
+ sprintf(pBuf, "%sFrom: Remote Computer %s\\\n\nTo: Local Computer %s\\\n\nTotal %d file(s)/folder(s)",
+ prefix, m_szRemotePath, m_szLocalPath, numSel);
+
+ if (MessageBox(m_hwndFTDialog, pBuf, "Copy Selected Files and Folders", MB_OKCANCEL) == IDOK)
+ m_pFileTransfer->addTransferQueue(m_szLocalPath, m_szRemotePath, &fi, FT_ATTR_COPY_DOWNLOAD);
+
+ setButtonsState();
+
+ delete [] pBuf;
+ return;
+ }
+
+ setButtonsState();
+ setStatusText("File Transfer Impossible. No file(s) selected for transfer");
+}
+
+void
+FTDialog::onLocalRename()
+{
+ if (m_pRenameDlg != NULL) return;
+
+ FileInfo fi;
+ if (m_pLocalLV->getSelectedItems(&fi) == 1) {
+ unsigned int flags = fi.getFlagsAt(0);
+ m_pRenameDlg = new FTDialog::RenameDlg(this);
+ if (m_pRenameDlg != NULL) {
+ if (flags & FT_ATTR_DIR) {
+ m_pRenameDlg->create(fi.getNameAt(0), true);
+ } else {
+ m_pRenameDlg->create(fi.getNameAt(0), false);
+ }
+ if (strlen(m_pRenameDlg->getFolderName()) > 0) {
+ FolderManager fm;
+ fm.renameIt(m_szLocalPath, fi.getNameAt(0), m_pRenameDlg->getFolderName());
+ showLocalLVItems();
+ }
+ delete m_pRenameDlg;
+ m_pRenameDlg = NULL;
+ }
+ }
+ setButtonsState();
+}
+
+void
+FTDialog::onRemoteRename()
+{
+ if (m_pRenameDlg != NULL) return;
+
+ FileInfo fi;
+ if (m_pRemoteLV->getSelectedItems(&fi) == 1) {
+ unsigned int flags = fi.getFlagsAt(0);
+ m_pRenameDlg = new FTDialog::RenameDlg(this);
+ if (m_pRenameDlg != NULL) {
+ if (flags & FT_ATTR_DIR) {
+ m_pRenameDlg->create(fi.getNameAt(0), true);
+ } else {
+ m_pRenameDlg->create(fi.getNameAt(0), false);
+ }
+ if (strlen(m_pRenameDlg->getFolderName()) > 0) {
+ m_pFileTransfer->renameRemote(m_szRemotePath, fi.getNameAt(0), m_pRenameDlg->getFolderName());
+ }
+ delete m_pRenameDlg;
+ m_pRenameDlg = NULL;
+ }
+ }
+ setButtonsState();
+}
+
+void
+FTDialog::onLocalDelete()
+{
+ FileInfo fi;
+ if (m_pLocalLV->getSelectedItems(&fi) > 0) {
+ m_pFileTransfer->addDeleteQueue(m_szLocalPath, &fi, FT_ATTR_DELETE_LOCAL);
+ }
+ setButtonsState();
+}
+
+void
+FTDialog::onRemoteDelete()
+{
+ FileInfo fi;
+ if (m_pRemoteLV->getSelectedItems(&fi) > 0) {
+ m_pFileTransfer->addDeleteQueue(m_szRemotePath, &fi, FT_ATTR_DELETE_REMOTE);
+ }
+ setButtonsState();
+}
+
+bool
+FTDialog::getCreateFolderName()
+{
+ if (m_pCreateFolderDlg != NULL) return false;
+
+ bool bResult = false;
+
+ m_pCreateFolderDlg = new FTDialog::CreateFolderDlg(this);
+ m_pCreateFolderDlg->create();
+ if (strlen(m_pCreateFolderDlg->getFolderName()) != 0) {
+ strcpy(m_szCreateFolderName, m_pCreateFolderDlg->getFolderName());
+ bResult = true;
+ } else {
+ m_szCreateFolderName[0] = '\0';
+ bResult = false;
+ }
+ delete m_pCreateFolderDlg;
+ m_pCreateFolderDlg = NULL;
+
+ return bResult;
+}
+
+void
+FTDialog::onLocalCreateFolder()
+{
+ if (getCreateFolderName()) {
+ char path[FT_FILENAME_SIZE];
+ sprintf(path, "%s\\%s", m_szLocalPath, m_szCreateFolderName);
+ setStatusText("Creating Local Folder: %s", path);
+ FolderManager fm;
+ if (fm.createDir(path)) showLocalLVItems();
+ }
+}
+
+void
+FTDialog::onRemoteCreateFolder()
+{
+ if (getCreateFolderName()) {
+ m_pFileTransfer->createRemoteFolder(m_szRemotePath, m_szCreateFolderName);
+ }
+}
+
+void
+FTDialog::onFTCancel()
+{
+ if (m_pCancelingDlg != NULL) return;
+
+ m_pCancelingDlg = new CancelingDlg(this);
+
+ m_pCancelingDlg->create();
+}
+
+void
+FTDialog::cancelTransfer(bool bResult)
+{
+ if (m_pCancelingDlg != NULL) {
+ delete m_pCancelingDlg;
+ m_pCancelingDlg = NULL;
+ }
+
+ setButtonsState();
+
+ if ((m_bCloseDlgAfterCancel) && (bResult)) {
+ m_bCloseDlgAfterCancel = false;
+ closeFTDialog();
+ }
+
+ m_pFileTransfer->m_bCancel = bResult;
+}
+
+void
+FTDialog::afterCancelTransfer()
+{
+ if (m_pCancelingDlg != NULL) {
+ delete m_pCancelingDlg;
+ m_pCancelingDlg = NULL;
+ }
+}
+
+void
+FTDialog::onFTMenuCommand(int command)
+{
+ switch (command)
+ {
+ case IDM_FTCOPY:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onUpload(); break;
+ case IDC_FTREMOTELIST: onDownload(); break;
+ default: break;
+ }
+ }
+ break;
+ case IDM_FTRENAME:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onLocalRename(); break;
+ case IDC_FTREMOTELIST: onRemoteRename(); break;
+ default: break;
+ }
+ }
+ break;
+ case IDM_FTDELETE:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onLocalDelete(); break;
+ case IDC_FTREMOTELIST: onRemoteDelete(); break;
+ default: break;
+ }
+ }
+ break;
+ case IDM_FTCANCEL: onFTCancel(); break;
+ case IDM_FTCREATEFOLDER:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onLocalCreateFolder(); break;
+ case IDC_FTREMOTELIST: onRemoteCreateFolder(); break;
+ default: break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+FTDialog::onLocalRButton()
+{
+ refreshBtnState();
+ m_FTMenuSource = IDC_FTLOCALLIST;
+ showFTMenu(m_BtnState.uploadBtn, m_BtnState.createLocalFldBtn,
+ m_BtnState.renameLocalBtn, m_BtnState.deleteLocalBtn,
+ m_BtnState.cancelBtn);
+}
+
+void
+FTDialog::onRemoteRButton()
+{
+ refreshBtnState();
+ m_FTMenuSource = IDC_FTREMOTELIST;
+ showFTMenu(m_BtnState.downloadBtn, m_BtnState.createRemoteFldBtn,
+ m_BtnState.renameRemoteBtn, m_BtnState.deleteRemoteBtn,
+ m_BtnState.cancelBtn);
+}
+
+void
+FTDialog::showFTMenu(bool copyBtnState, bool createFldBtnState, bool renameBtnState,
+ bool deleteBtnState, bool cancelBtnState)
+{
+ HMENU hMenu = LoadMenu(m_hInstance, MAKEINTRESOURCE(IDR_FTMENU));
+ HMENU hFTMenu = GetSubMenu(hMenu, 0);
+
+ SetMenuDefaultItem(hFTMenu, IDM_FTCOPY, FALSE);
+
+ SetForegroundWindow(m_hwndFTDialog);
+
+ if (copyBtnState) {
+ EnableMenuItem(hMenu, IDM_FTCOPY, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTCOPY, MF_DISABLED | MF_GRAYED);
+ }
+ if (createFldBtnState) {
+ EnableMenuItem(hMenu, IDM_FTCREATEFOLDER, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTCREATEFOLDER, MF_DISABLED | MF_GRAYED);
+ }
+ if (renameBtnState) {
+ EnableMenuItem(hMenu, IDM_FTRENAME, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTRENAME, MF_DISABLED | MF_GRAYED);
+ }
+ if (deleteBtnState) {
+ EnableMenuItem(hMenu, IDM_FTDELETE, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTDELETE, MF_DISABLED | MF_GRAYED);
+ }
+ if (cancelBtnState) {
+ EnableMenuItem(hMenu, IDM_FTCANCEL, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTCANCEL, MF_DISABLED | MF_GRAYED);
+ }
+ DrawMenuBar(m_hwndFTDialog);
+
+ POINT cursorPosition;
+ GetCursorPos(&cursorPosition);
+ TrackPopupMenu(hFTMenu, 0, cursorPosition.x, cursorPosition.y, 0, m_hwndFTDialog, 0);
+ DestroyMenu(hFTMenu);
+}
+
+void
+FTDialog::setIcon(int dest, int idIcon)
+{
+ HANDLE hIcon = LoadImage(m_hInstance, MAKEINTRESOURCE(idIcon), IMAGE_ICON, 16, 16, LR_SHARED);
+ SendMessage(GetDlgItem(m_hwndFTDialog, dest), BM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) hIcon);
+ DestroyIcon((HICON) hIcon);
+}
+
+void
+FTDialog::refreshBtnState()
+{
+ if (!m_bDlgShown) return;
+
+ int locPathLen = strlen(m_szLocalPath);
+ int remPathLen = strlen(m_szRemotePath);
+
+ if (GetFocus() == m_pLocalLV->getWndHandle()) {
+ m_BtnState.downloadBtn = false;
+ if (strlen(m_szLocalPath) != 0) {
+ m_BtnState.createLocalFldBtn = true;
+ int nCount = ListView_GetSelectedCount(m_pLocalLV->getWndHandle());
+ if (nCount <= 0) {
+ m_BtnState.uploadBtn = false;
+ m_BtnState.deleteLocalBtn = false;
+ m_BtnState.renameLocalBtn = false;
+ } else {
+ m_BtnState.deleteLocalBtn = true;
+ if (remPathLen == 0) {
+ m_BtnState.uploadBtn = false;
+ } else {
+ m_BtnState.uploadBtn = true;
+ }
+ if (nCount == 1) {
+ m_BtnState.renameLocalBtn = true;
+ } else {
+ m_BtnState.renameLocalBtn = false;
+ }
+ }
+ } else {
+ m_BtnState.uploadBtn = false;
+ m_BtnState.createLocalFldBtn = false;
+ m_BtnState.deleteLocalBtn = false;
+ m_BtnState.renameLocalBtn = false;
+ m_BtnState.downloadBtn = false;
+ }
+ } else {
+ if (GetFocus() == m_pRemoteLV->getWndHandle()) {
+ m_BtnState.uploadBtn = false;
+ if (strlen(m_szRemotePath) != 0) {
+ m_BtnState.createRemoteFldBtn = true;
+ int nCount = ListView_GetSelectedCount(m_pRemoteLV->getWndHandle());
+ if (nCount <= 0) {
+ m_BtnState.downloadBtn = false;
+ m_BtnState.deleteRemoteBtn = false;
+ m_BtnState.renameRemoteBtn = false;
+ } else {
+ m_BtnState.deleteRemoteBtn = true;
+ if (locPathLen == 0) {
+ m_BtnState.downloadBtn = false;
+ } else {
+ m_BtnState.downloadBtn = true;
+ }
+ if (nCount == 1) {
+ m_BtnState.renameRemoteBtn = true;
+ } else {
+ m_BtnState.renameRemoteBtn = false;
+ }
+ }
+ } else {
+ m_BtnState.downloadBtn = false;
+ m_BtnState.createRemoteFldBtn = false;
+ m_BtnState.deleteRemoteBtn = false;
+ m_BtnState.renameRemoteBtn = false;
+ m_BtnState.uploadBtn = false;
+ }
+ } else {
+ }
+ }
+ if (m_pFileTransfer->isTransferEnable())
+ m_BtnState.cancelBtn = true;
+ else
+ m_BtnState.cancelBtn = false;
+}
+
+void
+FTDialog::setButtonsState()
+{
+ refreshBtnState();
+
+ switch (m_BtnState.uploadBtn)
+ {
+ case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTUPLOAD), FALSE); break;
+ case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTUPLOAD), TRUE); break;
+ }
+
+ switch (m_BtnState.downloadBtn)
+ {
+ case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTDOWNLOAD), FALSE); break;
+ case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTDOWNLOAD), TRUE); break;
+ }
+
+ switch (m_BtnState.cancelBtn)
+ {
+ case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTCANCEL), FALSE); break;
+ case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTCANCEL), TRUE); break;
+ }
+
+ UpdateWindow(m_hwndFTDialog);
+}
+
+void
+FTDialog::setStatusText(LPCSTR format,...)
+{
+ char text[1024];
+ va_list args;
+ va_start(args, format);
+ int nSize = _vsnprintf(text, sizeof(text), format, args);
+
+ HWND hStatusBox = GetDlgItem(m_hwndFTDialog, IDC_FTSTATUS);
+
+ LRESULT lRes = SendMessage(hStatusBox, (UINT) CB_INSERTSTRING, (WPARAM) 0, (LPARAM) text);
+ if ((lRes != CB_ERR) && (lRes != CB_ERRSPACE)) {
+ lRes = SendMessage(hStatusBox, (UINT) CB_SETCURSEL, (WPARAM) lRes, (LPARAM) 0);
+ }
+
+ m_dwNumStatusStrings++;
+ if (m_dwNumStatusStrings > FT_MAX_STATUS_STRINGS) {
+ int numItems = SendMessage(hStatusBox, (UINT) CB_GETCOUNT, (WPARAM) 0, (LPARAM) 0);
+ if (numItems != CB_ERR) {
+ m_dwNumStatusStrings--;
+ SendMessage(hStatusBox, (UINT) CB_DELETESTRING, (WPARAM) numItems - 1, (LPARAM) 0);
+ }
+ }
+}
+
+void
+FTDialog::getBrowseItems(char *pPath)
+{
+ if (m_bLocalBrowsing) {
+ FileInfo fi;
+ FolderManager fm;
+ fm.getDirInfo(pPath, &fi, 1);
+ if (m_pBrowseDlg != NULL) m_pBrowseDlg->addItems(&fi);
+ } else {
+ m_pFileTransfer->requestFileList(pPath, FT_FLR_DEST_BROWSE, true);
+ }
+}
+
+void
+FTDialog::addBrowseItems(FileInfo *pFI)
+{
+ if (m_pBrowseDlg == NULL) return;
+
+ m_pBrowseDlg->addItems(pFI);
+}
+
+void
+FTDialog::processDlgMsgs()
+{
+ MSG msg;
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+void
+FTDialog::postCheckTransferQueueMsg()
+{
+ PostMessage(m_hwndFTDialog, m_msgCheckTransferQueue, 0, 0);
+}
+
+void
+FTDialog::postUploadFilePortionMsg()
+{
+ PostMessage(m_hwndFTDialog, m_msgUploadFilePortion, 0, 0);
+}
+
+void
+FTDialog::postCheckDeleteQueueMsg()
+{
+ PostMessage(m_hwndFTDialog, m_msgCheckDeleteQueue, 0, 0);
+}
+
+FTDialog::CancelingDlg::CancelingDlg(FTDialog *pFTDlg)
+{
+ m_pFTDlg = pFTDlg;
+ m_hwndDlg = NULL;
+}
+
+FTDialog::CancelingDlg::~CancelingDlg()
+{
+ destroy();
+}
+
+bool
+FTDialog::CancelingDlg::create()
+{
+ if (m_hwndDlg != NULL) return false;
+
+ m_hwndDlg = CreateDialogParam(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDD_FTCANCELING),
+ NULL,
+ (DLGPROC) cancelingDlgProc,
+ (LONG) this);
+
+ if (m_hwndDlg == NULL) return false;
+
+ ShowWindow(m_hwndDlg, SW_SHOW);
+ DrawIcon(GetDC(m_hwndDlg), 15, 22, LoadIcon(NULL, IDI_QUESTION));
+ UpdateWindow(m_hwndDlg);
+
+ return true;
+}
+
+bool
+FTDialog::CancelingDlg::destroy()
+{
+ if (m_hwndDlg == NULL) return true;
+
+ if (DestroyWindow(m_hwndDlg)) {
+ m_hwndDlg = NULL;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool
+FTDialog::CancelingDlg::close(bool bResult)
+{
+ if (m_hwndDlg == NULL) return true;
+
+ destroy();
+
+ m_pFTDlg->cancelTransfer(bResult);
+
+ return false;
+}
+
+BOOL CALLBACK
+FTDialog::CancelingDlg::cancelingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FTDialog::CancelingDlg *_this = (FTDialog::CancelingDlg *) GetWindowLong(hwnd, GWL_USERDATA);
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
+ SetForegroundWindow(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ _this->close(true);
+ return TRUE;
+ case IDCANCEL:
+ _this->close(false);
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ _this->close(false);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+FTDialog::CreateFolderDlg::CreateFolderDlg(FTDialog *pFTDlg) : Dialog(GetModuleHandle(0))
+{
+ m_pFTDlg = pFTDlg;
+ m_szFolderName[0] = '\0';
+}
+
+FTDialog::CreateFolderDlg::~CreateFolderDlg()
+{
+
+}
+
+bool
+FTDialog::CreateFolderDlg::create()
+{
+ return showDialog(MAKEINTRESOURCE(IDD_FTCREATEFOLDER), m_pFTDlg->getWndHandle());
+}
+
+bool
+FTDialog::CreateFolderDlg::onOk()
+{
+ strcpy(m_szFolderName, getItemString(IDC_FTFOLDERNAME));
+ return true;
+}
+
+FTDialog::RenameDlg::RenameDlg(FTDialog *pFTDlg) : CreateFolderDlg(pFTDlg)
+{
+ m_bFolder = false;
+}
+
+FTDialog::RenameDlg::~RenameDlg()
+{
+}
+
+bool
+FTDialog::RenameDlg::create(char *pFilename, bool bFolder)
+{
+ m_bFolder = bFolder;
+ strcpy(m_szFilename, pFilename);
+ return showDialog(MAKEINTRESOURCE(IDD_FTCREATEFOLDER), m_pFTDlg->getWndHandle());
+}
+
+void
+FTDialog::RenameDlg::initDialog()
+{
+ char buf[2*FT_FILENAME_SIZE];
+ if (m_bFolder) {
+ SetWindowText(handle, "Rename Folder");
+ sprintf(buf, "Rename Folder '%s'", m_szFilename);
+ } else {
+ SetWindowText(handle, "Rename File");
+ sprintf(buf, "Rename File '%s'", m_szFilename);
+ }
+
+ setItemString(IDC_FTTEXT, buf);
+ setItemString(IDC_FTFOLDERNAME, m_szFilename);
+ SendDlgItemMessage(handle, IDC_FTFOLDERNAME, EM_SETSEL, (WPARAM) 0, (LPARAM) -1);
+}
diff --git a/win/vncviewer/FTDialog.h b/win/vncviewer/FTDialog.h
new file mode 100644
index 00000000..a4b55461
--- /dev/null
+++ b/win/vncviewer/FTDialog.h
@@ -0,0 +1,243 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTDialog.h
+
+#ifndef __RFB_WIN32_FTDIALOG_H__
+#define __RFB_WIN32_FTDIALOG_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb_win32/Dialog.h>
+#include <vncviewer/FileTransfer.h>
+#include <vncviewer/FTListView.h>
+#include <vncviewer/FTProgress.h>
+#include <vncviewer/FTBrowseDlg.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32 {
+ class FileTransfer;
+ class FTBrowseDlg;
+
+ class FTDialog
+ {
+ public:
+ FTDialog(HINSTANCE hInst, FileTransfer *pFT);
+ ~FTDialog();
+
+ bool createFTDialog(HWND hwndParent);
+ bool closeFTDialog();
+ void destroyFTDialog();
+
+ void processDlgMsgs();
+
+ void cancelTransfer(bool bResult);
+ void afterCancelTransfer();
+
+ static BOOL CALLBACK FTDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ void addRemoteLVItems(FileInfo *pFI);
+ void reqFolderUnavailable();
+
+ void onEndBrowseDlg(bool bResult);
+ void getBrowseItems(char *pPath);
+ void addBrowseItems(FileInfo *pFI);
+
+ void setStatusText(LPCSTR format,...);
+
+ HWND getWndHandle() { return m_hwndFTDialog; }
+
+ void postCheckDeleteQueueMsg();
+ void postCheckTransferQueueMsg();
+ void postUploadFilePortionMsg();
+ void postDownloadFilePortionMsg();
+
+ char *getLocalPath() { return m_szLocalPath; }
+ char *getRemotePath() { return m_szRemotePath; }
+
+ FTProgress *m_pProgress;
+ FileTransfer *m_pFileTransfer;
+
+ private:
+ HWND m_hwndFTDialog;
+ HWND m_hwndLocalPath;
+ HWND m_hwndRemotePath;
+ HINSTANCE m_hInstance;
+
+ void showLocalLVItems();
+ void showRemoteLVItems();
+
+ void onClose();
+
+ void onLocalItemActivate(LPNMITEMACTIVATE lpnmia);
+ void onRemoteItemActivate(LPNMITEMACTIVATE lpnmia);
+
+ void onLocalBrowse();
+ void onRemoteBrowse();
+
+ void onLocalReload();
+ void onRemoteReload();
+
+ void onLocalRButton();
+ void onRemoteRButton();
+
+ bool getCreateFolderName();
+ void onLocalCreateFolder();
+ void onRemoteCreateFolder();
+
+ void showFTMenu(bool copyBtnState, bool createFldBtnState,
+ bool renameBtnState, bool deleteBtnState,
+ bool cancelBtnState);
+ void onFTMenuCommand(int command);
+
+ void onUpload();
+ void onDownload();
+
+ void onLocalRename();
+ void onRemoteRename();
+
+ void onLocalDelete();
+ void onRemoteDelete();
+
+ void onFTCancel();
+
+ void setIcon(int dest, int idIcon);
+ bool initFTDialog();
+ bool initFTWndMsgs();
+
+ void onLocalOneUpFolder();
+ void onRemoteOneUpFolder();
+ int makeOneUpFolder(char *pPath);
+
+ void refreshBtnState();
+ void setButtonsState();
+
+ bool m_bDlgShown;
+ bool m_bLocalBrowsing;
+ bool m_bCloseDlgAfterCancel;
+
+ UINT m_msgCheckDeleteQueue;
+ UINT m_msgCheckTransferQueue;
+ UINT m_msgUploadFilePortion;
+ UINT m_msgDownloadFilePortion;
+
+ DWORD m_dwNumStatusStrings;
+
+ FTListView *m_pLocalLV;
+ FTListView *m_pRemoteLV;
+
+ FTBrowseDlg *m_pBrowseDlg;
+
+ int m_FTMenuSource;
+
+ char m_szLocalPath[FT_FILENAME_SIZE];
+ char m_szRemotePath[FT_FILENAME_SIZE];
+ char m_szLocalPathTmp[FT_FILENAME_SIZE];
+ char m_szRemotePathTmp[FT_FILENAME_SIZE];
+ char m_szCreateFolderName[FT_FILENAME_SIZE];
+
+ static const char szCheckDeleteQueueText[];
+ static const char szCheckTransferQueueText[];
+ static const char szUploadFilePortionText[];
+
+ typedef struct tagFTBUTTONSSTATE
+ {
+ bool uploadBtn;
+ bool downloadBtn;
+ bool createLocalFldBtn;
+ bool createRemoteFldBtn;
+ bool renameLocalBtn;
+ bool renameRemoteBtn;
+ bool deleteLocalBtn;
+ bool deleteRemoteBtn;
+ bool cancelBtn;
+ } FTBUTTONSSTATE;
+
+ FTBUTTONSSTATE m_BtnState;
+
+ public:
+ class CancelingDlg
+ {
+ public:
+ CancelingDlg(FTDialog *pFTDlg);
+ ~CancelingDlg();
+
+ static BOOL CALLBACK cancelingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ bool create();
+ bool destroy();
+
+ private:
+ FTDialog *m_pFTDlg;
+ HWND m_hwndDlg;
+
+ bool close(bool bResult);
+ };
+
+ private:
+ CancelingDlg *m_pCancelingDlg;
+
+ public:
+ class CreateFolderDlg : public Dialog
+ {
+ public:
+ CreateFolderDlg(FTDialog *pFTDlg);
+ ~CreateFolderDlg();
+
+ bool onOk();
+ bool create();
+ char *getFolderName() { return m_szFolderName; }
+
+ protected:
+ FTDialog *m_pFTDlg;
+ char m_szFolderName[FT_FILENAME_SIZE];
+ };
+
+ private:
+ CreateFolderDlg *m_pCreateFolderDlg;
+
+ public:
+ class RenameDlg : public CreateFolderDlg
+ {
+ public:
+ RenameDlg(FTDialog *pFTDlg);
+ ~RenameDlg();
+
+ bool create(char *pFilename, bool bFolder);
+ void initDialog();
+
+ private:
+ bool m_bFolder;
+ char m_szFilename[FT_FILENAME_SIZE];
+ };
+
+ private:
+ RenameDlg *m_pRenameDlg;
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTDIALOG_H__
diff --git a/win/vncviewer/FTListView.cxx b/win/vncviewer/FTListView.cxx
new file mode 100644
index 00000000..8f41abf6
--- /dev/null
+++ b/win/vncviewer/FTListView.cxx
@@ -0,0 +1,211 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTListView.cxx
+
+#include <vncviewer/FTListView.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTListView::FTListView(HWND hListView)
+{
+ m_bInitialized = false;
+ m_hListView = hListView;
+ m_fileInfo.free();
+}
+
+FTListView::~FTListView()
+{
+ m_fileInfo.free();
+}
+
+
+bool
+FTListView::initialize(HINSTANCE hInst)
+{
+ if (m_bInitialized) return false;
+
+ initImageList(hInst);
+
+ RECT Rect;
+ GetClientRect(m_hListView, &Rect);
+ Rect.right -= GetSystemMetrics(SM_CXHSCROLL);
+ int xwidth0 = (int) (0.35 * Rect.right);
+ int xwidth1 = (int) (0.22 * Rect.right);
+ int xwidth2 = (int) (0.43 * Rect.right);
+
+ addColumn("Name", 0, xwidth0, LVCFMT_LEFT);
+ addColumn("Size", 1, xwidth1, LVCFMT_RIGHT);
+ addColumn("Data", 2, xwidth2, LVCFMT_LEFT);
+
+ ListView_SetExtendedListViewStyleEx(m_hListView, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
+
+ return true;
+}
+
+void
+FTListView::onGetDispInfo(NMLVDISPINFO *pDI)
+{
+ if (m_fileInfo.getFlagsAt(pDI->item.iItem) & FT_ATTR_DIR) {
+ pDI->item.iImage = 0;
+ } else {
+ pDI->item.iImage = 1;
+ }
+
+ switch (pDI->item.iSubItem)
+ {
+ case 0:
+ pDI->item.pszText = m_fileInfo.getNameAt(pDI->item.iItem);
+ break;
+ case 1:
+ {
+ unsigned int flags = m_fileInfo.getFlagsAt(pDI->item.iItem);
+ switch(flags & 0x000000FF)
+ {
+ case FT_ATTR_FILE:
+ {
+ char buf[32];
+ unsigned int size = m_fileInfo.getSizeAt(pDI->item.iItem);
+ sprintf(buf, "%u", size);
+ pDI->item.pszText = buf;
+ }
+ break;
+ case FT_ATTR_DIR:
+ pDI->item.pszText = "";
+ break;
+ default:
+ pDI->item.pszText = "Unspecified";
+ }
+ }
+ break;
+ case 2:
+ {
+ unsigned int data = m_fileInfo.getDataAt(pDI->item.iItem);
+ if (data == 0) {
+ pDI->item.pszText = "Unspecified";
+ } else {
+ FILETIME ft;
+ FolderManager fm;
+ fm.getFiletime(data, &ft);
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&ft, &st);
+
+ char pDateTimeStr[1024];
+ char timeFmt[128];
+ GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, timeFmt, 128);
+ char dateFmt[128];
+ GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, dateFmt, 128);
+
+ char timeStr[128];
+ GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, timeFmt, timeStr, 128);
+ char dateStr[128];
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, dateFmt, dateStr, 128);
+
+ sprintf(pDateTimeStr, "%s %s", dateStr, timeStr);
+ pDI->item.pszText = pDateTimeStr;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+FTListView::addItems(FileInfo *pFI)
+{
+ m_fileInfo.add(pFI);
+ LVITEM LVItem;
+ LVItem.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
+ LVItem.state = 0;
+ LVItem.stateMask = 0;
+ for (unsigned int i = 0; i < m_fileInfo.getNumEntries(); i++) {
+ LVItem.iItem = i;
+ LVItem.iSubItem = 0;
+ LVItem.iImage = I_IMAGECALLBACK;
+ LVItem.pszText = LPSTR_TEXTCALLBACK;
+ ListView_InsertItem(m_hListView, &LVItem);
+ }
+}
+
+void
+FTListView::deleteAllItems()
+{
+ ListView_DeleteAllItems(m_hListView);
+ m_fileInfo.free();
+}
+
+char *
+FTListView::getActivateItemName(LPNMITEMACTIVATE lpnmia)
+{
+ return m_fileInfo.getNameAt(lpnmia->iItem);
+}
+
+int
+FTListView::getSelectedItems(FileInfo *pFI)
+{
+ int selCount = ListView_GetSelectedCount(m_hListView);
+ int selItem = ListView_GetSelectionMark(m_hListView);
+ if ((selCount < 1) || (selItem < 0)) return -1;
+
+ selItem = -1;
+ selItem = ListView_GetNextItem(m_hListView, selItem, LVNI_SELECTED);
+ do {
+ pFI->add(m_fileInfo.getFullDataAt(selItem));
+ selItem = ListView_GetNextItem(m_hListView, selItem, LVNI_SELECTED);
+ } while (selItem >= 0);
+
+ return selCount;
+}
+
+void
+FTListView::initImageList(HINSTANCE hInst)
+{
+ m_hImageList = ImageList_Create(16, 16, ILC_MASK, 2, 2);
+
+ HICON hiconItem = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FTDIR));
+ ImageList_AddIcon(m_hImageList, hiconItem);
+ DestroyIcon(hiconItem);
+
+ hiconItem = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FTFILE));
+ ImageList_AddIcon(m_hImageList, hiconItem);
+ DestroyIcon(hiconItem);
+
+ ListView_SetImageList(m_hListView, m_hImageList, LVSIL_SMALL);
+}
+
+void
+FTListView::addColumn(char *iText, int iOrder, int xWidth, int alignFmt)
+{
+ LVCOLUMN lvc;
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
+ lvc.fmt = alignFmt;
+ lvc.iSubItem = iOrder;
+ lvc.pszText = iText;
+ lvc.cchTextMax = 32;
+ lvc.cx = xWidth;
+ lvc.iOrder = iOrder;
+ ListView_InsertColumn(m_hListView, iOrder, &lvc);
+}
diff --git a/win/vncviewer/FTListView.h b/win/vncviewer/FTListView.h
new file mode 100644
index 00000000..c920fa00
--- /dev/null
+++ b/win/vncviewer/FTListView.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTListView.h
+
+#ifndef __RFB_WIN32_FTLISTVIEW_H__
+#define __RFB_WIN32_FTLISTVIEW_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb_win32/FolderManager.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32{
+ class FTListView
+ {
+ public:
+ FTListView(HWND hListView);
+ ~FTListView();
+
+ bool initialize(HINSTANCE hInst);
+
+ void onGetDispInfo(NMLVDISPINFO *di);
+ void addItems(FileInfo *pFI);
+ void deleteAllItems();
+
+ char *getActivateItemName(LPNMITEMACTIVATE lpnmia);
+ int getSelectedItems(FileInfo *pFI);
+
+ HWND getWndHandle() { return m_hListView; };
+
+ private:
+ HWND m_hListView;
+ FileInfo m_fileInfo;
+ HIMAGELIST m_hImageList;
+
+ bool m_bInitialized;
+
+ void addColumn(char *iText, int iOrder, int xWidth, int alignFmt);
+ void initImageList(HINSTANCE hInst);
+
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTLISTVIEW_H__
diff --git a/win/vncviewer/FTProgress.cxx b/win/vncviewer/FTProgress.cxx
new file mode 100644
index 00000000..e6cc952f
--- /dev/null
+++ b/win/vncviewer/FTProgress.cxx
@@ -0,0 +1,151 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTProgress.cxx
+
+#include <vncviewer/FTProgress.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTProgress::FTProgress(HWND hwndParent)
+{
+ m_bInitialized = false;
+ m_hwndParent = hwndParent;
+
+ m_pSingleProgress = NULL;
+ m_pGeneralProgress = NULL;
+
+ m_hwndSinglePercent = GetDlgItem(m_hwndParent, IDC_FTSINGLEPERCENT);
+ m_hwndGeneralPercent = GetDlgItem(m_hwndParent, IDC_FTGENERALPERCENT);
+
+ m_bInitialized = createProgressBarObjects();
+}
+
+FTProgress::~FTProgress()
+{
+ destroyProgressBarObjects();
+}
+
+void
+FTProgress::increase(DWORD value)
+{
+ if (!m_bInitialized) return;
+
+ m_pSingleProgress->increase(value);
+ m_pGeneralProgress->increase(value);
+
+ setProgressText();
+}
+
+void
+FTProgress::clearAndInitGeneral(DWORD64 dw64MaxValue, DWORD64 dw64Position)
+{
+ if (!m_bInitialized) return;
+
+ m_pGeneralProgress->clear();
+ m_pGeneralProgress->init(dw64MaxValue, dw64Position);
+
+ setProgressText();
+}
+
+void
+FTProgress::clearAndInitSingle(DWORD dwMaxValue, DWORD dwPosition)
+{
+ if (!m_bInitialized) return;
+
+ m_pSingleProgress->clear();
+ m_pSingleProgress->init(dwMaxValue, dwPosition);
+
+ setProgressText();
+}
+
+void
+FTProgress::clearAll()
+{
+ if (!m_bInitialized) return;
+
+ m_pSingleProgress->clear();
+ m_pGeneralProgress->clear();
+
+ setProgressText();
+}
+
+bool
+FTProgress::createProgressBarObjects()
+{
+ if ((m_pSingleProgress != NULL) || (m_pGeneralProgress != NULL)) {
+ return false;
+ } else {
+ HWND hwndSingleProgr = GetDlgItem(m_hwndParent, IDC_FTSINGLEPROGRESS);
+ HWND hwndGeneralProgr = GetDlgItem(m_hwndParent, IDC_FTGENERALPROGRESS);
+
+ m_pSingleProgress = new ProgressControl(hwndSingleProgr);
+ if (m_pSingleProgress == NULL) return false;
+
+ m_pGeneralProgress = new ProgressControl(hwndGeneralProgr);
+ if (m_pGeneralProgress == NULL) {
+ delete m_pSingleProgress;
+ m_pSingleProgress = NULL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+FTProgress::destroyProgressBarObjects()
+{
+ clearAll();
+
+ if (m_pSingleProgress != NULL) {
+ delete m_pSingleProgress;
+ m_pSingleProgress = NULL;
+ }
+
+ if (m_pGeneralProgress != NULL) {
+ delete m_pGeneralProgress;
+ m_pGeneralProgress = NULL;
+ }
+
+ return true;
+}
+
+void
+FTProgress::setProgressText()
+{
+ char buf[16] = {0};
+ char buf2[16] = {0};
+
+ int percent = m_pSingleProgress->getCurrentPercent();
+ sprintf(buf, "%d%%", percent);
+ GetWindowText(m_hwndSinglePercent, buf2, 16);
+ if (strcmp(buf, buf2) != 0)
+ SetWindowText(m_hwndSinglePercent, buf);
+
+ percent = m_pGeneralProgress->getCurrentPercent();
+ sprintf(buf, "%d%%", percent);
+ GetWindowText(m_hwndGeneralPercent, buf2, 16);
+ if (strcmp(buf, buf2) != 0)
+ SetWindowText(m_hwndGeneralPercent, buf);
+} \ No newline at end of file
diff --git a/win/vncviewer/FTProgress.h b/win/vncviewer/FTProgress.h
new file mode 100644
index 00000000..caad7798
--- /dev/null
+++ b/win/vncviewer/FTProgress.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTProgress.h
+
+#ifndef __RFB_WIN32_FTPROGRESS_H__
+#define __RFB_WIN32_FTPROGRESS_H__
+
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#include <rfb_win32/ProgressControl.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32 {
+ class FTProgress
+ {
+ public:
+ FTProgress(HWND hwndParent);
+ ~FTProgress();
+
+ void increase(DWORD value);
+ void clearAndInitGeneral(DWORD64 dw64MaxValue, DWORD64 dw64Position);
+ void clearAndInitSingle(DWORD dwMaxValue, DWORD dwPosition);
+ void clearAll();
+
+ private:
+ ProgressControl *m_pSingleProgress;
+ ProgressControl *m_pGeneralProgress;
+
+ HWND m_hwndParent;
+ HWND m_hwndSinglePercent;
+ HWND m_hwndGeneralPercent;
+
+ bool m_bInitialized;
+
+ void setProgressText();
+ bool createProgressBarObjects();
+ bool destroyProgressBarObjects();
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTPROGRESS_H__
diff --git a/win/vncviewer/FileTransfer.cxx b/win/vncviewer/FileTransfer.cxx
new file mode 100644
index 00000000..cf57072f
--- /dev/null
+++ b/win/vncviewer/FileTransfer.cxx
@@ -0,0 +1,803 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileTransfer.cxx
+
+#include <vncviewer/FileTransfer.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FileTransfer::FileTransfer()
+{
+ m_bFTDlgShown = false;
+ m_bInitialized = false;
+ m_bResized = false;
+ m_bCancel = false;
+ m_bOverwriteAll = false;
+
+ m_pFTDialog = new FTDialog(GetModuleHandle(0), this);
+
+ m_pReader = NULL;
+ m_pWriter = NULL;
+
+ m_dw64SizeSending = 0;
+ m_dirSizeRqstNum = 0;
+}
+
+FileTransfer::~FileTransfer()
+{
+ if (m_pFTDialog != NULL) {
+ delete m_pFTDialog;
+ m_pFTDialog = NULL;
+ }
+
+ if (m_pReader != NULL) {
+ delete m_pReader;
+ m_pReader = NULL;
+ }
+
+ if (m_pWriter != NULL) {
+ delete m_pWriter;
+ m_pWriter = NULL;
+ }
+
+ freeQueues();
+}
+
+bool
+FileTransfer::initialize(rdr::InStream *pIS, rdr::OutStream *pOS)
+{
+ if (m_bInitialized) return false;
+
+ m_pReader = new CFTMsgReader(pIS);
+ m_pWriter = new CFTMsgWriter(pOS);
+
+ freeQueues();
+
+ m_bInitialized = true;
+ return true;
+}
+
+bool
+FileTransfer::show(HWND hwndParent)
+{
+ if (!m_bInitialized) return false;
+
+ m_bFTDlgShown = m_pFTDialog->createFTDialog(hwndParent);
+
+ return m_bFTDlgShown;
+}
+
+bool
+FileTransfer::processFTMsg(int type)
+{
+ if (!m_bInitialized) return false;
+
+ switch (type)
+ {
+ case msgTypeFileListData:
+ return procFileListDataMsg();
+ case msgTypeFileDownloadData:
+ return procFileDownloadDataMsg();
+ case msgTypeFileUploadCancel:
+ return procFileUploadCancelMsg();
+ case msgTypeFileDownloadFailed:
+ return procFileDownloadFailedMsg();
+ case msgTypeFileDirSizeData:
+ return procFileDirSizeDataMsg();
+ case msgTypeFileLastRequestFailed:
+ return procFileLastRqstFailedMsg();
+ default:
+ return false;
+ }
+}
+
+bool
+FileTransfer::isTransferEnable()
+{
+ if (m_TransferQueue.getNumEntries() > 0) return true; else return false;
+}
+
+void
+FileTransfer::addDeleteQueue(char *pPathPrefix, FileInfo *pFI, unsigned int flags)
+{
+ if ((m_bFTDlgShown) && (m_DeleteQueue.getNumEntries() > 0))
+ m_pFTDialog->setStatusText("Starting Delete Operation");
+
+ m_DeleteQueue.add(pPathPrefix, pPathPrefix, pFI, flags);
+
+ checkDeleteQueue();
+}
+
+void
+FileTransfer::checkDeleteQueue()
+{
+ if (m_DeleteQueue.getNumEntries() > 0) {
+ if (m_bFTDlgShown)
+ m_pFTDialog->setStatusText("Delete Operation Executing: %s", m_DeleteQueue.getFullLocPathAt(0));
+ if (m_DeleteQueue.getFlagsAt(0) & FT_ATTR_DELETE_LOCAL) {
+ FolderManager fm;
+ if (!fm.deleteIt(m_DeleteQueue.getFullLocPathAt(0))) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Failed");
+ } else {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Completed");
+ }
+ m_DeleteQueue.deleteAt(0);
+ m_pFTDialog->postCheckDeleteQueueMsg();
+ } else {
+ if (m_DeleteQueue.getFlagsAt(0) & FT_ATTR_DELETE_REMOTE) {
+ writeFileDeleteRqst(strlen(m_DeleteQueue.getFullLocPathAt(0)),
+ m_DeleteQueue.getFullLocPathAt(0));
+
+ char *pPath = m_DeleteQueue.getLocPathAt(0);
+ m_queueFileListRqst.add(pPath, 0, 0, FT_FLR_DEST_DELETE);
+ writeFileListRqst(strlen(pPath), pPath, false);
+ }
+ }
+ } else {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Delete Operation Completed Successfully");
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTREMOTERELOAD, 0), 0);
+ }
+ }
+}
+
+void
+FileTransfer::addTransferQueue(char *pLocalPath, char *pRemotePath,
+ FileInfo *pFI, unsigned int flags)
+{
+ if (!isTransferEnable()) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Starting Copy Operation");
+ m_bTransferSuccess = true;
+ }
+
+ m_TransferQueue.add(pLocalPath, pRemotePath, pFI, (flags | FT_ATTR_RESIZE_NEEDED));
+
+ checkTransferQueue();
+}
+
+bool
+FileTransfer::resizeSending()
+{
+ for (unsigned int i = 0; i < m_TransferQueue.getNumEntries(); i++) {
+ unsigned int flags = m_TransferQueue.getFlagsAt(i);
+ if (flags & FT_ATTR_RESIZE_NEEDED) {
+ if (flags & FT_ATTR_FILE) {
+ m_bResized = true;
+ m_dw64SizeSending += m_TransferQueue.getSizeAt(i);
+ m_TransferQueue.clearFlagAt(i, FT_ATTR_RESIZE_NEEDED);
+ } else {
+ if (flags & FT_ATTR_DIR) {
+ if (flags & FT_ATTR_COPY_DOWNLOAD) {
+ m_bResized = true;
+ char *pPath = m_TransferQueue.getFullRemPathAt(i);
+ m_dirSizeRqstNum = i;
+ writeFileDirSizeRqst(strlen(pPath), pPath);
+ return false;
+ } else {
+ if (flags & FT_ATTR_COPY_UPLOAD) {
+ FolderManager fm;
+ DWORD64 dw64Size;
+ m_bResized = true;
+ fm.getDirSize(m_TransferQueue.getFullLocPathAt(i), &dw64Size);
+ m_dw64SizeSending += dw64Size;
+ m_TransferQueue.clearFlagAt(i, FT_ATTR_RESIZE_NEEDED);
+ }
+ } // if (flags & FT_ATTR_COPY_DOWNLOAD)
+ } // if (flags & FT_ATTR_FOLDER)
+ } // if (flags & FT_ATTR_FILE)
+ } // if (flags & FT_ATTR_NEEDED_RESIZE)
+ } // for (unsigned int i = 0; i < m_TransferQueue.getNumEntries(); i++)
+
+ if ((m_bFTDlgShown) && (m_bResized)) {
+ m_pFTDialog->m_pProgress->clearAndInitGeneral(m_dw64SizeSending, 0);
+ m_bResized = false;
+ }
+
+ return true;
+}
+
+void
+FileTransfer::checkTransferQueue()
+{
+ if (!isTransferEnable()) {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->clearAll();
+ m_dw64SizeSending = 0;
+ m_bResized = false;
+
+ if (m_bTransferSuccess)
+ m_pFTDialog->setStatusText("File Transfer Operation Completed Successfully");
+ else
+ m_pFTDialog->setStatusText("File Transfer Operation Completed");
+
+ m_pFTDialog->afterCancelTransfer();
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTREMOTERELOAD, 0), 0);
+ return;
+ }
+ } else {
+ if (!resizeSending()) return;
+
+ unsigned int flag0 = m_TransferQueue.getFlagsAt(0);
+
+ if (flag0 & FT_ATTR_COPY_UPLOAD) {
+ if (flag0 & FT_ATTR_FILE) {
+ uploadFile();
+ return;
+ }
+ if (flag0 & FT_ATTR_DIR) {
+ char *pFullPath = m_TransferQueue.getFullRemPathAt(0);
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Remote Folder. %s", pFullPath);
+ writeFileCreateDirRqst(strlen(pFullPath), pFullPath);
+
+ char *pPath = m_TransferQueue.getRemPathAt(0);
+ m_TransferQueue.setFlagsAt(0, (flag0 | FT_ATTR_FLR_UPLOAD_CHECK));
+ m_queueFileListRqst.add(pPath, 0, 0, FT_FLR_DEST_UPLOAD);
+ writeFileListRqst(strlen(pPath), pPath, false);
+ return;
+ }
+ } else {
+ if (flag0 & FT_ATTR_COPY_DOWNLOAD) {
+ if (flag0 & FT_ATTR_FILE) {
+ downloadFile();
+ return;
+ }
+ if (flag0 & FT_ATTR_DIR) {
+ FolderManager fm;
+ char *pLocPath = m_TransferQueue.getFullLocPathAt(0);
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Local Folder. %s", pLocPath);
+
+ if (!fm.createDir(pLocPath)) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Local Folder Failed.");
+ m_bTransferSuccess = false;
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return;
+ } else {
+ if ((m_bFTDlgShown) && (strcmp(m_TransferQueue.getLocPathAt(0), m_pFTDialog->getLocalPath()) == 0))
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+
+ m_TransferQueue.setFlagsAt(0, (m_TransferQueue.getFlagsAt(0) | FT_ATTR_FLR_DOWNLOAD_ADD));
+ char *pRemPath = m_TransferQueue.getFullRemPathAt(0);
+ m_queueFileListRqst.add(pRemPath, 0, 0, FT_FLR_DEST_DOWNLOAD);
+ writeFileListRqst(strlen(pRemPath), pRemPath, 0);
+ return;
+ }
+ }
+ }
+ }
+ m_bTransferSuccess = false;
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("File Transfer Operation Failed. Unknown data in the transfer queue");
+ } // if (!isTransferEnable())
+}
+
+bool
+FileTransfer::uploadFile()
+{
+ if (m_TransferQueue.getFlagsAt(0) & FT_ATTR_FILE) {
+ if (m_fileReader.create(m_TransferQueue.getFullLocPathAt(0))) {
+
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Upload Started: %s to %s",
+ m_TransferQueue.getFullLocPathAt(0),
+ m_TransferQueue.getFullRemPathAt(0));
+ m_pFTDialog->m_pProgress->clearAndInitSingle(m_TransferQueue.getSizeAt(0), 0);
+ }
+
+ writeFileUploadRqst(strlen(m_TransferQueue.getFullRemPathAt(0)),
+ m_TransferQueue.getFullRemPathAt(0), 0);
+ uploadFilePortion();
+ }
+ }
+ return false;
+}
+
+bool
+FileTransfer::downloadFile()
+{
+ if (m_TransferQueue.getFlagsAt(0) & FT_ATTR_FILE) {
+ if (m_fileWriter.create(m_TransferQueue.getFullLocPathAt(0))) {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Started: %s to %s",
+ m_TransferQueue.getFullRemPathAt(0),
+ m_TransferQueue.getFullLocPathAt(0));
+ m_pFTDialog->m_pProgress->clearAndInitSingle(m_TransferQueue.getSizeAt(0), 0);
+ }
+ writeFileDownloadRqst(strlen(m_TransferQueue.getFullRemPathAt(0)),
+ m_TransferQueue.getFullRemPathAt(0), 0);
+ return true;
+ } else return false;
+ }
+ return false;
+}
+
+void
+FileTransfer::uploadFilePortion()
+{
+ if (checkCancelOperations()) {
+ char reason[] = "The user cancel transfer";
+ m_pWriter->writeFileUploadFailed(strlen(reason), reason);
+ }
+
+ if (m_fileReader.isCreated()) {
+ char buf[FT_MAX_SENDING_SIZE];
+ unsigned int bytesRead = 0;
+ if (m_fileReader.read((void *)buf, FT_MAX_SENDING_SIZE, &bytesRead)) {
+ if (bytesRead == 0) {
+ m_pWriter->writeFileUploadData(m_TransferQueue.getDataAt(0));
+ m_fileReader.close();
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ m_pFTDialog->setStatusText("Upload Completed");
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ } else {
+ if (m_bFTDlgShown) m_pFTDialog->m_pProgress->increase(bytesRead);
+ m_pWriter->writeFileUploadData(bytesRead, (char *)buf);
+ m_pFTDialog->postUploadFilePortionMsg();
+ }
+ } else {
+ m_fileReader.close();
+ m_bTransferSuccess = false;
+ char reason[] = "Error While Reading File";
+ m_pWriter->writeFileUploadFailed(strlen(reason), reason);
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ m_pFTDialog->setStatusText("Upload Failed");
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ }
+ }
+}
+
+void
+FileTransfer::createRemoteFolder(char *pPath, char *pName)
+{
+ char fullPath[FT_FILENAME_SIZE];
+ sprintf(fullPath, "%s\\%s", pPath, pName);
+ m_pFTDialog->setStatusText("Creating Remote Folder: %s", fullPath);
+ writeFileCreateDirRqst(strlen(fullPath), fullPath);
+ requestFileList(pPath, FT_FLR_DEST_MAIN, false);
+}
+
+void
+FileTransfer::renameRemote(char *pPath, char *pOldName, char *pNewName)
+{
+ char fullOldName[FT_FILENAME_SIZE];
+ char fullNewName[FT_FILENAME_SIZE];
+
+ sprintf(fullOldName, "%s\\%s", pPath, pOldName);
+ sprintf(fullNewName, "%s\\%s", pPath, pNewName);
+
+ writeFileRenameRqst(strlen(fullOldName), strlen(fullNewName),
+ fullOldName, fullNewName);
+ requestFileList(pPath, FT_FLR_DEST_MAIN, false);
+}
+
+bool
+FileTransfer::procFileListDataMsg()
+{
+ FileInfo fileInfo;
+ int res = m_pReader->readFileListData(&fileInfo);
+
+ bool bResult;
+ switch (m_queueFileListRqst.getFlagsAt(0))
+ {
+ case FT_FLR_DEST_MAIN:
+ if (!m_bFTDlgShown) break;
+
+ if (res < 0) {
+ m_pFTDialog->reqFolderUnavailable();
+ bResult = true;
+ } else {
+ bResult = procFLRMain(&fileInfo);
+ }
+ break;
+ case FT_FLR_DEST_BROWSE:
+ bResult = procFLRBrowse(&fileInfo);
+ break;
+ case FT_FLR_DEST_UPLOAD:
+ bResult = procFLRUpload(&fileInfo);
+ break;
+ case FT_FLR_DEST_DOWNLOAD:
+ bResult = procFLRDownload(&fileInfo);
+ break;
+ case FT_FLR_DEST_DELETE:
+ bResult = procFLRDelete(&fileInfo);
+ break;
+ case FT_FLR_DEST_RENAME:
+ bResult = procFLRRename(&fileInfo);
+ break;
+ }
+ m_queueFileListRqst.deleteAt(0);
+ return bResult;
+}
+
+bool
+FileTransfer::procFileDownloadDataMsg()
+{
+ unsigned int bufSize = 0;
+ unsigned int modTime = 0;
+
+ void *pFile = m_pReader->readFileDownloadData(&bufSize, &modTime);
+
+ if (checkCancelOperations()) {
+ char reason[] = "The user cancel transfer";
+ m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+ }
+
+ if ((!m_fileWriter.isCreated()) || (!isTransferEnable())) {
+ m_bTransferSuccess = false;
+ if (pFile != NULL) delete [] pFile;
+ return false;
+ }
+
+ if (bufSize > 0) {
+ unsigned int bytesWritten = 0;
+ m_fileWriter.write(pFile, bufSize, &bytesWritten);
+ delete [] pFile;
+ if (bytesWritten != bufSize) {
+ m_bTransferSuccess = false;
+ char reason[] = "Error File Writting to File";
+ m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Failed");
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return false;
+ } else {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->increase(bufSize);
+ }
+ }
+ return true;
+ } else {
+ if (modTime != 0) {
+ m_fileWriter.setTime(modTime);
+ m_fileWriter.close();
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Completed");
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return true;
+ } else {
+ m_fileWriter.close();
+ m_bTransferSuccess = false;
+ char reason[] = "Error File Writting";
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Failed");
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ }
+ m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ }
+ }
+ return false;
+}
+
+bool
+FileTransfer::procFileUploadCancelMsg()
+{
+ unsigned int reasonSize = 0;
+ char *pReason = m_pReader->readFileUploadCancel(&reasonSize);
+
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Upload Canceled by Remote Computer : %s", pReason);
+ }
+ endUndoneOperation();
+ m_pFTDialog->postCheckTransferQueueMsg();
+
+ delete [] pReason;
+ return true;
+}
+
+bool
+FileTransfer::procFileDownloadFailedMsg()
+{
+ unsigned int reasonSize = 0;
+ char *pReason = m_pReader->readFileDownloadFailed(&reasonSize);
+
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Failed by Remote Computer : %s", pReason);
+ }
+ endUndoneOperation();
+ m_pFTDialog->postCheckTransferQueueMsg();
+
+ delete [] pReason;
+ return true;
+}
+
+bool
+FileTransfer::procFileDirSizeDataMsg()
+{
+ DWORD64 dw64DirSize = 0;
+ unsigned short dirSizeLow16 = 0;
+ unsigned int dirSizeHigh32 = 0;
+ m_pReader->readFileDirSizeData(&dirSizeLow16, &dirSizeHigh32);
+
+ dw64DirSize = dirSizeLow16;
+ dw64DirSize = (dw64DirSize << 32) + dirSizeHigh32;
+
+ m_dw64SizeSending += dw64DirSize;
+ m_TransferQueue.clearFlagAt(m_dirSizeRqstNum, FT_ATTR_RESIZE_NEEDED);
+ checkTransferQueue();
+ return true;
+}
+
+bool
+FileTransfer::procFileLastRqstFailedMsg()
+{
+ unsigned int reasonSize = 0;
+ int requestType;
+ char *pReason = m_pReader->readFileLastRqstFailed(&requestType, &reasonSize);
+ delete [] pReason;
+ return true;
+}
+
+bool
+FileTransfer::procFLRMain(FileInfo *pFI)
+{
+ if (m_bFTDlgShown) m_pFTDialog->addRemoteLVItems(pFI);
+ return true;
+}
+
+bool
+FileTransfer::procFLRBrowse(FileInfo *pFI)
+{
+ m_pFTDialog->addBrowseItems(pFI);
+ return false;
+}
+
+bool
+FileTransfer::procFLRUpload(FileInfo *pFI)
+{
+ unsigned int flags = m_TransferQueue.getFlagsAt(0);
+ if (flags & FT_ATTR_FLR_UPLOAD_CHECK) {
+ int num = isExistName(pFI, m_TransferQueue.getRemNameAt(0));
+ if (num >= 0) {
+ if ((m_bFTDlgShown) && (strcmp(m_TransferQueue.getRemPathAt(0), m_pFTDialog->getRemotePath()) == 0)) {
+ m_pFTDialog->addRemoteLVItems(pFI);
+ }
+ } else {
+ if (flags & FT_ATTR_DIR) {
+ m_TransferQueue.deleteAt(0);
+ m_bTransferSuccess = false;
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Create Remote Folder Failed.");
+ }
+ }
+ }
+ FolderManager fm;
+ FileInfo fi;
+ flags = m_TransferQueue.getFlagsAt(0);
+ if (flags & FT_ATTR_FILE) {
+ uploadFile();
+ return true;
+ } else {
+ if (fm.getDirInfo(m_TransferQueue.getFullLocPathAt(0), &fi, 0)) {
+ m_TransferQueue.add(m_TransferQueue.getFullLocPathAt(0),
+ m_TransferQueue.getFullRemPathAt(0),
+ &fi, FT_ATTR_COPY_UPLOAD);
+ }
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return true;
+}
+
+bool
+FileTransfer::procFLRDownload(FileInfo *pFI)
+{
+ unsigned int flags = m_TransferQueue.getFlagsAt(0);
+
+ if ((flags & FT_ATTR_DIR) && (flags & FT_ATTR_FLR_DOWNLOAD_ADD)) {
+ m_TransferQueue.add(m_TransferQueue.getFullLocPathAt(0),
+ m_TransferQueue.getFullRemPathAt(0),
+ pFI, FT_ATTR_COPY_DOWNLOAD);
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return true;
+ } else {
+ m_bTransferSuccess = false;
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("File Transfer Operation Failed: Unknown data from server.");
+ }
+ return false;
+}
+
+bool
+FileTransfer::procFLRDelete(FileInfo *pFI)
+{
+ if (isExistName(pFI, m_DeleteQueue.getLocNameAt(0)) >= 0) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Failed.");
+ } else {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Completed.");
+ }
+ m_DeleteQueue.deleteAt(0);
+ checkDeleteQueue();
+ return true;
+}
+
+bool
+FileTransfer::procFLRRename(FileInfo *pFI)
+{
+ return false;
+}
+
+void
+FileTransfer::requestFileList(char *pPath, int dest, bool bDirOnly)
+{
+ m_queueFileListRqst.add(pPath, 0, 0, dest);
+
+ writeFileListRqst(strlen(pPath), pPath, bDirOnly);
+}
+
+int
+FileTransfer::isExistName(FileInfo *pFI, char *pName)
+{
+ for (unsigned int i = 0; i < pFI->getNumEntries(); i++) {
+ if (strcmp(pFI->getNameAt(i), pName) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool
+FileTransfer::checkCancelOperations()
+{
+ if (m_bFTDlgShown) m_pFTDialog->processDlgMsgs();
+ if (m_bCancel) {
+ endUndoneOperation();
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("All Operations Canceled");
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void
+FileTransfer::endUndoneOperation()
+{
+ m_bCancel = false;
+ m_bTransferSuccess = false;
+ m_fileReader.close();
+ m_fileWriter.close();
+ freeQueues();
+ m_dw64SizeSending = 0;
+ m_pFTDialog->m_pProgress->clearAll();
+}
+
+void
+FileTransfer::freeQueues()
+{
+ m_TransferQueue.free();
+ m_DeleteQueue.free();
+ m_queueFileListRqst.free();
+}
+
+int
+FileTransfer::convertToUnixPath(char *path)
+{
+ int len = strlen(path);
+ if (len >= FT_FILENAME_SIZE) return -1;
+ if (len == 0) {strcpy(path, "/"); return 1;}
+ for (int i = (len - 1); i >= 0; i--) {
+ if (path[i] == '\\') path[i] = '/';
+ path[i+1] = path[i];
+ }
+ path[len + 1] = '\0';
+ path[0] = '/';
+ return strlen(path);
+}
+
+bool
+FileTransfer::writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly)
+{
+ char dirName[FT_FILENAME_SIZE];
+ strcpy(dirName, pDirName);
+ int len = convertToUnixPath(dirName);
+ if (len <= 0) return false;
+
+ return m_pWriter->writeFileListRqst(len, dirName, bDirOnly);
+}
+
+bool
+FileTransfer::writeFileDownloadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position)
+{
+ char filename[FT_FILENAME_SIZE];
+ strcpy(filename, pFilename);
+ unsigned short len = (unsigned short) convertToUnixPath(filename);
+ if (len <= 0) return false;
+
+ return m_pWriter->writeFileDownloadRqst(len, filename, position);
+}
+
+bool
+FileTransfer::writeFileUploadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position)
+{
+ char filename[FT_FILENAME_SIZE];
+ strcpy(filename, pFilename);
+ unsigned short len = (unsigned short) convertToUnixPath(filename);
+ if (len <= 0) return false;
+
+ return m_pWriter->writeFileUploadRqst(len, filename, position);
+}
+
+bool
+FileTransfer::writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName)
+{
+ char path[FT_FILENAME_SIZE];
+ strcpy(path, pDirName);
+ int nameLen = convertToUnixPath(path);
+
+ return m_pWriter->writeFileCreateDirRqst(nameLen, path);
+}
+
+bool
+FileTransfer::writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName)
+{
+ char path[FT_FILENAME_SIZE];
+ strcpy(path, pDirName);
+ int nameLen = convertToUnixPath(path);
+
+ return m_pWriter->writeFileDirSizeRqst(nameLen, path);
+}
+
+bool
+FileTransfer::writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+ char *pOldName, char *pNewName)
+{
+ char oldName[FT_FILENAME_SIZE];
+ char newName[FT_FILENAME_SIZE];
+
+ strcpy(oldName, pOldName);
+ strcpy(newName, pNewName);
+
+ int _oldNameLen = convertToUnixPath(oldName);
+ int _newNameLen = convertToUnixPath(newName);
+
+ return m_pWriter->writeFileRenameRqst(_oldNameLen, _newNameLen, oldName, newName);
+}
+
+bool
+FileTransfer::writeFileDeleteRqst(unsigned short nameLen, char *pName)
+{
+ char path[FT_FILENAME_SIZE];
+ strcpy(path, pName);
+ int _nameLen = convertToUnixPath(path);
+
+ return m_pWriter->writeFileDeleteRqst(_nameLen, path);
+}
diff --git a/win/vncviewer/FileTransfer.h b/win/vncviewer/FileTransfer.h
new file mode 100644
index 00000000..1bfded2c
--- /dev/null
+++ b/win/vncviewer/FileTransfer.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileTransfer.h
+
+#ifndef __RFB_WIN32_FILETRANSFER_H__
+#define __RFB_WIN32_FILETRANSFER_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/FileInfo.h>
+#include <rfb/FileReader.h>
+#include <rfb/FileWriter.h>
+#include <rfb/TransferQueue.h>
+#include <rfb/CFTMsgReader.h>
+#include <rfb/CFTMsgWriter.h>
+#include <vncviewer/FTDialog.h>
+
+namespace rfb {
+ namespace win32 {
+ class FTDialog;
+
+ class FileTransfer
+ {
+ public:
+ FileTransfer();
+ ~FileTransfer();
+
+ bool initialize(rdr::InStream *pIS, rdr::OutStream *pOS);
+ bool processFTMsg(int type);
+ bool show(HWND hwndParent);
+
+ void requestFileList(char *pPath, int dest, bool bDirOnly);
+
+ void addTransferQueue(char *pLocalPath, char *pRemotePath,
+ FileInfo *pFI, unsigned int flags);
+ void addDeleteQueue(char *pPathPrefix, FileInfo *pFI,
+ unsigned int flags);
+
+ bool isTransferEnable();
+
+ void checkTransferQueue();
+ void checkDeleteQueue();
+ bool checkCancelOperations();
+
+ void uploadFilePortion();
+
+ void createRemoteFolder(char *pPath, char *pName);
+ void renameRemote(char *pPath, char *pOldName, char *pNewName);
+
+ bool m_bCancel;
+
+ private:
+ bool m_bFTDlgShown;
+ bool m_bInitialized;
+ bool m_bResized;
+ bool m_bTransferSuccess;
+ bool m_bOverwriteAll;
+
+ FTDialog *m_pFTDialog;
+
+ rfb::CFTMsgReader *m_pReader;
+ rfb::CFTMsgWriter *m_pWriter;
+
+ FileReader m_fileReader;
+ FileWriter m_fileWriter;
+
+ FileInfo m_queueFileListRqst;
+
+ TransferQueue m_TransferQueue;
+ TransferQueue m_DeleteQueue;
+
+ bool resizeSending();
+ bool uploadFile();
+ bool downloadFile();
+
+ int isExistName(FileInfo *pFI, char *pName);
+ void freeQueues();
+
+ void endUndoneOperation();
+
+ bool procFileListDataMsg();
+ bool procFileDownloadDataMsg();
+ bool procFileUploadCancelMsg();
+ bool procFileDownloadFailedMsg();
+ bool procFileDirSizeDataMsg();
+ bool procFileLastRqstFailedMsg();
+
+ bool procFLRMain(FileInfo *pFI);
+ bool procFLRBrowse(FileInfo *pFI);
+ bool procFLRUpload(FileInfo *pFI);
+ bool procFLRDownload(FileInfo *pFI);
+ bool procFLRDelete(FileInfo *pFI);
+ bool procFLRRename(FileInfo *pFI);
+
+ int convertToUnixPath(char *path);
+
+ bool writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly);
+ bool writeFileDownloadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position);
+ bool writeFileUploadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position);
+ bool writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName);
+ bool writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName);
+ bool writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+ char *pOldName, char *pNewName);
+ bool writeFileDeleteRqst(unsigned short nameLen, char *pName);
+
+ DWORD64 m_dw64SizeSending;
+ unsigned int m_dirSizeRqstNum;
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FILETRANSFER_H__
diff --git a/win/vncviewer/InfoDialog.cxx b/win/vncviewer/InfoDialog.cxx
new file mode 100644
index 00000000..e74896dc
--- /dev/null
+++ b/win/vncviewer/InfoDialog.cxx
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/resource.h>
+#include <vncviewer/CConn.h>
+#include <rfb/secTypes.h>
+#include <rfb/encodings.h>
+#include <rfb/CSecurity.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Info");
+
+
+bool InfoDialog::showDialog(CConn* cc) {
+ conn = cc;
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_INFO));
+}
+
+void InfoDialog::initDialog() {
+ char buf[256];
+
+ setItemString(IDC_INFO_NAME, TStr(conn->cp.name()));
+
+ setItemString(IDC_INFO_HOST, TCharArray(conn->getSocket()->getPeerAddress()).buf);
+
+ sprintf(buf, "%dx%d", conn->cp.width, conn->cp.height);
+ setItemString(IDC_INFO_SIZE, TStr(buf));
+
+ conn->cp.pf().print(buf, 256);
+ setItemString(IDC_INFO_PF, TStr(buf));
+
+ conn->getServerDefaultPF().print(buf, 256);
+ setItemString(IDC_INFO_DEF_PF, TStr(buf));
+
+ setItemString(IDC_REQUESTED_ENCODING, TStr(encodingName(conn->getOptions().preferredEncoding)));
+ setItemString(IDC_LAST_ENCODING, TStr(encodingName(conn->lastUsedEncoding())));
+
+ sprintf(buf, "%d kbits/s", conn->getSocket()->inStream().kbitsPerSecond());
+ setItemString(IDC_INFO_LINESPEED, TStr(buf));
+
+ sprintf(buf, "%d.%d", conn->cp.majorVersion, conn->cp.minorVersion);
+ setItemString(IDC_INFO_VERSION, TStr(buf));
+
+ const CSecurity* cSec = conn->getCurrentCSecurity();
+ setItemString(IDC_INFO_SECURITY, TStr(secTypeName(cSec->getType())));
+ setItemString(IDC_INFO_ENCRYPTION, TStr(cSec->description()));
+}
diff --git a/win/vncviewer/InfoDialog.h b/win/vncviewer/InfoDialog.h
new file mode 100644
index 00000000..752d53c5
--- /dev/null
+++ b/win/vncviewer/InfoDialog.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- InfoDialog.h
+
+// Info dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_INFO_DIALOG_H__
+#define __RFB_WIN32_INFO_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConn;
+
+ class InfoDialog : Dialog {
+ public:
+ InfoDialog() : Dialog(GetModuleHandle(0)), conn(0) {}
+ virtual bool showDialog(CConn* vw);
+ virtual void initDialog();
+ protected:
+ CConn* conn;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/ListenServer.h b/win/vncviewer/ListenServer.h
new file mode 100644
index 00000000..4d1590c0
--- /dev/null
+++ b/win/vncviewer/ListenServer.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ListenServer.h
+
+#ifndef __RFB_WIN32_LISTEN_SERVER_H__
+#define __RFB_WIN32_LISTEN_SERVER_H__
+
+#include <windows.h>
+#include <winsock2.h>
+#include <network/Socket.h>
+#include <rfb_win32/MsgWindow.h>
+#include <vncviewer/CConnThread.h>
+
+
+namespace rfb {
+ namespace win32 {
+
+ class ListenServer : MsgWindow {
+ public:
+ ListenServer(network::SocketListener* l) : MsgWindow(_T("rfb::win32::ListenServer")), sock(l) {
+ if (WSAAsyncSelect(l->getFd(), getHandle(), WM_USER, FD_ACCEPT) == SOCKET_ERROR)
+ throw rdr::SystemException("unable to monitor listen socket", WSAGetLastError());
+ }
+
+ LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ if (msg == WM_USER) {
+ network::Socket* newConn = sock->accept();
+ Thread* newThread = new CConnThread(newConn, true);
+ return 0;
+ }
+ return MsgWindow::processMessage(msg, wParam, lParam);
+ }
+ protected:
+ network::SocketListener* sock;
+ };
+
+ };
+};
+
+#endif \ No newline at end of file
diff --git a/win/vncviewer/ListenTrayIcon.h b/win/vncviewer/ListenTrayIcon.h
new file mode 100644
index 00000000..7e334d91
--- /dev/null
+++ b/win/vncviewer/ListenTrayIcon.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ListenTrayIcon.h
+
+#ifndef __RFB_WIN32_LISTEN_TRAY_ICON_H__
+#define __RFB_WIN32_LISTEN_TRAY_ICON_H__
+
+#include <rfb_win32/TrayIcon.h>
+#include <rfb_win32/AboutDialog.h>
+
+namespace rfb {
+ namespace win32 {
+
+ class ListenTrayIcon : public TrayIcon {
+ public:
+ ListenTrayIcon() {
+ setIcon(IDI_ICON);
+ setToolTip(_T("VNC Viewer"));
+ }
+ virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch(msg) {
+
+ case WM_USER:
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
+ break;
+ case WM_RBUTTONUP:
+ HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
+ HMENU trayMenu = GetSubMenu(menu, 0);
+
+ // First item is New Connection, the default
+ SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
+
+ // SetForegroundWindow is required, otherwise Windows ignores the
+ // TrackPopupMenu because the window isn't the foreground one, on
+ // some older Windows versions...
+ SetForegroundWindow(getHandle());
+
+ // Display the menu
+ POINT pos;
+ GetCursorPos(&pos);
+ TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
+ break;
+ }
+ return 0;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case ID_NEW_CONNECTION:
+ {
+ Thread* connThread = new CConnThread();
+ break;
+ }
+ case ID_OPTIONS:
+ OptionsDialog::global.showDialog(0);
+ break;
+ case ID_ABOUT:
+ AboutDialog::instance.showDialog();
+ break;
+ case ID_CLOSE:
+ SendMessage(getHandle(), WM_CLOSE, 0, 0);
+ break;
+ }
+ return 0;
+
+ case WM_CLOSE:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return TrayIcon::processMessage(msg, wParam, lParam);
+ }
+ };
+
+ };
+};
+
+#endif // __RFB_WIN32_LISTEN_TRAY_ICON_H__ \ No newline at end of file
diff --git a/win/vncviewer/MRU.h b/win/vncviewer/MRU.h
new file mode 100644
index 00000000..ae703b3a
--- /dev/null
+++ b/win/vncviewer/MRU.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __VIEWER_MRU_H__
+#define __VIEWER_MRU_H__
+
+#include <windows.h>
+#include <list>
+#include <set>
+#include <rfb_win32/Registry.h>
+#include <rfb/util.h>
+#include <rdr/HexOutStream.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ namespace MRU {
+
+ static const RegKey RegRoot = HKEY_CURRENT_USER;
+ static const TCHAR* RegPath = _T("Software\\TightVNC\\VNCViewer4\\MRU");
+ static const int MaxMRUEntries = 256;
+ static const int MRUEntries = 10;
+
+ static std::list<char*> getEntries() {
+ std::list<char*> mru;
+
+ try {
+ RegKey key;
+ key.openKey(RegRoot, RegPath);
+
+ CharArray order;
+ int length;
+ key.getBinary(_T("Order"), (void**)&order.buf, &length);
+
+ for (int i=0; i<length; i++) {
+ TCharArray keyname = rdr::HexOutStream::binToHexStr(&order.buf[i], 1);
+ try {
+ TCharArray entry = key.getString(keyname.buf);
+ mru.push_back(strDup(entry.buf));
+ } catch (rdr::Exception) {
+ }
+ }
+ } catch (rdr::Exception) {
+ }
+
+ return mru;
+ }
+
+ static void addToMRU(const char* name) {
+ RegKey key;
+ key.createKey(RegRoot, RegPath);
+
+ BYTE keycode;
+ CharArray old_order;
+ char order[MaxMRUEntries];
+ int orderlen;
+
+ try {
+ key.getBinary(_T("Order"), (void**)&old_order.buf, &orderlen);
+ if (orderlen)
+ memcpy(order, old_order.buf, orderlen);
+
+ std::set<int> ordercodes;
+ keycode = 0;
+ bool found = false;
+ for (int i=0; i<orderlen; i++) {
+ TCharArray keyname = rdr::HexOutStream::binToHexStr(&order[i], 1);
+ try {
+ TCharArray hostname = key.getString(keyname.buf);
+ if (stricmp(name, CStr(hostname.buf)) == 0) {
+ keycode = order[i];
+ found = true;
+ break;
+ }
+ } catch (rdr::Exception) {
+ }
+ ordercodes.insert(order[i]);
+ }
+
+ if (!found) {
+ if (orderlen <= MRUEntries) {
+ while (ordercodes.find(keycode) != ordercodes.end()) keycode++;
+ } else {
+ keycode = order[orderlen-1];
+ orderlen--;
+ }
+ }
+
+ } catch (rdr::Exception) {
+ keycode = 0;
+ orderlen = 0;
+ }
+
+ orderlen++;
+ int i, j=orderlen-1;
+ for (i=0; i<orderlen-1; i++) {
+ if (order[i] == keycode) {
+ j = i;
+ orderlen--;
+ break;
+ }
+ }
+ for (i=j; i>0; i--)
+ order[i] = order[i-1];
+ order[0] = keycode;
+
+ TCharArray keyname = rdr::HexOutStream::binToHexStr((char*)&keycode, 1);
+ key.setString(keyname.buf, TStr(name));
+ key.setBinary(_T("Order"), order, orderlen);
+ }
+
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/OptionsDialog.cxx b/win/vncviewer/OptionsDialog.cxx
new file mode 100644
index 00000000..2e43b38f
--- /dev/null
+++ b/win/vncviewer/OptionsDialog.cxx
@@ -0,0 +1,337 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb/encodings.h>
+#include <rfb/CConnection.h>
+#include <commdlg.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Options");
+
+
+struct OptionsInfo {
+ CConn* view;
+ CConnOptions options;
+};
+
+
+OptionsDialog rfb::win32::OptionsDialog::global;
+
+
+class ViewerOptions : public PropSheet {
+public:
+ ViewerOptions(OptionsInfo& info_, std::list<PropSheetPage*> pages)
+ : PropSheet(GetModuleHandle(0),
+ info_.view ? _T("VNC Viewer Options") : _T("VNC Viewer Defaults"), pages),
+ info(info_), changed(false) {
+ }
+ ~ViewerOptions() {
+ if (changed) {
+ if (info.view)
+ // Apply the settings to the supplied session object
+ info.view->applyOptions(info.options);
+ else {
+ // Commit the settings to the user's registry area
+ info.options.writeDefaults();
+ }
+ }
+ }
+
+ void setChanged() {changed = true;}
+
+ bool changed;
+ OptionsInfo& info;
+};
+
+
+class FormatPage : public PropSheetPage {
+public:
+ FormatPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FORMAT)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ setItemChecked(IDC_ENCODING_AUTO, dlg->options.autoSelect);
+ setItemChecked(IDC_FORMAT_FULLCOLOUR, dlg->options.fullColour);
+ if (!dlg->options.fullColour) {
+ switch (dlg->options.lowColourLevel) {
+ case 0: setItemChecked(IDC_FORMAT_VERYLOWCOLOUR, true); break;
+ case 1: setItemChecked(IDC_FORMAT_LOWCOLOUR, true); break;
+ case 2: setItemChecked(IDC_FORMAT_MEDIUMCOLOUR, true); break;
+ }
+ }
+ switch (dlg->options.preferredEncoding) {
+ case encodingTight: setItemChecked(IDC_ENCODING_TIGHT, true); break;
+ case encodingZRLE: setItemChecked(IDC_ENCODING_ZRLE, true); break;
+ case encodingHextile: setItemChecked(IDC_ENCODING_HEXTILE, true); break;
+ case encodingRaw: setItemChecked(IDC_ENCODING_RAW, true); break;
+ }
+ setItemChecked(IDC_CUSTOM_COMPRESSLEVEL, dlg->options.customCompressLevel);
+ setItemInt(IDC_COMPRESSLEVEL, dlg->options.compressLevel);
+ setItemChecked(IDC_ALLOW_JPEG, !dlg->options.noJpeg);
+ setItemInt(IDC_QUALITYLEVEL, dlg->options.qualityLevel);
+ onCommand(IDC_ENCODING_AUTO, 0 /* ? */); // Force enableItem status to refresh
+ onCommand(IDC_CUSTOM_COMPRESSLEVEL, 0 /* ? */); // Force enableItem status to refresh
+ onCommand(IDC_ALLOW_JPEG, 0 /* ? */); // Force enableItem status to refresh
+ }
+ virtual bool onOk() {
+ dlg->options.autoSelect = isItemChecked(IDC_ENCODING_AUTO);
+ dlg->options.fullColour = isItemChecked(IDC_FORMAT_FULLCOLOUR);
+ dlg->options.customCompressLevel = isItemChecked(IDC_CUSTOM_COMPRESSLEVEL);
+ dlg->options.compressLevel = getItemInt(IDC_COMPRESSLEVEL);
+ dlg->options.noJpeg = !isItemChecked(IDC_ALLOW_JPEG);
+ dlg->options.qualityLevel = getItemInt(IDC_QUALITYLEVEL);
+ if (isItemChecked(IDC_FORMAT_VERYLOWCOLOUR))
+ dlg->options.lowColourLevel = 0;
+ if (isItemChecked(IDC_FORMAT_LOWCOLOUR))
+ dlg->options.lowColourLevel = 1;
+ if (isItemChecked(IDC_FORMAT_MEDIUMCOLOUR))
+ dlg->options.lowColourLevel = 2;
+ dlg->options.preferredEncoding = encodingTight;
+ if (isItemChecked(IDC_ENCODING_ZRLE))
+ dlg->options.preferredEncoding = encodingZRLE;
+ if (isItemChecked(IDC_ENCODING_HEXTILE))
+ dlg->options.preferredEncoding = encodingHextile;
+ if (isItemChecked(IDC_ENCODING_RAW))
+ dlg->options.preferredEncoding = encodingRaw;
+ ((ViewerOptions*)propSheet)->setChanged();
+ return true;
+ }
+ virtual bool onCommand(int id, int cmd) {
+ if (id == IDC_ENCODING_AUTO) {
+ bool ok = !isItemChecked(IDC_ENCODING_AUTO);
+ enableItem(IDC_ENCODING_TIGHT, ok);
+ enableItem(IDC_ENCODING_ZRLE, ok);
+ enableItem(IDC_ENCODING_HEXTILE, ok);
+ enableItem(IDC_ENCODING_RAW, ok);
+ enableItem(IDC_FORMAT_FULLCOLOUR, ok);
+ enableItem(IDC_FORMAT_MEDIUMCOLOUR, ok);
+ enableItem(IDC_FORMAT_LOWCOLOUR, ok);
+ enableItem(IDC_FORMAT_VERYLOWCOLOUR, ok);
+ return true;
+ }
+ if (id == IDC_CUSTOM_COMPRESSLEVEL) {
+ enableItem(IDC_COMPRESSLEVEL, isItemChecked(IDC_CUSTOM_COMPRESSLEVEL));
+ return true;
+ }
+ if (id == IDC_ALLOW_JPEG) {
+ enableItem(IDC_QUALITYLEVEL, isItemChecked(IDC_ALLOW_JPEG));
+ return true;
+ }
+ return false;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+class MiscPage : public PropSheetPage {
+public:
+ MiscPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MISC)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ setItemChecked(IDC_CONN_SHARED, dlg->options.shared);
+ enableItem(IDC_CONN_SHARED, (!dlg->view) || (dlg->view->state() != CConnection::RFBSTATE_NORMAL));
+ setItemChecked(IDC_FULL_SCREEN, dlg->options.fullScreen);
+ setItemChecked(IDC_LOCAL_CURSOR, dlg->options.useLocalCursor);
+ setItemChecked(IDC_DESKTOP_RESIZE, dlg->options.useDesktopResize);
+ enableItem(IDC_PROTOCOL_3_3, (!dlg->view) || (dlg->view->state() != CConnection::RFBSTATE_NORMAL));
+ setItemChecked(IDC_PROTOCOL_3_3, dlg->options.protocol3_3);
+ setItemChecked(IDC_ACCEPT_BELL, dlg->options.acceptBell);
+ setItemChecked(IDC_AUTO_RECONNECT, dlg->options.autoReconnect);
+ setItemChecked(IDC_SHOW_TOOLBAR, dlg->options.showToolbar);
+ }
+ virtual bool onOk() {
+ dlg->options.shared = isItemChecked(IDC_CONN_SHARED);
+ dlg->options.fullScreen = isItemChecked(IDC_FULL_SCREEN);
+ dlg->options.useLocalCursor = isItemChecked(IDC_LOCAL_CURSOR);
+ dlg->options.useDesktopResize = isItemChecked(IDC_DESKTOP_RESIZE);
+ dlg->options.protocol3_3 = isItemChecked(IDC_PROTOCOL_3_3);
+ dlg->options.acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+ dlg->options.autoReconnect = isItemChecked(IDC_AUTO_RECONNECT);
+ dlg->options.showToolbar = isItemChecked(IDC_SHOW_TOOLBAR);
+ ((ViewerOptions*)propSheet)->setChanged();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+class InputsPage : public PropSheetPage {
+public:
+ InputsPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_INPUTS)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ setItemChecked(IDC_SEND_POINTER, dlg->options.sendPtrEvents);
+ setItemChecked(IDC_SEND_KEYS, dlg->options.sendKeyEvents);
+ setItemChecked(IDC_CLIENT_CUTTEXT, dlg->options.clientCutText);
+ setItemChecked(IDC_SERVER_CUTTEXT, dlg->options.serverCutText);
+ setItemChecked(IDC_DISABLE_WINKEYS, dlg->options.disableWinKeys && !osVersion.isPlatformWindows);
+ enableItem(IDC_DISABLE_WINKEYS, !osVersion.isPlatformWindows);
+ setItemChecked(IDC_EMULATE3, dlg->options.emulate3);
+ setItemChecked(IDC_POINTER_INTERVAL, dlg->options.pointerEventInterval != 0);
+
+ // Populate the Menu Key tab
+ HWND menuKey = GetDlgItem(handle, IDC_MENU_KEY);
+ SendMessage(menuKey, CB_RESETCONTENT, 0, 0);
+ SendMessage(menuKey, CB_ADDSTRING, 0, (LPARAM)_T("none"));
+ if (!dlg->options.menuKey)
+ SendMessage(menuKey, CB_SETCURSEL, 0, 0);
+ for (int i=0; i<12; i++) {
+ TCHAR buf[4];
+ _stprintf(buf, _T("F%d"), i+1);
+ int index = SendMessage(menuKey, CB_ADDSTRING, 0, (LPARAM)buf);
+ if (i == (dlg->options.menuKey - VK_F1))
+ SendMessage(menuKey, CB_SETCURSEL, index, 0);
+ }
+ }
+ virtual bool onOk() {
+ dlg->options.sendPtrEvents = isItemChecked(IDC_SEND_POINTER);
+ dlg->options.sendKeyEvents = isItemChecked(IDC_SEND_KEYS);
+ dlg->options.clientCutText = isItemChecked(IDC_CLIENT_CUTTEXT);
+ dlg->options.serverCutText = isItemChecked(IDC_SERVER_CUTTEXT);
+ dlg->options.disableWinKeys = isItemChecked(IDC_DISABLE_WINKEYS);
+ dlg->options.emulate3 = isItemChecked(IDC_EMULATE3);
+ dlg->options.pointerEventInterval =
+ isItemChecked(IDC_POINTER_INTERVAL) ? 200 : 0;
+
+ HWND mkHwnd = GetDlgItem(handle, IDC_MENU_KEY);
+ int index = SendMessage(mkHwnd, CB_GETCURSEL, 0, 0);
+ TCharArray keyName(SendMessage(mkHwnd, CB_GETLBTEXTLEN, index, 0)+1);
+ SendMessage(mkHwnd, CB_GETLBTEXT, index, (LPARAM)keyName.buf);
+ if (_tcscmp(keyName.buf, _T("none")) == 0)
+ dlg->options.setMenuKey("");
+ else
+ dlg->options.setMenuKey(CStr(keyName.buf));
+
+ ((ViewerOptions*)propSheet)->setChanged();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+class DefaultsPage : public PropSheetPage {
+public:
+ DefaultsPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DEFAULTS)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ enableItem(IDC_LOAD_CONFIG, dlg->options.configFileName.buf);
+ enableItem(IDC_SAVE_CONFIG, dlg->options.configFileName.buf);
+ }
+ virtual bool onCommand(int id, int cmd) {
+ switch (id) {
+ case IDC_LOAD_DEFAULTS:
+ dlg->options = CConnOptions();
+ break;
+ case IDC_SAVE_DEFAULTS:
+ propSheet->commitPages();
+ dlg->options.writeDefaults();
+ break;
+ case IDC_LOAD_CONFIG:
+ dlg->options.readFromFile(dlg->options.configFileName.buf);
+ break;
+ case IDC_SAVE_CONFIG:
+ propSheet->commitPages();
+ dlg->options.writeToFile(dlg->options.configFileName.buf);
+ MsgBox(handle, _T("Options saved successfully"),
+ MB_OK | MB_ICONINFORMATION);
+ return 0;
+ case IDC_SAVE_CONFIG_AS:
+ propSheet->commitPages();
+ // Get a filename to save to
+ TCHAR newFilename[4096];
+ TCHAR currentDir[4096];
+ if (dlg->options.configFileName.buf)
+ _tcscpy(newFilename, TStr(dlg->options.configFileName.buf));
+ else
+ newFilename[0] = 0;
+ OPENFILENAME ofn;
+ memset(&ofn, 0, sizeof(ofn));
+#ifdef OPENFILENAME_SIZE_VERSION_400
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+#else
+ ofn.lStructSize = sizeof(ofn);
+#endif
+ ofn.hwndOwner = handle;
+ ofn.lpstrFilter = _T("VNC Connection Options\000*.vnc\000");
+ ofn.lpstrFile = newFilename;
+ currentDir[0] = 0;
+ GetCurrentDirectory(4096, currentDir);
+ ofn.lpstrInitialDir = currentDir;
+ ofn.nMaxFile = 4096;
+ ofn.lpstrDefExt = _T(".vnc");
+ ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
+ if (!GetSaveFileName(&ofn)) {
+ if (CommDlgExtendedError())
+ throw rdr::Exception("GetSaveFileName failed");
+ return 0;
+ }
+
+ // Save the Options
+ dlg->options.writeToFile(CStr(newFilename));
+ MsgBox(handle, _T("Options saved successfully"),
+ MB_OK | MB_ICONINFORMATION);
+ return 0;
+ };
+ propSheet->reInitPages();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+
+OptionsDialog::OptionsDialog() : visible(false) {
+}
+
+bool OptionsDialog::showDialog(CConn* view, bool capture) {
+ if (visible) return false;
+ visible = true;
+
+ // Grab the current properties
+ OptionsInfo info;
+ if (view)
+ info.options = view->getOptions();
+ info.view = view;
+
+ // Build a list of pages to display
+ std::list<PropSheetPage*> pages;
+ FormatPage formatPage(&info); pages.push_back(&formatPage);
+ InputsPage inputsPage(&info); pages.push_back(&inputsPage);
+ MiscPage miscPage(&info); pages.push_back(&miscPage);
+ DefaultsPage defPage(&info); if (view) pages.push_back(&defPage);
+
+ // Show the property sheet
+ ViewerOptions dialog(info, pages);
+ dialog.showPropSheet(view && view->getWindow() ? view->getWindow()->getHandle() : 0,
+ false, false, capture);
+
+ visible = false;
+ return dialog.changed;
+}
diff --git a/win/vncviewer/OptionsDialog.h b/win/vncviewer/OptionsDialog.h
new file mode 100644
index 00000000..fcddc71c
--- /dev/null
+++ b/win/vncviewer/OptionsDialog.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- OptionsDialog.h
+
+// Options dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_OPTIONS_DIALOG_H__
+#define __RFB_WIN32_OPTIONS_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConn;
+
+ class OptionsDialog {
+ public:
+ OptionsDialog();
+ virtual bool showDialog(CConn* cfg, bool capture=false);
+
+ static OptionsDialog global;
+ protected:
+ bool visible;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/UserPasswdDialog.cxx b/win/vncviewer/UserPasswdDialog.cxx
new file mode 100644
index 00000000..2eea0ea0
--- /dev/null
+++ b/win/vncviewer/UserPasswdDialog.cxx
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/resource.h>
+#include <rfb/Exception.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+UserPasswdDialog::UserPasswdDialog() : Dialog(GetModuleHandle(0)),
+ showUsername(false), showPassword(false) {
+}
+
+
+void UserPasswdDialog::setCSecurity(const CSecurity* cs) {
+ description.replaceBuf(tstrDup(cs->description()));
+}
+
+bool UserPasswdDialog::showDialog() {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_VNC_AUTH_DLG));
+}
+
+void UserPasswdDialog::initDialog() {
+ if (username.buf)
+ setItemString(IDC_USERNAME, username.buf);
+ if (password.buf)
+ setItemString(IDC_PASSWORD, password.buf);
+ if (!showUsername) {
+ setItemString(IDC_USERNAME, _T(""));
+ enableItem(IDC_USERNAME, false);
+ }
+ if (!showPassword) {
+ setItemString(IDC_PASSWORD, _T(""));
+ enableItem(IDC_PASSWORD, false);
+ }
+ if (description.buf) {
+ TCharArray title(128);
+ GetWindowText(handle, title.buf, 128);
+ _tcsncat(title.buf, _T(" ["), 128);
+ _tcsncat(title.buf, description.buf, 128);
+ _tcsncat(title.buf, _T("]"), 128);
+ SetWindowText(handle, title.buf);
+ }
+}
+
+bool UserPasswdDialog::onOk() {
+ username.replaceBuf(getItemString(IDC_USERNAME));
+ password.replaceBuf(getItemString(IDC_PASSWORD));
+ return true;
+}
+
+
+void UserPasswdDialog::getUserPasswd(char** user, char** passwd) {
+ showUsername = user != 0;
+ showPassword = passwd != 0;
+ if (user && *user)
+ username.replaceBuf(tstrDup(*user));
+ if (passwd && *passwd)
+ password.replaceBuf(tstrDup(*passwd));
+
+ if (!showDialog())
+ throw rfb::AuthCancelledException();
+
+ if (user)
+ *user = strDup(username.buf);
+ if (passwd)
+ *passwd = strDup(password.buf);
+}
diff --git a/win/vncviewer/UserPasswdDialog.h b/win/vncviewer/UserPasswdDialog.h
new file mode 100644
index 00000000..bf006f4d
--- /dev/null
+++ b/win/vncviewer/UserPasswdDialog.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- UserPasswdDialog.h
+
+// Username and password dialog for VNC Viewer 4.0
+// Note that the password and username fields are only freed
+// when the dialog instance is deleted - it is important to
+// ensure that the instance is deleted as early as possible, to
+// avoid the password being retained in memory for too long.
+
+#ifndef __RFB_WIN32_USERPASSWD_DIALOG_H__
+#define __RFB_WIN32_USERPASSWD_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/CSecurity.h>
+#include <rfb/UserPasswdGetter.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class UserPasswdDialog : Dialog, public UserPasswdGetter {
+ public:
+ UserPasswdDialog();
+ virtual bool showDialog();
+ virtual void initDialog();
+ virtual bool onOk();
+ virtual void getUserPasswd(char** user, char** passwd);
+ void setCSecurity(const CSecurity* cs);
+ protected:
+ TCharArray username;
+ TPlainPasswd password;
+ bool showUsername, showPassword;
+ TCharArray description;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/ViewerToolBar.cxx b/win/vncviewer/ViewerToolBar.cxx
new file mode 100644
index 00000000..29b80301
--- /dev/null
+++ b/win/vncviewer/ViewerToolBar.cxx
@@ -0,0 +1,117 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ViewerToolBar.cxx
+
+#include <vncviewer/ViewerToolBar.h>
+#include <vncviewer/resource.h>
+
+void ViewerToolBar::create(HWND parentHwnd) {
+ // Create the toolbar panel
+ ToolBar::create(ID_TOOLBAR, parentHwnd, WS_CHILD |
+ TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NORESIZE);
+ addBitmap(4, IDB_TOOLBAR);
+
+ // Create the control buttons
+ addButton(0, ID_OPTIONS);
+ addButton(1, ID_INFO);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(2, ID_FULLSCREEN);
+ addButton(3, ID_REQUEST_REFRESH);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(4, ID_SEND_CAD);
+ addButton(5, ID_SEND_CTLESC);
+ addButton(6, ID_CTRL_KEY);
+ addButton(7, ID_ALT_KEY);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(8, ID_FILE_TRANSFER);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(9, ID_NEW_CONNECTION);
+ addButton(10, ID_CONN_SAVE_AS);
+ addButton(11, ID_CLOSE);
+
+ // Resize the toolbar window
+ autoSize();
+}
+
+LRESULT ViewerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+ switch (((LPNMHDR)lParam)->code) {
+ // Process tooltips text
+ case TTN_NEEDTEXT:
+ {
+ LPTOOLTIPTEXT TTStr = (LPTOOLTIPTEXT)lParam;
+ if (TTStr->hdr.code != TTN_NEEDTEXT)
+ return 0;
+
+ switch (TTStr->hdr.idFrom) {
+ case ID_OPTIONS:
+ TTStr->lpszText = "Connection options...";
+ break;
+ case ID_INFO:
+ TTStr->lpszText = "Connection info";
+ break;
+ case ID_FULLSCREEN:
+ TTStr->lpszText = "Full screen";
+ break;
+ case ID_REQUEST_REFRESH:
+ TTStr->lpszText = "Request screen refresh";
+ break;
+ case ID_SEND_CAD:
+ TTStr->lpszText = "Send Ctrl-Alt-Del";
+ break;
+ case ID_SEND_CTLESC:
+ TTStr->lpszText = "Send Ctrl-Esc";
+ break;
+ case ID_CTRL_KEY:
+ TTStr->lpszText = "Send Ctrl key press/release";
+ break;
+ case ID_ALT_KEY:
+ TTStr->lpszText = "Send Alt key press/release";
+ break;
+ case ID_FILE_TRANSFER:
+ TTStr->lpszText = "Transfer files...";
+ break;
+ case ID_NEW_CONNECTION:
+ TTStr->lpszText = "New connection...";
+ break;
+ case ID_CONN_SAVE_AS:
+ TTStr->lpszText = "Save connection info as...";
+ break;
+ case ID_CLOSE:
+ TTStr->lpszText = "Disconnect";
+ break;
+ default:
+ break;
+ }
+ }
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+void ViewerToolBar::show() {
+ ShowWindow(getHandle(), SW_SHOW);
+ SendMessage(parentHwnd, WM_SIZE, 0, 0);
+}
+
+void ViewerToolBar::hide() {
+ ShowWindow(getHandle(), SW_HIDE);
+ SendMessage(parentHwnd, WM_SIZE, 0, 0);
+}
diff --git a/win/vncviewer/ViewerToolBar.h b/win/vncviewer/ViewerToolBar.h
new file mode 100644
index 00000000..30e7708f
--- /dev/null
+++ b/win/vncviewer/ViewerToolBar.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ViewerToolBar.h
+
+// ToolBar for the Vnc Viewer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+class ViewerToolBar : public ToolBar {
+public:
+ ViewerToolBar() {}
+ ~ViewerToolBar() {}
+
+ void create(HWND parentHwnd);
+
+ LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+ void show();
+ void hide();
+};
diff --git a/win/vncviewer/buildTime.cxx b/win/vncviewer/buildTime.cxx
new file mode 100644
index 00000000..9f37b387
--- /dev/null
+++ b/win/vncviewer/buildTime.cxx
@@ -0,0 +1,18 @@
+/* Copyright (C) 2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
diff --git a/win/vncviewer/cursor1.cur b/win/vncviewer/cursor1.cur
new file mode 100644
index 00000000..20a713f7
--- /dev/null
+++ b/win/vncviewer/cursor1.cur
Binary files differ
diff --git a/win/vncviewer/ftdir.ico b/win/vncviewer/ftdir.ico
new file mode 100644
index 00000000..7a7f7419
--- /dev/null
+++ b/win/vncviewer/ftdir.ico
Binary files differ
diff --git a/win/vncviewer/ftfile.ico b/win/vncviewer/ftfile.ico
new file mode 100644
index 00000000..a8084b88
--- /dev/null
+++ b/win/vncviewer/ftfile.ico
Binary files differ
diff --git a/win/vncviewer/ftreload.ico b/win/vncviewer/ftreload.ico
new file mode 100644
index 00000000..34383e90
--- /dev/null
+++ b/win/vncviewer/ftreload.ico
Binary files differ
diff --git a/win/vncviewer/ftup.ico b/win/vncviewer/ftup.ico
new file mode 100644
index 00000000..fc215ada
--- /dev/null
+++ b/win/vncviewer/ftup.ico
Binary files differ
diff --git a/win/vncviewer/resource.h b/win/vncviewer/resource.h
new file mode 100644
index 00000000..5493fd0b
--- /dev/null
+++ b/win/vncviewer/resource.h
@@ -0,0 +1,154 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by vncviewer.rc
+//
+#define IDR_MANIFEST 1
+#define IDI_ICON 101
+#define IDD_VNC_AUTH_DLG 102
+#define IDD_CONNECTING_DLG 103
+#define IDD_CONNECTION_DLG 104
+#define IDC_DOT_CURSOR 105
+#define IDD_ABOUT 107
+#define IDD_FORMAT 108
+#define IDD_MISC 109
+#define IDD_INPUTS 110
+#define IDD_SERVER_KEYS 111
+#define IDR_TRAY 112
+#define IDD_CONNECTION_INFO 113
+#define IDD_DEFAULTS 116
+#define IDB_BITMAP 120
+#define IDD_FILETRANSFER_DLG 121
+#define IDB_TOOLBAR 122
+#define IDD_FTCONFIRM_DLG 124
+#define IDI_FTUP 125
+#define IDI_FTDIR 126
+#define IDI_FTFILE 127
+#define IDI_FTRELOAD 128
+#define IDR_FTMENU 130
+#define IDD_FTCANCELING 131
+#define IDD_FTCREATEFOLDER 132
+#define IDD_FTBROWSE 133
+#define IDC_PASSWORD 1000
+#define IDC_CONNECTING_TEXT 1001
+#define IDC_SERVER_EDIT 1002
+#define IDC_USERNAME 1005
+#define IDC_VERSION 1008
+#define IDC_BUILDTIME 1009
+#define IDC_ENCODING_AUTO 1010
+#define IDC_FORMAT_FULLCOLOUR 1011
+#define IDC_ENCODING_ZRLE 1012
+#define IDC_ENCODING_HEXTILE 1013
+#define IDC_CONN_SHARED 1013
+#define IDC_ENCODING_RAW 1014
+#define IDC_FULL_SCREEN 1014
+#define IDC_SEND_POINTER 1015
+#define IDC_SEND_KEYS 1016
+#define IDC_CLIENT_CUTTEXT 1017
+#define IDC_SERVER_CUTTEXT 1018
+#define IDC_LOCAL_CURSOR 1019
+#define IDC_DESKTOP_RESIZE 1020
+#define IDC_COPYRIGHT 1021
+#define IDC_DESCRIPTION 1022
+#define IDC_OPTIONS 1023
+#define IDC_ABOUT 1024
+#define IDC_LIST1 1025
+#define IDC_FTLOCALLIST 1025
+#define IDC_INFO_NAME 1026
+#define IDC_INFO_HOST 1027
+#define IDC_INFO_SIZE 1028
+#define IDC_INFO_PF 1029
+#define IDC_INFO_DEF_PF 1030
+#define IDC_INFO_LINESPEED 1031
+#define IDC_INFO_VERSION 1032
+#define IDC_PROTOCOL_3_3 1034
+#define IDC_ACCEPT_BELL 1035
+#define IDC_FORMAT_VERYLOWCOLOUR 1036
+#define IDC_SHOW_TOOLBAR 1036
+#define IDC_FORMAT_LOWCOLOUR 1037
+#define IDC_FORMAT_MEDIUMCOLOUR 1038
+#define IDC_LOAD_DEFAULTS 1040
+#define IDC_SAVE_DEFAULTS 1041
+#define IDC_LOAD_CONFIG 1042
+#define IDC_EMULATE3 1043
+#define IDC_POINTER_INTERVAL 1044
+#define IDC_SAVE_CONFIG 1045
+#define IDC_INFO_SECURITY 1046
+#define IDC_SAVE_CONFIG_AS 1048
+#define IDC_MENU_KEY 1051
+#define IDC_REQUESTED_ENCODING 1052
+#define IDC_LAST_ENCODING 1053
+#define IDC_SECURITY_LEVEL 1054
+#define IDC_INFO_ENCRYPTION 1055
+#define IDC_AUTO_RECONNECT 1056
+#define IDC_DISABLE_WINKEYS 1057
+#define IDC_QUALITYLEVEL 1058
+#define IDC_FTLOCALUP 1058
+#define IDC_SEND_SYSKEYS 1059
+#define IDC_FTLOCALBROWSE 1059
+#define IDC_FTREMOTERELOAD 1060
+#define IDC_FTREMOTEUP 1061
+#define IDC_FTREMOTEBROWSE 1062
+#define IDC_FTPROGRESS 1063
+#define IDC_FTGENERALPROGRESS 1063
+#define IDC_PROGRESS 1064
+#define IDC_FTSINGLEPROGRESS 1064
+#define IDC_FTSTATUS 1065
+#define IDC_FTCURRENTPROCENT 1066
+#define IDC_FTSINGLEPERCENT 1066
+#define IDC_FTTOTALPROCENT 1067
+#define IDC_FTGENERALPERCENT 1067
+#define IDC_FTUPLOAD 1072
+#define IDC_FTCANCEL 1073
+#define IDC_FTDOWNLOAD 1074
+#define IDC_FTCLOSE 1075
+#define IDC_FTLOCALLABEL 1076
+#define IDC_FTREMOTELABEL 1077
+#define IDC_FTDIRNAME 1078
+#define IDC_CONFIRM_YESTOALL 1079
+#define IDC_CONFIRM_TEXT 1080
+#define IDC_EDIT2 1082
+#define IDC_FTFOLDERNAME 1083
+#define IDC_FTTEXT 1084
+#define IDC_FTBROWSEPATH 1085
+#define IDC_FTBROWSETREE 1086
+#define IDC_TYPE 1088
+#define IDC_ENCODING_TIGHT 1089
+#define IDC_FTLOCALPATH 1090
+#define IDC_CUSTOM_COMPRESSLEVEL 1091
+#define IDC_FTREMOTEPATH 1092
+#define IDC_COMPRESSLEVEL 1093
+#define IDC_FTREMOTELIST 1094
+#define IDC_ALLOW_JPEG 1095
+#define IDC_FTLOCALRELOAD 1096
+#define ID_TOOLBAR 40002
+#define ID_CLOSE 40003
+#define ID_OPTIONS 40004
+#define ID_NEW_CONNECTION 40005
+#define ID_ABOUT 40006
+#define ID_FULLSCREEN 40007
+#define ID_SEND_CAD 40008
+#define ID_INFO 40009
+#define ID_REQUEST_REFRESH 40010
+#define ID_CTRL_KEY 40011
+#define ID_ALT_KEY 40012
+#define ID_SEND_MENU_KEY 40013
+#define ID_SEND_CTLESC 40014
+#define ID_CONN_SAVE_AS 40015
+#define ID_FILE_TRANSFER 40016
+#define IDM_FTCOPY 40022
+#define IDM_FTRENAME 40023
+#define IDM_FTDELETE 40024
+#define IDM_FTCANCEL 40025
+#define IDM_FTCREATEFOLDER 40026
+#define IDM_SHOW_TOOLBAR 40027
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 134
+#define _APS_NEXT_COMMAND_VALUE 40028
+#define _APS_NEXT_CONTROL_VALUE 1097
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/win/vncviewer/toolbar.bmp b/win/vncviewer/toolbar.bmp
new file mode 100644
index 00000000..0a146361
--- /dev/null
+++ b/win/vncviewer/toolbar.bmp
Binary files differ
diff --git a/win/vncviewer/vncviewer.bmp b/win/vncviewer/vncviewer.bmp
new file mode 100644
index 00000000..4ea9c378
--- /dev/null
+++ b/win/vncviewer/vncviewer.bmp
Binary files differ
diff --git a/win/vncviewer/vncviewer.cxx b/win/vncviewer/vncviewer.cxx
new file mode 100644
index 00000000..3a5214a3
--- /dev/null
+++ b/win/vncviewer/vncviewer.cxx
@@ -0,0 +1,295 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- VNC Viewer for Win32
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+#include <list>
+
+#include <vncviewer/resource.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/ListenServer.h>
+#include <vncviewer/ListenTrayIcon.h>
+#include <network/TcpSocket.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/Logger_file.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb_win32/RegConfig.h>
+#include <rfb_win32/MsgBox.h>
+
+#ifdef _DIALOG_CAPTURE
+#include <extra/LoadBMP.h>
+#endif
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+using namespace network;
+
+static LogWriter vlog("main");
+
+TStr rfb::win32::AppName("VNC Viewer");
+
+
+#ifdef _DIALOG_CAPTURE
+BoolParameter captureDialogs("CaptureDialogs", "", false);
+#endif
+
+//
+// -=- Listener
+// Class to handle listening on a particular port for incoming connections
+// from servers, and spawning of clients
+//
+
+static BoolParameter acceptIncoming("Listen", "Accept incoming connections from VNC servers.", false);
+
+
+//
+// -=- AboutDialog global values
+//
+
+const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
+const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
+const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
+const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
+const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
+
+
+//
+// -=- processParams
+// Read in the command-line parameters and interpret them.
+//
+
+void
+programInfo() {
+ win32::FileVersionInfo inf;
+ _tprintf(_T("%s - %s, Version %s\n"),
+ inf.getVerString(_T("ProductName")),
+ inf.getVerString(_T("FileDescription")),
+ inf.getVerString(_T("FileVersion")));
+ printf("%s\n", buildTime);
+ _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
+}
+
+void
+programUsage() {
+ printf("usage: vncviewer <options> <hostname>[:<display>]\n");
+ printf("Command-line options:\n");
+ printf(" -help - Provide usage information.\n");
+ printf(" -config <file> - Load connection settings from VNC Viewer 3.3 settings file\n");
+ printf(" -console - Run with a console window visible.\n");
+ printf(" <setting>=<value> - Set the named configuration parameter.\n");
+ printf(" (Parameter values specified on the command-line override those specified by other configuration methods.)\n");
+ printf("\nLog names:\n");
+ LogWriter::listLogWriters();
+ printf("\nLog destinations:\n");
+ Logger::listLoggers();
+ printf("\nParameters:\n");
+ Configuration::listParams();
+ printf("Press Enter/Return key to continue\n");
+ char c = getchar();
+ exit(1);
+}
+
+
+bool print_usage = false;
+bool close_console = true;
+std::list<char*> hosts;
+std::list<char*> configFiles;
+
+void
+processParams(int argc, char* argv[]) {
+ for (int i=1; i<argc; i++) {
+ try {
+
+ if (strcasecmp(argv[i], "-console") == 0) {
+ close_console = false;
+
+ } else if (((strcasecmp(argv[i], "-config") == 0) ||
+ (strcasecmp(argv[i], "/config") == 0)) && (i < argc-1)) {
+ configFiles.push_back(strDup(argv[i+1]));
+ i++;
+
+ } else if ((strcasecmp(argv[i], "-help") == 0) ||
+ (strcasecmp(argv[i], "--help") == 0) ||
+ (strcasecmp(argv[i], "-h") == 0) ||
+ (strcasecmp(argv[i], "/?") == 0)) {
+ print_usage = true;
+ close_console = false;
+ break;
+
+ } else {
+ // Try to process <option>=<value>, or -<bool>
+ if (Configuration::setParam(argv[i], true))
+ continue;
+ // Try to process -<option> <value>
+ if ((argv[i][0] == '-') && (i+1 < argc)) {
+ if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
+ i++;
+ continue;
+ }
+ }
+ // If it's -<option> then it's not recognised - error
+ // If it's <host> then add it to the list to connect to.
+ if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
+ const char* fmt = "The option %s was not recognized. Use -help to see VNC Viewer usage";
+ CharArray tmp(strlen(argv[i])+strlen(fmt)+1);
+ sprintf(tmp.buf, fmt, argv[i]);
+ MsgBox(0, TStr(tmp.buf), MB_ICONSTOP | MB_OK);
+ exit(1);
+ } else if (strContains(argv[i], '\\')) {
+ configFiles.push_back(strDup(argv[i]));
+ } else {
+ hosts.push_back(strDup(argv[i]));
+ }
+ }
+
+ } catch (rdr::Exception& e) {
+ vlog.error(e.str());
+ }
+ }
+}
+
+
+//
+// -=- main
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+ try {
+
+ // - Initialise the available loggers
+ initStdIOLoggers();
+ initFileLogger("C:\\temp\\vncviewer4.log");
+
+ // - By default, just log errors to stderr
+ logParams.setDefault("*:stderr:0");
+
+ // - Process the command-line
+ int argc = __argc;
+ char** argv = __argv;
+ processParams(argc, argv);
+
+ // - By default the console will be closed
+ if (close_console) {
+ if (!FreeConsole())
+ vlog.info("unable to close console:%u", GetLastError());
+ } else {
+ AllocConsole();
+ freopen("CONIN$","rb",stdin);
+ freopen("CONOUT$","wb",stdout);
+ freopen("CONOUT$","wb",stderr);
+ setbuf(stderr, 0);
+ }
+
+#ifdef _DIALOG_CAPTURE
+ if (captureDialogs) {
+ CConn::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+ OptionsDialog::global.showDialog(0, true);
+ return 0;
+ }
+#endif
+
+ // - If no clients are specified, bring up a connection dialog
+ if (configFiles.empty() && hosts.empty() && !acceptIncoming && !print_usage)
+ hosts.push_back(0);
+
+ programInfo();
+
+ // - Connect to the clients
+ if (!configFiles.empty() || !hosts.empty() || acceptIncoming) {
+ // - Configure the registry configuration reader
+ win32::RegConfigThread config;
+ config.start(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+
+ // - Tell the rest of VNC Viewer where to write config data to
+ CConn::userConfigKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+
+ if (acceptIncoming) {
+ int port = 5500;
+
+ // Listening viewer
+ if (hosts.size() > 1)
+ programUsage();
+ if (!hosts.empty())
+ port = atoi(hosts.front());
+
+ // Show the tray icon & menu
+ ListenTrayIcon tray;
+
+ // Listen for reverse connections
+ network::TcpListener sock(port);
+ ListenServer listener(&sock);
+
+ // Run the view manager
+ // Also processes the tray icon if necessary
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else {
+ // Read each config file in turn
+ while (!configFiles.empty()) {
+ char* filename = configFiles.front();
+ Thread* connThread = new CConnThread(filename, true);
+ strFree(filename);
+ configFiles.pop_front();
+ }
+
+ // Connect to each client in turn
+ while (!hosts.empty()) {
+ char* hostinfo = hosts.front();
+ Thread* connThread = new CConnThread(hostinfo);
+ strFree(hostinfo);
+ hosts.pop_front();
+ }
+
+ // Run the view manager
+ MSG msg;
+ while (CConnThread::getMessage(&msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ vlog.debug("quitting viewer");
+ }
+
+ }
+
+ // - If necessary, print the program's usage info
+ if (print_usage)
+ programUsage();
+
+ if (!close_console) {
+ printf("Press Enter/Return key to continue\n");
+ char c = getchar();
+ }
+
+ } catch (rdr::Exception& e) {
+ MsgBox(0, TStr(e.str()), MB_ICONSTOP | MB_OK);
+ }
+
+ return 0;
+}
diff --git a/win/vncviewer/vncviewer.dsp b/win/vncviewer/vncviewer.dsp
new file mode 100644
index 00000000..e245cd6e
--- /dev/null
+++ b/win/vncviewer/vncviewer.dsp
@@ -0,0 +1,321 @@
+# Microsoft Developer Studio Project File - Name="vncviewer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=vncviewer - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "vncviewer.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "vncviewer.mak" CFG="vncviewer - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "vncviewer - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "vncviewer - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "vncviewer - Win32 Debug Unicode" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "vncviewer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\vncviewer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /machine:I386
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\vncviewer /MT buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "vncviewer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\vncviewer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\vncviewer /MTd buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "vncviewer - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "vncviewer___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "vncviewer___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\vncviewer"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_WINDOWS" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /Fo..\Debug_Unicode\ /Fd..\Debug_Unicode\vncviewer /MTd buildTime.cxx
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "vncviewer - Win32 Release"
+# Name "vncviewer - Win32 Debug"
+# Name "vncviewer - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\buildTime.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConn.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnOptions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnThread.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectingDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectionDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\DesktopWindow.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileTransfer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTBrowseDlg.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTListView.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTProgress.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPasswdDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ViewerToolBar.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.rc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\CConn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnThread.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectingDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectionDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DesktopWindow.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileTransfer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTBrowseDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTListView.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListenServer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListenTrayIcon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MRU.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPasswdDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ViewerToolBar.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\cursor1.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftdir.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftfile.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftreload.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftup.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\toolbar.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.ico
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win/vncviewer/vncviewer.exe.manifest b/win/vncviewer/vncviewer.exe.manifest
new file mode 100644
index 00000000..7fd947ff
--- /dev/null
+++ b/win/vncviewer/vncviewer.exe.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+ version="4.0.0.26"
+ processorArchitecture="X86"
+ name="TightVNC.vncviewer.exe"
+ type="win32"
+/>
+<description>.NET control deployment tool</description>
+<dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="X86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+</dependency>
+</assembly>
diff --git a/win/vncviewer/vncviewer.ico b/win/vncviewer/vncviewer.ico
new file mode 100644
index 00000000..65726612
--- /dev/null
+++ b/win/vncviewer/vncviewer.ico
Binary files differ
diff --git a/win/vncviewer/vncviewer.rc b/win/vncviewer/vncviewer.rc
new file mode 100644
index 00000000..ea5dd65c
--- /dev/null
+++ b/win/vncviewer/vncviewer.rc
@@ -0,0 +1,708 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON ICON DISCARDABLE "vncviewer.ico"
+IDI_FTDIR ICON DISCARDABLE "ftdir.ico"
+IDI_FTFILE ICON DISCARDABLE "ftfile.ico"
+IDI_FTRELOAD ICON DISCARDABLE "ftreload.ico"
+IDI_FTUP ICON DISCARDABLE "ftup.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,1,1,0
+ PRODUCTVERSION 4,1,1,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "Constantin Kaplinsky\0"
+ VALUE "FileDescription", "TightVNC Viewer for Win32\0"
+ VALUE "FileVersion", "4.1.1\0"
+ VALUE "InternalName", "free4/vncviewer/win\0"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2006 [many holders]\0"
+ VALUE "LegalTrademarks", "TightVNC\0"
+ VALUE "OriginalFilename", "vncviewer.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "TightVNC Viewer\0"
+ VALUE "ProductVersion", "4.1.1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_VNC_AUTH_DLG DIALOG DISCARDABLE 0, 0, 241, 46
+STYLE DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION
+CAPTION "VNC Viewer : Authentication"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_USERNAME,85,6,100,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_PASSWORD,85,25,100,15,ES_PASSWORD | ES_AUTOHSCROLL |
+ ES_WANTRETURN
+ DEFPUSHBUTTON "OK",IDOK,190,6,45,14
+ PUSHBUTTON "Cancel",IDCANCEL,190,25,45,15
+ CONTROL 120,IDI_ICON,"Static",SS_BITMAP,7,6,21,20
+ LTEXT "Username:",IDC_STATIC,45,6,35,14
+ LTEXT "Password:",IDC_STATIC,45,25,35,15
+END
+
+IDD_CONNECTING_DLG DIALOG DISCARDABLE 0, 0, 185, 47
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION
+CAPTION "VNC Viewer : Connecting"
+FONT 8, "MS Sans Serif"
+BEGIN
+ PUSHBUTTON "Cancel",IDCANCEL,128,26,50,14
+ CTEXT "Attempting to connect to host...",IDC_CONNECTING_TEXT,7,
+ 7,171,14,SS_CENTERIMAGE
+END
+
+IDD_CONNECTION_DLG DIALOG DISCARDABLE 0, 0, 224, 66
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "VNC Viewer : Connection Details"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_SERVER_EDIT,85,6,105,234,CBS_DROPDOWN |
+ CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&About...",IDC_ABOUT,5,45,50,14
+ PUSHBUTTON "&Options...",IDC_OPTIONS,60,45,50,14
+ DEFPUSHBUTTON "OK",IDOK,115,45,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,170,45,48,14
+ CONTROL 120,IDI_ICON,"Static",SS_BITMAP | SS_REALSIZEIMAGE,5,6,
+ 20,20
+ RTEXT "Server:",IDC_STATIC,43,6,37,13,SS_CENTERIMAGE
+ RTEXT "Encryption:",IDC_STATIC,43,24,37,12,SS_CENTERIMAGE
+ COMBOBOX IDC_SECURITY_LEVEL,85,24,105,76,CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 249, 92
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "About VNC Viewer for Windows"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,195,70,47,15
+ CONTROL 120,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,7,
+ 10,33,31
+ LTEXT ">appname<",IDC_DESCRIPTION,46,10,119,15
+ LTEXT ">version<",IDC_VERSION,165,10,77,15
+ LTEXT ">buildtime<",IDC_BUILDTIME,46,25,196,15
+ LTEXT ">copyright<",IDC_COPYRIGHT,46,40,196,15
+ LTEXT "Visit www.tightvnc.com for more information on TightVNC.",
+ IDC_STATIC,46,55,196,15
+END
+
+IDD_FORMAT DIALOG DISCARDABLE 0, 0, 201, 161
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Colour && Encoding"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "&Auto select",IDC_ENCODING_AUTO,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,7,88,13
+ GROUPBOX "Preferred encoding",IDC_STATIC,7,20,83,75
+ CONTROL "Tight",IDC_ENCODING_TIGHT,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,10,30,75,14
+ CONTROL "ZRLE",IDC_ENCODING_ZRLE,"Button",BS_AUTORADIOBUTTON,10,
+ 45,75,14
+ CONTROL "Hextile",IDC_ENCODING_HEXTILE,"Button",
+ BS_AUTORADIOBUTTON,10,60,75,16
+ CONTROL "Raw",IDC_ENCODING_RAW,"Button",BS_AUTORADIOBUTTON,10,75,
+ 75,15
+ GROUPBOX "Color level",IDC_STATIC,95,20,99,75
+ CONTROL "&Full (all available colors)",IDC_FORMAT_FULLCOLOUR,
+ "Button",BS_AUTORADIOBUTTON | WS_GROUP,100,30,90,15
+ CONTROL "&Medium (256 colors)",IDC_FORMAT_MEDIUMCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,45,90,14
+ CONTROL "&Low (64 colors)",IDC_FORMAT_LOWCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,60,90,16
+ CONTROL "&Very low (8 colors)",IDC_FORMAT_VERYLOWCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,75,90,15
+ CONTROL "Custom compression level:",IDC_CUSTOM_COMPRESSLEVEL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,100,99,10
+ EDITTEXT IDC_COMPRESSLEVEL,25,111,15,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "level (1=fast, 9=best)",IDC_STATIC,44,114,81,9,NOT
+ WS_GROUP
+ CONTROL "Allow JPEG compression:",IDC_ALLOW_JPEG,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,126,96,10
+ EDITTEXT IDC_QUALITYLEVEL,25,137,15,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "quality (1=poor, 9=best)",IDC_STATIC,44,140,81,9
+END
+
+IDD_MISC DIALOG DISCARDABLE 0, 0, 213, 137
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Misc"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Shared connection (do not disconnect other viewers)",
+ IDC_CONN_SHARED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,
+ 10,199,15
+ CONTROL "Full-screen mode",IDC_FULL_SCREEN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,25,99,15
+ CONTROL "Show toolbar",IDC_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,106,25,100,15
+ CONTROL "Render cursor locally",IDC_LOCAL_CURSOR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,40,199,15
+ CONTROL "Allow dynamic desktop resizing",IDC_DESKTOP_RESIZE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,199,15
+ CONTROL "Only use protocol version 3.3",IDC_PROTOCOL_3_3,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,70,199,15
+ CONTROL "Beep when requested to by the server",IDC_ACCEPT_BELL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,85,199,15
+ CONTROL "Offer to automatically reconnect",IDC_AUTO_RECONNECT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,199,15
+END
+
+IDD_INPUTS DIALOG DISCARDABLE 0, 0, 186, 162
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Inputs"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Send pointer events to server",IDC_SEND_POINTER,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,10,172,15
+ CONTROL "Send keyboard events to server",IDC_SEND_KEYS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,25,172,15
+ CONTROL "Send clipboard changes to server",IDC_CLIENT_CUTTEXT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,172,15
+ CONTROL "Accept clipboard changes from server",
+ IDC_SERVER_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 7,55,172,15
+ CONTROL "Enable 3-button mouse emulation",IDC_EMULATE3,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,70,172,15
+ CONTROL "Rate-limit mouse move events",IDC_POINTER_INTERVAL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,86,172,14
+ LTEXT "Menu key",IDC_STATIC,7,100,98,15,SS_CENTERIMAGE
+ COMBOBOX IDC_MENU_KEY,105,100,74,105,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Pass special keys directly to server",
+ IDC_DISABLE_WINKEYS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,7,115,172,15
+END
+
+IDD_CONNECTION_INFO DIALOG DISCARDABLE 0, 0, 239, 199
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "VNC Connection Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,182,178,50,14
+ LTEXT "Desktop Name:",IDC_STATIC,7,10,73,15
+ LTEXT "Host:",IDC_STATIC,7,25,73,15
+ LTEXT "Size:",IDC_STATIC,7,40,73,15
+ LTEXT "Pixel Format:",IDC_STATIC,7,55,73,15
+ LTEXT "Server Default:",IDC_STATIC,7,70,73,15
+ LTEXT "Line Speed Estimate:",IDC_STATIC,7,115,73,15
+ LTEXT "Protocol Version:",IDC_STATIC,7,130,73,15
+ LTEXT "",IDC_INFO_NAME,80,10,152,15
+ LTEXT "",IDC_INFO_HOST,80,25,152,15
+ LTEXT "",IDC_INFO_SIZE,80,40,152,15
+ LTEXT "",IDC_INFO_PF,80,55,152,15
+ LTEXT "",IDC_INFO_DEF_PF,80,70,152,15
+ LTEXT "",IDC_INFO_LINESPEED,80,115,152,15
+ LTEXT "",IDC_INFO_VERSION,80,130,152,15
+ LTEXT "Security Method:",IDC_STATIC,7,145,73,15
+ LTEXT "",IDC_INFO_SECURITY,80,145,152,15
+ LTEXT "Requested Encoding:",IDC_STATIC,7,85,73,15
+ LTEXT "Last Used Encoding:",IDC_STATIC,7,100,73,15
+ LTEXT "",IDC_REQUESTED_ENCODING,80,86,152,15
+ LTEXT "",IDC_LAST_ENCODING,80,100,152,15
+ LTEXT "Static",IDC_INFO_ENCRYPTION,80,160,152,15
+ LTEXT "Encryption:",IDC_STATIC,7,160,73,15
+END
+
+IDD_DEFAULTS DIALOG DISCARDABLE 0, 0, 217, 87
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Load / Save"
+FONT 8, "MS Sans Serif"
+BEGIN
+ PUSHBUTTON "&Reload",IDC_LOAD_CONFIG,15,20,85,15
+ PUSHBUTTON "&Save",IDC_SAVE_CONFIG,15,40,85,15
+ PUSHBUTTON "Save &As ...",IDC_SAVE_CONFIG_AS,15,60,85,15
+ PUSHBUTTON "R&eload",IDC_LOAD_DEFAULTS,120,20,85,15
+ PUSHBUTTON "S&ave",IDC_SAVE_DEFAULTS,120,40,85,15
+ GROUPBOX "Configuration File",IDC_STATIC,7,7,100,74
+ GROUPBOX "Defaults",IDC_STATIC,113,7,97,53
+END
+
+IDD_FILETRANSFER_DLG DIALOGEX 0, 0, 530, 282
+STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTEXTHELP | WS_EX_CONTROLPARENT
+CAPTION "TightVNC File Transfers"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_FTLOCALLIST,"SysListView32",LVS_REPORT |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,7,40,200,196
+ CONTROL "List2",IDC_FTREMOTELIST,"SysListView32",LVS_REPORT |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,323,40,200,196
+ PUSHBUTTON "Upload Files and Folders",IDC_FTUPLOAD,218,66,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Download Files and Folders",IDC_FTDOWNLOAD,218,85,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Cancel File Transfer",IDC_FTCANCEL,218,167,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Close",IDC_FTCLOSE,218,217,94,12
+ EDITTEXT IDC_FTLOCALPATH,7,20,155,12,ES_AUTOHSCROLL | NOT
+ WS_TABSTOP
+ CTEXT "Local Computer",IDC_FTLOCALLABEL,7,7,200,10
+ PUSHBUTTON "...",IDC_FTLOCALBROWSE,165,20,14,12,NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTLOCALUP,179,20,14,12,BS_ICON | NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTLOCALRELOAD,193,20,14,12,BS_ICON | NOT
+ WS_TABSTOP
+ CONTROL "Progress1",IDC_FTGENERALPROGRESS,"msctls_progress32",
+ WS_BORDER,55,244,128,10
+ LTEXT "File Transfer",IDC_STATIC,7,245,40,8
+ COMBOBOX IDC_FTSTATUS,7,263,516,65,CBS_DROPDOWNLIST |
+ CBS_NOINTEGRALHEIGHT | WS_VSCROLL
+ CONTROL "Progress1",IDC_FTSINGLEPROGRESS,"msctls_progress32",
+ WS_BORDER,370,244,128,10
+ EDITTEXT IDC_FTREMOTEPATH,323,20,155,12,ES_AUTOHSCROLL | NOT
+ WS_TABSTOP
+ PUSHBUTTON "...",IDC_FTREMOTEBROWSE,481,20,14,12,NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTREMOTEUP,495,20,14,12,BS_ICON | NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTREMOTERELOAD,509,20,14,12,BS_ICON | NOT
+ WS_TABSTOP
+ CTEXT "TightVNC Server",IDC_FTREMOTELABEL,323,7,200,10
+ LTEXT "Current File",IDC_STATIC,323,245,36,8
+ CTEXT "0%",IDC_FTGENERALPERCENT,189,245,18,8
+ CTEXT "0%",IDC_FTSINGLEPERCENT,505,245,18,8
+END
+
+IDD_FTBROWSE DIALOGEX 0, 0, 183, 196
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Browse Folders"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,38,175,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,95,175,50,14
+ EDITTEXT IDC_FTBROWSEPATH,7,7,169,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_TABSTOP
+ CONTROL "Tree1",IDC_FTBROWSETREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,25,169,143
+END
+
+IDD_FTCANCELING DIALOG DISCARDABLE 0, 0, 193, 63
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Canceling Active File Transfer"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,40,42,50,14
+ PUSHBUTTON "No",IDCANCEL,102,42,50,14
+ LTEXT "FileTransfer is active.\nAre you sure you want to cancel transfer?",
+ IDC_STATIC,42,14,133,19
+END
+
+IDD_FTCONFIRM_DLG DIALOG DISCARDABLE 0, 0, 188, 143
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,69,122,50,14,WS_GROUP
+ PUSHBUTTON "No",IDCANCEL,131,122,50,14
+ PUSHBUTTON "Yes to All",IDC_CONFIRM_YESTOALL,7,122,50,14
+ LTEXT "Static",IDC_CONFIRM_TEXT,7,7,174,107
+END
+
+IDD_FTCREATEFOLDER DIALOG DISCARDABLE 0, 0, 193, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Create a New Folder"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_FTFOLDERNAME,7,19,179,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,80,42,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,136,42,50,14
+ LTEXT "New folder name:",IDC_FTTEXT,7,7,179,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_VNC_AUTH_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 235
+ VERTGUIDE, 45
+ VERTGUIDE, 80
+ VERTGUIDE, 85
+ VERTGUIDE, 185
+ VERTGUIDE, 190
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 40
+ HORZGUIDE, 20
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ END
+
+ IDD_CONNECTING_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 178
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 40
+ HORZGUIDE, 21
+ HORZGUIDE, 26
+ END
+
+ IDD_CONNECTION_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 218
+ VERTGUIDE, 30
+ VERTGUIDE, 43
+ VERTGUIDE, 55
+ VERTGUIDE, 60
+ VERTGUIDE, 80
+ VERTGUIDE, 85
+ VERTGUIDE, 110
+ VERTGUIDE, 115
+ VERTGUIDE, 165
+ VERTGUIDE, 170
+ VERTGUIDE, 190
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 59
+ HORZGUIDE, 19
+ HORZGUIDE, 24
+ HORZGUIDE, 36
+ HORZGUIDE, 45
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 242
+ VERTGUIDE, 46
+ VERTGUIDE, 165
+ VERTGUIDE, 195
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ END
+
+ IDD_FORMAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 194
+ VERTGUIDE, 10
+ VERTGUIDE, 85
+ VERTGUIDE, 90
+ VERTGUIDE, 95
+ VERTGUIDE, 100
+ VERTGUIDE, 105
+ VERTGUIDE, 190
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 154
+ HORZGUIDE, 10
+ HORZGUIDE, 20
+ HORZGUIDE, 25
+ HORZGUIDE, 35
+ HORZGUIDE, 49
+ HORZGUIDE, 65
+ HORZGUIDE, 80
+ HORZGUIDE, 85
+ END
+
+ IDD_MISC, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 206
+ VERTGUIDE, 106
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 130
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ END
+
+ IDD_INPUTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ VERTGUIDE, 105
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 155
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ HORZGUIDE, 145
+ END
+
+ IDD_CONNECTION_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 232
+ VERTGUIDE, 80
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 192
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ HORZGUIDE, 145
+ HORZGUIDE, 160
+ HORZGUIDE, 175
+ END
+
+ IDD_DEFAULTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 210
+ VERTGUIDE, 15
+ VERTGUIDE, 100
+ VERTGUIDE, 107
+ VERTGUIDE, 113
+ VERTGUIDE, 120
+ VERTGUIDE, 205
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 80
+ HORZGUIDE, 20
+ HORZGUIDE, 35
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 60
+ HORZGUIDE, 75
+ END
+
+ IDD_FILETRANSFER_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 523
+ VERTGUIDE, 207
+ VERTGUIDE, 265
+ VERTGUIDE, 323
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 275
+ HORZGUIDE, 12
+ HORZGUIDE, 26
+ HORZGUIDE, 40
+ HORZGUIDE, 47
+ HORZGUIDE, 249
+ END
+
+ IDD_FTBROWSE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 176
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 189
+ END
+
+ IDD_FTCANCELING, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 186
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
+ END
+
+ IDD_FTCONFIRM_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 181
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 136
+ END
+
+ IDD_FTCREATEFOLDER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 186
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_DOT_CURSOR CURSOR DISCARDABLE "cursor1.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog Info
+//
+
+IDD_CONNECTION_DLG DLGINIT
+BEGIN
+ IDC_SERVER_EDIT, 0x403, 16, 0
+0x796d, 0x616d, 0x6863, 0x6e69, 0x2e65, 0x726f, 0x3a67, 0x0031,
+ 0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAY MENU DISCARDABLE
+BEGIN
+ POPUP "Tray Menu"
+ BEGIN
+ MENUITEM "&New Connection...", ID_NEW_CONNECTION
+ MENUITEM SEPARATOR
+ MENUITEM "Default &Options...", ID_OPTIONS
+ MENUITEM SEPARATOR
+ MENUITEM "&Close Daemon", ID_CLOSE
+ MENUITEM "&About...", ID_ABOUT
+ END
+END
+
+IDR_FTMENU MENU DISCARDABLE
+BEGIN
+ POPUP "File Transfer"
+ BEGIN
+ MENUITEM "Copy Files and Folders", IDM_FTCOPY
+ MENUITEM SEPARATOR
+ MENUITEM "Create a Folder", IDM_FTCREATEFOLDER
+ MENUITEM "Rename File or Folder", IDM_FTRENAME
+ MENUITEM "Delete Files and Folders", IDM_FTDELETE
+ MENUITEM SEPARATOR
+ MENUITEM "Cancel File Transfer", IDM_FTCANCEL
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 24
+//
+
+IDR_MANIFEST 24 DISCARDABLE "vncviewer.exe.manifest"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP BITMAP DISCARDABLE "vncviewer.bmp"
+IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp"
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/win/winvnc/AddNewClientDialog.h b/win/winvnc/AddNewClientDialog.h
new file mode 100644
index 00000000..9bf51355
--- /dev/null
+++ b/win/winvnc/AddNewClientDialog.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- 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
index 00000000..74282303
--- /dev/null
+++ b/win/winvnc/ControlPanel.cxx
@@ -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
index 00000000..73b859f8
--- /dev/null
+++ b/win/winvnc/ControlPanel.h
@@ -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
index 00000000..15c05c46
--- /dev/null
+++ b/win/winvnc/JavaViewer.cxx
@@ -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
index 00000000..ecda4d3e
--- /dev/null
+++ b/win/winvnc/JavaViewer.h
@@ -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
index 00000000..9bf1b9a1
--- /dev/null
+++ b/win/winvnc/ManagedListener.cxx
@@ -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
index 00000000..e83aa0b6
--- /dev/null
+++ b/win/winvnc/ManagedListener.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#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
index 00000000..dc50eab3
--- /dev/null
+++ b/win/winvnc/QueryConnectDialog.cxx
@@ -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
index 00000000..b28de198
--- /dev/null
+++ b/win/winvnc/QueryConnectDialog.h
@@ -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
index 00000000..0b10fa5b
--- /dev/null
+++ b/win/winvnc/STrayIcon.cxx
@@ -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
index 00000000..309d3f4a
--- /dev/null
+++ b/win/winvnc/STrayIcon.h
@@ -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
index 00000000..2ef2ee08
--- /dev/null
+++ b/win/winvnc/VNCServerService.cxx
@@ -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
index 00000000..c7a76cce
--- /dev/null
+++ b/win/winvnc/VNCServerService.h
@@ -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
index 00000000..3b0e1a0a
--- /dev/null
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -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
index 00000000..579a6a0b
--- /dev/null
+++ b/win/winvnc/VNCServerWin32.h
@@ -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
index 00000000..9f37b387
--- /dev/null
+++ b/win/winvnc/buildTime.cxx
@@ -0,0 +1,18 @@
+/* Copyright (C) 2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
diff --git a/win/winvnc/connecte.ico b/win/winvnc/connecte.ico
new file mode 100644
index 00000000..8f814b33
--- /dev/null
+++ b/win/winvnc/connecte.ico
Binary files differ
diff --git a/win/winvnc/connected.ico b/win/winvnc/connected.ico
new file mode 100644
index 00000000..44ce3c97
--- /dev/null
+++ b/win/winvnc/connected.ico
Binary files differ
diff --git a/win/winvnc/icon_dis.ico b/win/winvnc/icon_dis.ico
new file mode 100644
index 00000000..0a6ea15c
--- /dev/null
+++ b/win/winvnc/icon_dis.ico
Binary files differ
diff --git a/win/winvnc/resource.h b/win/winvnc/resource.h
new file mode 100644
index 00000000..68316be9
--- /dev/null
+++ b/win/winvnc/resource.h
@@ -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
index 00000000..90c02f89
--- /dev/null
+++ b/win/winvnc/winvnc.bmp
Binary files differ
diff --git a/win/winvnc/winvnc.cxx b/win/winvnc/winvnc.cxx
new file mode 100644
index 00000000..2d01f893
--- /dev/null
+++ b/win/winvnc/winvnc.cxx
@@ -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
index 00000000..ec76f3f2
--- /dev/null
+++ b/win/winvnc/winvnc.dsp
@@ -0,0 +1,252 @@
+# Microsoft Developer Studio Project File - Name="winvnc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=winvnc - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "winvnc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "winvnc.mak" CFG="winvnc - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "winvnc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "winvnc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "winvnc - Win32 Debug Unicode" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "winvnc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\winvnc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# 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
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# 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"
+# SUBTRACT LINK32 /profile
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /Fo..\Release\ /Fd..\Release\winvnc /MT buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "winvnc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\winvnc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# 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
+# SUBTRACT LINK32 /profile
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /Fo..\Debug\ /Fd..\Debug\winvnc /MTd buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "winvnc - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "winvnc___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "winvnc___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\winvnc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_CONSOLE" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../Debug/winvnc4.exe" /fixed:no
+# SUBTRACT BASE LINK32 /pdb:none
+# 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
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /Fo..\Debug_Unicode /Fd..\Debug_Unicode\winvnc /MTd buildTime.cxx
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "winvnc - Win32 Release"
+# Name "winvnc - Win32 Debug"
+# Name "winvnc - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\buildTime.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ControlPanel.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\JavaViewer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ManagedListener.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\QueryConnectDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\STrayIcon.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServerService.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServerWin32.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\winvnc.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\winvnc.rc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\AddNewClientDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ControlPanel.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\JavaViewer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ManagedListener.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\QueryConnectDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\STrayIcon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServerService.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServerWin32.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\connecte.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\connected.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\icon_dis.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\common\javabin\logo150x150.gif
+# End Source File
+# Begin Source File
+
+SOURCE=.\winvnc.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\winvnc.ico
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\common\javabin\index.vnc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\common\javabin\vncviewer.jar
+# End Source File
+# Begin Source File
+
+SOURCE=.\winvnc4.exe.manifest
+# End Source File
+# End Target
+# End Project
diff --git a/win/winvnc/winvnc.ico b/win/winvnc/winvnc.ico
new file mode 100644
index 00000000..1b42416c
--- /dev/null
+++ b/win/winvnc/winvnc.ico
Binary files differ
diff --git a/win/winvnc/winvnc.rc b/win/winvnc/winvnc.rc
new file mode 100644
index 00000000..143b0d6f
--- /dev/null
+++ b/win/winvnc/winvnc.rc
@@ -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
index 00000000..69be5a04
--- /dev/null
+++ b/win/winvnc/winvnc4.exe.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+ version="4.0.0.26"
+ processorArchitecture="X86"
+ name="TightVNC.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
index 00000000..0d8f646f
--- /dev/null
+++ b/win/wm_hooks/resource.h
@@ -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
index 00000000..fd01159c
--- /dev/null
+++ b/win/wm_hooks/wm_hooks.cxx
@@ -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
index 00000000..b9198ab9
--- /dev/null
+++ b/win/wm_hooks/wm_hooks.def
@@ -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
index 00000000..65e4b866
--- /dev/null
+++ b/win/wm_hooks/wm_hooks.dsp
@@ -0,0 +1,149 @@
+# Microsoft Developer Studio Project File - Name="wm_hooks" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=wm_hooks - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "wm_hooks.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "wm_hooks.mak" CFG="wm_hooks - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "wm_hooks - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "wm_hooks - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "wm_hooks - Win32 Debug Unicode" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "wm_hooks - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "../Release"
+# PROP Intermediate_Dir "..\Release\wm_hooks"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# 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
+# 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
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# 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
+
+!ELSEIF "$(CFG)" == "wm_hooks - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../Debug"
+# PROP Intermediate_Dir "..\Debug\wm_hooks"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# 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
+# 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
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# 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
+# SUBTRACT LINK32 /profile
+
+!ELSEIF "$(CFG)" == "wm_hooks - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "wm_hooks___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "wm_hooks___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\wm_hooks"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "WM_HOOKS_EXPORTS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# 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
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# 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
+
+!ENDIF
+
+# Begin Target
+
+# Name "wm_hooks - Win32 Release"
+# Name "wm_hooks - Win32 Debug"
+# Name "wm_hooks - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\wm_hooks.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\wm_hooks.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\wm_hooks.rc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\wm_hooks.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/win/wm_hooks/wm_hooks.h b/win/wm_hooks/wm_hooks.h
new file mode 100644
index 00000000..f65412ea
--- /dev/null
+++ b/win/wm_hooks/wm_hooks.h
@@ -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
index 00000000..3f171d26
--- /dev/null
+++ b/win/wm_hooks/wm_hooks.rc
@@ -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
+