summaryrefslogtreecommitdiffstats
path: root/rfb_win32
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-18 11:08:21 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-18 11:08:21 +0000
commit8d9f5139332ca8509ab84601c53634d361ab4a2d (patch)
tree499e7ce0e3bfec1a5d374794126ef7b35565e9b2 /rfb_win32
parent265d3c8752f2e9799dab2b048dde64994f891cb6 (diff)
parent590db877c7bbadc2f95751c3a6ea6f6c93bca37a (diff)
downloadtigervnc-8d9f5139332ca8509ab84601c53634d361ab4a2d.tar.gz
tigervnc-8d9f5139332ca8509ab84601c53634d361ab4a2d.zip
Merged the changes from branch/merge-with-vnc-4.1.1, revisions 520:558.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@559 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'rfb_win32')
-rw-r--r--rfb_win32/AboutDialog.cxx8
-rw-r--r--rfb_win32/AboutDialog.h4
-rw-r--r--rfb_win32/BitmapInfo.h48
-rw-r--r--rfb_win32/CKeyboard.cxx29
-rw-r--r--rfb_win32/CKeyboard.h16
-rw-r--r--rfb_win32/CPointer.cxx42
-rw-r--r--rfb_win32/CPointer.h16
-rw-r--r--rfb_win32/CleanDesktop.cxx124
-rw-r--r--rfb_win32/CleanDesktop.h4
-rw-r--r--rfb_win32/Clipboard.cxx15
-rw-r--r--rfb_win32/Clipboard.h4
-rw-r--r--rfb_win32/CompatibleBitmap.h46
-rw-r--r--rfb_win32/ComputerName.h40
-rw-r--r--rfb_win32/CurrentUser.cxx123
-rw-r--r--rfb_win32/CurrentUser.h52
-rw-r--r--rfb_win32/DIBSectionBuffer.cxx19
-rw-r--r--rfb_win32/DIBSectionBuffer.h6
-rw-r--r--rfb_win32/DeviceContext.cxx188
-rw-r--r--rfb_win32/DeviceContext.h86
-rw-r--r--rfb_win32/DeviceFrameBuffer.cxx49
-rw-r--r--rfb_win32/DeviceFrameBuffer.h25
-rw-r--r--rfb_win32/Dialog.cxx56
-rw-r--r--rfb_win32/Dialog.h5
-rw-r--r--rfb_win32/DynamicFn.cxx45
-rw-r--r--rfb_win32/DynamicFn.h51
-rw-r--r--rfb_win32/EventManager.cxx103
-rw-r--r--rfb_win32/EventManager.h77
-rw-r--r--rfb_win32/Handle.h (renamed from rfb_win32/msvcwarning.h)33
-rw-r--r--rfb_win32/IconInfo.h44
-rw-r--r--rfb_win32/IntervalTimer.h4
-rw-r--r--rfb_win32/LaunchProcess.cxx39
-rw-r--r--rfb_win32/LaunchProcess.h30
-rw-r--r--rfb_win32/LocalMem.h45
-rw-r--r--rfb_win32/LogicalPalette.h90
-rw-r--r--rfb_win32/LowLevelKeyEvents.cxx96
-rw-r--r--rfb_win32/LowLevelKeyEvents.h49
-rw-r--r--rfb_win32/ModuleFileName.h40
-rw-r--r--rfb_win32/MonitorInfo.cxx205
-rw-r--r--rfb_win32/MonitorInfo.h72
-rw-r--r--rfb_win32/MsgBox.h63
-rw-r--r--rfb_win32/MsgWindow.cxx6
-rw-r--r--rfb_win32/MsgWindow.h6
-rw-r--r--rfb_win32/OSVersion.cxx4
-rw-r--r--rfb_win32/OSVersion.h5
-rw-r--r--rfb_win32/RegConfig.cxx141
-rw-r--r--rfb_win32/RegConfig.h54
-rw-r--r--rfb_win32/Registry.cxx70
-rw-r--r--rfb_win32/Registry.h19
-rw-r--r--rfb_win32/SDisplay.cxx664
-rw-r--r--rfb_win32/SDisplay.h92
-rw-r--r--rfb_win32/SDisplayCoreDriver.h52
-rw-r--r--rfb_win32/SDisplayCorePolling.cxx81
-rw-r--r--rfb_win32/SDisplayCorePolling.h75
-rw-r--r--rfb_win32/SDisplayCoreWMHooks.cxx74
-rw-r--r--rfb_win32/SDisplayCoreWMHooks.h68
-rw-r--r--rfb_win32/SInput.cxx29
-rw-r--r--rfb_win32/SInput.h8
-rw-r--r--rfb_win32/Security.cxx192
-rw-r--r--rfb_win32/Security.h159
-rw-r--r--rfb_win32/Service.cxx67
-rw-r--r--rfb_win32/Service.h19
-rw-r--r--rfb_win32/SocketManager.cxx331
-rw-r--r--rfb_win32/SocketManager.h81
-rw-r--r--rfb_win32/TCharArray.cxx4
-rw-r--r--rfb_win32/TCharArray.h26
-rw-r--r--rfb_win32/Threading.cxx151
-rw-r--r--rfb_win32/Threading.h154
-rw-r--r--rfb_win32/TrayIcon.h5
-rw-r--r--rfb_win32/TsSessions.cxx93
-rw-r--r--rfb_win32/TsSessions.h61
-rw-r--r--rfb_win32/WMCursor.cxx36
-rw-r--r--rfb_win32/WMCursor.h8
-rw-r--r--rfb_win32/WMHooks.cxx282
-rw-r--r--rfb_win32/WMHooks.h41
-rw-r--r--rfb_win32/WMNotifier.cxx6
-rw-r--r--rfb_win32/WMNotifier.h4
-rw-r--r--rfb_win32/WMPoller.cxx28
-rw-r--r--rfb_win32/WMPoller.h13
-rw-r--r--rfb_win32/WMShatter.cxx4
-rw-r--r--rfb_win32/WMShatter.h7
-rw-r--r--rfb_win32/WMWindowCopyRect.cxx60
-rw-r--r--rfb_win32/WMWindowCopyRect.h9
-rw-r--r--rfb_win32/Win32Util.cxx393
-rw-r--r--rfb_win32/Win32Util.h174
-rw-r--r--rfb_win32/keymap.h4
-rw-r--r--rfb_win32/rfb_win32.dsp122
86 files changed, 4090 insertions, 1983 deletions
diff --git a/rfb_win32/AboutDialog.cxx b/rfb_win32/AboutDialog.cxx
index efb15c00..030be1b3 100644
--- a/rfb_win32/AboutDialog.cxx
+++ b/rfb_win32/AboutDialog.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -43,7 +43,7 @@ void AboutDialog::initDialog() {
// Get our executable's version info
FileVersionInfo verInfo;
- SetWindowText(GetDlgItem(handle, Version), verInfo.getVerString(_T("FileVersion")));
+ SetWindowText(GetDlgItem(handle, Version), verInfo.getVerString(_T("ProductVersion")));
SetWindowText(GetDlgItem(handle, Copyright), verInfo.getVerString(_T("LegalCopyright")));
- SetWindowText(GetDlgItem(handle, Description), verInfo.getVerString(_T("FileDescription")));
+ SetWindowText(GetDlgItem(handle, Description), verInfo.getVerString(_T("ProductName")));
}
diff --git a/rfb_win32/AboutDialog.h b/rfb_win32/AboutDialog.h
index cb1713d4..0dd9d494 100644
--- a/rfb_win32/AboutDialog.h
+++ b/rfb_win32/AboutDialog.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/BitmapInfo.h b/rfb_win32/BitmapInfo.h
new file mode 100644
index 00000000..6a6f0d24
--- /dev/null
+++ b/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/rfb_win32/CKeyboard.cxx b/rfb_win32/CKeyboard.cxx
index ad852a0e..28aceab7 100644
--- a/rfb_win32/CKeyboard.cxx
+++ b/rfb_win32/CKeyboard.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -24,7 +24,6 @@
#include <rfb/keysymdef.h>
#include <rfb_win32/CKeyboard.h>
-#include <rfb/CMsgWriter.h>
#include <rfb/LogWriter.h>
#include <rfb_win32/OSVersion.h>
#include "keymap.h"
@@ -67,7 +66,7 @@ private:
class ModifierKeyReleaser {
public:
- ModifierKeyReleaser(CMsgWriter* writer_, int vkCode, bool extended)
+ ModifierKeyReleaser(InputHandler* writer_, int vkCode, bool extended)
: writer(writer_), extendedVkey(vkCode + (extended ? 256 : 0)),
keysym(0)
{}
@@ -76,17 +75,17 @@ public:
keysym = (*downKeysym)[extendedVkey];
vlog.debug("fake release extendedVkey 0x%x, keysym 0x%x",
extendedVkey, keysym);
- writer->writeKeyEvent(keysym, false);
+ writer->keyEvent(keysym, false);
}
}
~ModifierKeyReleaser() {
if (keysym) {
vlog.debug("fake press extendedVkey 0x%x, keysym 0x%x",
extendedVkey, keysym);
- writer->writeKeyEvent(keysym, true);
+ writer->keyEvent(keysym, true);
}
}
- CMsgWriter* writer;
+ InputHandler* writer;
int extendedVkey;
rdr::U32 keysym;
};
@@ -96,7 +95,7 @@ public:
#define IS_PRINTABLE_LATIN1(c) (((c) >= 32 && (c) <= 126) || (c) == 128 || \
((c) >= 160 && (c) <= 255))
-void win32::CKeyboard::keyEvent(CMsgWriter* writer, rdr::U8 vkey,
+void win32::CKeyboard::keyEvent(InputHandler* writer, rdr::U8 vkey,
rdr::U32 flags, bool down)
{
bool extended = (flags & 0x1000000);
@@ -212,11 +211,11 @@ void win32::CKeyboard::keyEvent(CMsgWriter* writer, rdr::U8 vkey,
// releaseAllKeys() - write key release events to the server for all keys
// that are currently regarded as being down.
-void win32::CKeyboard::releaseAllKeys(CMsgWriter* writer) {
+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->writeKeyEvent((*i).second, false);
+ writer->keyEvent((*i).second, false);
downKeysym.erase(i);
}
}
@@ -225,12 +224,12 @@ void win32::CKeyboard::releaseAllKeys(CMsgWriter* writer) {
// 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(CMsgWriter* writer, int extendedVkey)
+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->writeKeyEvent(downKeysym[extendedVkey], false);
+ writer->keyEvent(downKeysym[extendedVkey], false);
downKeysym.erase(extendedVkey);
}
}
@@ -242,18 +241,18 @@ void win32::CKeyboard::releaseKey(CMsgWriter* writer, int extendedVkey)
// 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(CMsgWriter* writer, int extendedVkey,
+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->writeKeyEvent(downKeysym[extendedVkey], false);
+ writer->keyEvent(downKeysym[extendedVkey], false);
}
}
vlog.debug("press extendedVkey 0x%x, keysym 0x%x",
extendedVkey, keysym);
- writer->writeKeyEvent(keysym, true);
+ writer->keyEvent(keysym, true);
downKeysym[extendedVkey] = keysym;
}
diff --git a/rfb_win32/CKeyboard.h b/rfb_win32/CKeyboard.h
index 10346ffc..666ebce5 100644
--- a/rfb_win32/CKeyboard.h
+++ b/rfb_win32/CKeyboard.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -23,25 +23,23 @@
#ifndef __RFB_WIN32_CKEYBOARD_H__
#define __RFB_WIN32_CKEYBOARD_H__
-#include <rdr/types.h>
+#include <rfb/InputHandler.h>
#include <map>
namespace rfb {
- class CMsgWriter;
-
namespace win32 {
class CKeyboard {
public:
- void keyEvent(CMsgWriter* writer, rdr::U8 vkey, rdr::U32 flags,
+ void keyEvent(InputHandler* writer, rdr::U8 vkey, rdr::U32 flags,
bool down);
- void releaseAllKeys(CMsgWriter* writer);
+ 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(CMsgWriter* writer, int extendedVkey);
- void win32::CKeyboard::pressKey(CMsgWriter* writer, int extendedVkey,
+ 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;
};
diff --git a/rfb_win32/CPointer.cxx b/rfb_win32/CPointer.cxx
index 1cab662a..3d0d9342 100644
--- a/rfb_win32/CPointer.cxx
+++ b/rfb_win32/CPointer.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -16,9 +16,7 @@
* USA.
*/
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
#include <rfb/LogWriter.h>
#include <rfb_win32/CPointer.h>
@@ -37,21 +35,21 @@ CPointer::~CPointer() {
}
-void CPointer::pointerEvent(CMsgWriter* writer, int x, int y, int buttonMask) {
+void CPointer::pointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
//
// - Duplicate Event Filtering
//
bool maskChanged = buttonMask != currButtonMask;
- bool posChanged = !Point(x, y).equals(currPos);
+ bool posChanged = !pos.equals(currPos);
if (!(posChanged || maskChanged))
return;
// Pass on the event to the event-interval handler
- threePointerEvent(writer, x, y, buttonMask);
+ threePointerEvent(writer, pos, buttonMask);
// Save the position and mask
- currPos = Point(x, y);
+ currPos = pos;
currButtonMask = buttonMask;
}
@@ -66,7 +64,7 @@ int emulate3Mask(int buttonMask) {
return buttonMask;
}
-void CPointer::threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMask) {
+void CPointer::threePointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
//
// - 3-Button Mouse Emulation
//
@@ -84,7 +82,7 @@ void CPointer::threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMas
// expires then we know we should actually send this event
vlog.debug("emulate3: start timer");
threeTimer.start(100);
- threePos = Point(x, y);
+ threePos = pos;
threeMask = buttonMask;
return;
@@ -94,7 +92,7 @@ void CPointer::threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMas
vlog.debug("emulate3: stop timer (state)");
threeTimer.stop();
if (threeEmulating == ((buttonMask & 5) == 5))
- intervalPointerEvent(writer, threePos.x, threePos.y, threeMask);
+ intervalPointerEvent(writer, threePos, threeMask);
else
threeEmulating = ((buttonMask & 5) == 5);
}
@@ -104,11 +102,11 @@ void CPointer::threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMas
if (threeTimer.isActive()) {
// - We are timing for an emulation event
- if (abs(threePos.x - x) <= 4 || abs(threePos.y - y) <= 4) {
+ 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.x, threePos.y, threeMask);
+ intervalPointerEvent(writer, threePos, threeMask);
} else {
// Otherwise, we ignore the new event
@@ -129,14 +127,14 @@ void CPointer::threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMas
}
// - Let the event pass through to the next stage of processing
- intervalPointerEvent(writer, x, y, buttonMask);
+ intervalPointerEvent(writer, pos, buttonMask);
}
-void CPointer::intervalPointerEvent(CMsgWriter* writer, int x, int y, int buttonMask) {
+void CPointer::intervalPointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
//
// - Pointer Event Interval
//
- vlog.write(101, "ptrEvent: %d,%d (%lx)", x, y, buttonMask);
+ 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();
@@ -145,14 +143,14 @@ void CPointer::intervalPointerEvent(CMsgWriter* writer, int x, int y, int button
// If the buttons have changed then flush queued events and send now
sendNow = true;
if (intervalQueued)
- writer->writePointerEvent(intervalPos.x, intervalPos.y, intervalMask);
+ writer->pointerEvent(intervalPos, intervalMask);
intervalQueued = false;
}
if (!sendNow) {
// If we're not sending now then just queue the event
intervalQueued = true;
- intervalPos = Point(x, y);
+ intervalPos = pos;
intervalMask = buttonMask;
} else {
// Start the interval timer if required, and send the event
@@ -160,15 +158,15 @@ void CPointer::intervalPointerEvent(CMsgWriter* writer, int x, int y, int button
intervalMask = buttonMask;
if (pointerEventInterval)
intervalTimer.start(pointerEventInterval);
- writer->writePointerEvent(x, y, buttonMask);
+ writer->pointerEvent(pos, buttonMask);
}
}
-void CPointer::handleTimer(CMsgWriter* writer, int timerId) {
+void CPointer::handleTimer(InputHandler* writer, int timerId) {
if (timerId == intervalTimer.getId()) {
// Pointer interval has expired - send any queued events
if (intervalQueued) {
- writer->writePointerEvent(intervalPos.x, intervalPos.y, intervalMask);
+ writer->pointerEvent(intervalPos, intervalMask);
intervalQueued = false;
} else {
intervalTimer.stop();
@@ -183,6 +181,6 @@ void CPointer::handleTimer(CMsgWriter* writer, int timerId) {
if (threeEmulating)
threeMask = emulate3Mask(threeMask);
- intervalPointerEvent(writer, threePos.x, threePos.y, threeMask);
+ intervalPointerEvent(writer, threePos, threeMask);
}
}
diff --git a/rfb_win32/CPointer.h b/rfb_win32/CPointer.h
index f111de74..b5916010 100644
--- a/rfb_win32/CPointer.h
+++ b/rfb_win32/CPointer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,14 +25,12 @@
#include <rdr/Exception.h>
#include <rfb/Configuration.h>
-#include <rfb/CMsgWriter.h>
+#include <rfb/InputHandler.h>
#include <rfb/Rect.h>
#include <rfb_win32/IntervalTimer.h>
namespace rfb {
- class CMsgWriter;
-
namespace win32 {
class CPointer {
@@ -40,8 +38,8 @@ namespace rfb {
CPointer();
~CPointer();
- void pointerEvent(CMsgWriter* writer, int x, int y, int buttonMask);
- void handleTimer(CMsgWriter* writer, int timerId);
+ 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);}
@@ -56,13 +54,13 @@ namespace rfb {
bool emulate3;
int pointerEventInterval;
- void intervalPointerEvent(CMsgWriter* writer, int x, int y, int buttonMask);
+ void intervalPointerEvent(InputHandler* writer, const Point& pos, int buttonMask);
IntervalTimer intervalTimer;
bool intervalQueued;
Point intervalPos;
int intervalMask;
- void threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMask);
+ void threePointerEvent(InputHandler* writer, const Point& pos, int buttonMask);
IntervalTimer threeTimer;
Point threePos;
int threeMask;
diff --git a/rfb_win32/CleanDesktop.cxx b/rfb_win32/CleanDesktop.cxx
index 9fb83478..39cca119 100644
--- a/rfb_win32/CleanDesktop.cxx
+++ b/rfb_win32/CleanDesktop.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -18,16 +18,22 @@
// -=- CleanDesktop.cxx
-#define WIN32_LEAN_AND_MEAN
#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;
@@ -47,37 +53,93 @@ struct 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_) {
- // - Get the current Active Desktop options
+ 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);
- HRESULT result = handle->GetDesktopItemOptions(&adOptions, 0);
- if (result != S_OK) {
- vlog.error("failed to get Active Desktop options: %d", result);
+ // 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 Active Desktop is active, disable it
- if ((adOptions.fActiveDesktop==0) != (enable_==0)) {
- if (enable_)
- vlog.debug("enabling Active Desktop");
- else
- vlog.debug("disabling Active Desktop");
-
- adOptions.fActiveDesktop = enable_;
- result = handle->SetDesktopItemOptions(&adOptions, 0);
- if (result != S_OK) {
- vlog.error("failed to disable ActiveDesktop: %d", result);
+ 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;
}
- handle->ApplyChanges(AD_APPLY_REFRESH);
- return true;
+ for (unsigned int i=0; i<itemCount; i++) {
+ if (enableItem(i, false))
+ restoreItems.insert(i);
+ }
}
- return false;
+
+ // - 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;
};
@@ -91,7 +153,8 @@ DWORD SysParamsInfo(UINT action, UINT param, PVOID ptr, UINT ini) {
}
-CleanDesktop::CleanDesktop() : restoreActiveDesktop(false), restoreWallpaper(false), restoreEffects(false) {
+CleanDesktop::CleanDesktop() : restoreActiveDesktop(false), restoreWallpaper(false),
+ restorePattern(false), restoreEffects(false) {
CoInitialize(0);
}
@@ -194,13 +257,13 @@ void CleanDesktop::enablePattern() {
void CleanDesktop::disableEffects() {
-#if (WINVER >= 0x500)
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);
@@ -214,21 +277,23 @@ void CleanDesktop::disableEffects() {
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());
}
-#else
- vlog.info("disableffects not implemented");
-#endif
}
void CleanDesktop::enableEffects() {
try {
if (restoreEffects) {
-#if (WINVER >= 0x500)
ImpersonateCurrentUser icu;
vlog.debug("restore desktop effects");
@@ -236,6 +301,7 @@ void CleanDesktop::enableEffects() {
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);
@@ -245,7 +311,7 @@ void CleanDesktop::enableEffects() {
}
restoreEffects = false;
#else
- vlog.info("enableEffects not implemented");
+ vlog.info(" not supported");
#endif
}
diff --git a/rfb_win32/CleanDesktop.h b/rfb_win32/CleanDesktop.h
index 73f41534..22e246fa 100644
--- a/rfb_win32/CleanDesktop.h
+++ b/rfb_win32/CleanDesktop.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/Clipboard.cxx b/rfb_win32/Clipboard.cxx
index 867f885d..a4c43f04 100644
--- a/rfb_win32/Clipboard.cxx
+++ b/rfb_win32/Clipboard.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -61,15 +61,16 @@ unix2dos(const char* text) {
//
-// -=- ASCII filter (in-place)
+// -=- ISO-8859-1 (Latin 1) filter (in-place)
//
void
-removeNonAsciiChars(char* text) {
+removeNonISOLatin1Chars(char* text) {
int len = strlen(text);
int i=0, j=0;
for (; i<len; i++) {
- if ((text[i] >= 1) && (text[i] <= 127))
+ if (((text[i] >= 1) && (text[i] <= 127)) ||
+ ((text[i] >= 160) && (text[i] <= 255)))
text[j++] = text[i];
}
text[j] = 0;
@@ -126,7 +127,7 @@ Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
} else {
CharArray unix_text;
unix_text.buf = dos2unix(clipdata);
- // removeNonAsciiChars(unix_text.buf);
+ removeNonISOLatin1Chars(unix_text.buf);
notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf));
}
} else {
@@ -162,7 +163,7 @@ Clipboard::setClipText(const char* text) {
// - Pre-process the supplied clipboard text into DOS format
CharArray dos_text;
dos_text.buf = unix2dos(text);
- // removeNonAsciiChars(dos_text.buf);
+ removeNonISOLatin1Chars(dos_text.buf);
int dos_text_len = strlen(dos_text.buf);
// - Allocate global memory for the data
diff --git a/rfb_win32/Clipboard.h b/rfb_win32/Clipboard.h
index 57297e1e..b79768f6 100644
--- a/rfb_win32/Clipboard.h
+++ b/rfb_win32/Clipboard.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/CompatibleBitmap.h b/rfb_win32/CompatibleBitmap.h
new file mode 100644
index 00000000..4beed8dc
--- /dev/null
+++ b/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/rfb_win32/ComputerName.h b/rfb_win32/ComputerName.h
new file mode 100644
index 00000000..110caa59
--- /dev/null
+++ b/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/rfb_win32/CurrentUser.cxx b/rfb_win32/CurrentUser.cxx
index 1a244853..7562d29b 100644
--- a/rfb_win32/CurrentUser.cxx
+++ b/rfb_win32/CurrentUser.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -18,48 +18,98 @@
// -=- Currentuser.cxx
-#include <windows.h>
-#include <lmcons.h>
+#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");
-CurrentUserToken::CurrentUserToken() : isValid_(false) {
- // - If the OS doesn't support security, ignore it
- if (!isServiceProcess()) {
- // - Running in User-Mode - just get our current token
- if (!OpenProcessToken(GetCurrentProcess(), GENERIC_ALL, &h)) {
- DWORD err = GetLastError();
- if (err != ERROR_CALL_NOT_IMPLEMENTED)
- throw rdr::SystemException("OpenProcessToken failed", GetLastError());
+
+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;
}
- isValid_ = true;
- } else {
- // - Under XP/2003 and above, we can just ask the operating system
+
+ // 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);
- isValid_ = true;
- } else {
- // - Under NT/2K we have to resort to a nasty hack...
- HWND tray = FindWindow(_T("Shell_TrayWnd"), 0);
- if (!tray)
- return;
- DWORD processId = 0;
- GetWindowThreadProcessId(tray, &processId);
- if (!processId)
- return;
- Handle process = OpenProcess(MAXIMUM_ALLOWED, FALSE, processId);
- if (!process.h)
- return;
- OpenProcessToken(process, MAXIMUM_ALLOWED, &h);
- isValid_ = true;
+ 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;
}
}
@@ -68,8 +118,8 @@ ImpersonateCurrentUser::ImpersonateCurrentUser() {
RegCloseKey(HKEY_CURRENT_USER);
if (!isServiceProcess())
return;
- if (!token.isValid())
- throw rdr::Exception("CurrentUserToken is not valid");
+ if (!token.canImpersonate())
+ throw rdr::Exception("Cannot impersonate unsafe or null token");
if (!ImpersonateLoggedOnUser(token)) {
DWORD err = GetLastError();
if (err != ERROR_CALL_NOT_IMPLEMENTED)
@@ -83,6 +133,7 @@ ImpersonateCurrentUser::~ImpersonateCurrentUser() {
if (err != ERROR_CALL_NOT_IMPLEMENTED)
exit(err);
}
+ RegCloseKey(HKEY_CURRENT_USER);
}
@@ -91,3 +142,11 @@ UserName::UserName() : TCharArray(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/rfb_win32/CurrentUser.h b/rfb_win32/CurrentUser.h
index 469946b6..794f27c6 100644
--- a/rfb_win32/CurrentUser.h
+++ b/rfb_win32/CurrentUser.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -26,29 +26,41 @@
#ifndef __RFB_WIN32_CURRENT_USER_H__
#define __RFB_WIN32_CURRENT_USER_H__
-#include <rfb_win32/Service.h>
-#include <rfb_win32/OSVersion.h>
-#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/Handle.h>
+#include <rfb_win32/Security.h>
namespace rfb {
namespace win32 {
// CurrentUserToken
- // h == 0
- // if platform is not NT *or* unable to get token
- // *or* if process is hosting service.
- // h != 0
- // if process is hosting service *and*
- // if platform is NT *and* able to get token.
- // isValid() == true
- // if platform is not NT *or* token is valid.
+ // 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 isValid() const {return isValid_;};
+ bool isSafe() const { return isSafe_; };
+ bool canImpersonate() const { return h && isSafe(); }
+ bool noUserLoggedOn() const { return !h && isSafe(); }
private:
- bool isValid_;
+ bool isSafe_;
};
// ImpersonateCurrentUser
@@ -66,11 +78,21 @@ namespace rfb {
// 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();
+ };
+
}
}
diff --git a/rfb_win32/DIBSectionBuffer.cxx b/rfb_win32/DIBSectionBuffer.cxx
index 026e5ed4..18ce3ea4 100644
--- a/rfb_win32/DIBSectionBuffer.cxx
+++ b/rfb_win32/DIBSectionBuffer.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -15,16 +15,16 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
-#include <rfb/LogWriter.h>
#include <rfb_win32/DIBSectionBuffer.h>
-#include <rfb_win32/Win32Util.h>
-
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/BitmapInfo.h>
+#include <rfb/LogWriter.h>
using namespace rfb;
using namespace win32;
-static LogWriter vlog("DIBSection");
+static LogWriter vlog("DIBSectionBuffer");
DIBSectionBuffer::DIBSectionBuffer(HWND window_)
@@ -53,7 +53,7 @@ void DIBSectionBuffer::setPF(const PixelFormat& pf) {
format = pf;
recreateBuffer();
if ((pf.bpp <= 8) && pf.trueColour) {
- vlog.debug("creating %d-bit TrueColor palette", pf.depth);
+ 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;
@@ -114,8 +114,6 @@ void DIBSectionBuffer::recreateBuffer() {
bi.mask.green = format.greenMax << format.greenShift;
bi.mask.blue = format.blueMax << format.blueShift;
- vlog.debug("area=%d, bpp=%d", width_ * height_, format.bpp);
-
// Create a DIBSection to draw into
if (device)
new_bitmap = ::CreateDIBSection(device, (BITMAPINFO*)&bi.bmiHeader, iUsage,
@@ -199,10 +197,13 @@ void DIBSectionBuffer::recreateBuffer() {
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();
}
+
}
}
diff --git a/rfb_win32/DIBSectionBuffer.h b/rfb_win32/DIBSectionBuffer.h
index 51e2da31..ad1a310c 100644
--- a/rfb_win32/DIBSectionBuffer.h
+++ b/rfb_win32/DIBSectionBuffer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,9 +25,7 @@
#ifndef __RFB_WIN32_DIB_SECTION_BUFFER_H__
#define __RFB_WIN32_DIB_SECTION_BUFFER_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
#include <rfb/PixelBuffer.h>
#include <rfb/Region.h>
#include <rfb/ColourMap.h>
diff --git a/rfb_win32/DeviceContext.cxx b/rfb_win32/DeviceContext.cxx
new file mode 100644
index 00000000..4f70a1bf
--- /dev/null
+++ b/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/rfb_win32/DeviceContext.h b/rfb_win32/DeviceContext.h
new file mode 100644
index 00000000..9d91cec2
--- /dev/null
+++ b/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/rfb_win32/DeviceFrameBuffer.cxx b/rfb_win32/DeviceFrameBuffer.cxx
index 70975c37..8da894e0 100644
--- a/rfb_win32/DeviceFrameBuffer.cxx
+++ b/rfb_win32/DeviceFrameBuffer.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -21,25 +21,22 @@
// The DeviceFrameBuffer class encapsulates the pixel data of the system
// display.
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <assert.h>
-
#include <vector>
-
-#include <rfb/LogWriter.h>
-#include <rfb/Exception.h>
-#include <rdr/types.h>
-#include <rfb/VNCServer.h>
#include <rfb_win32/DeviceFrameBuffer.h>
-#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/DeviceContext.h>
#include <rfb_win32/OSVersion.h>
+#include <rfb_win32/IconInfo.h>
+#include <rfb/VNCServer.h>
+#include <rfb/LogWriter.h>
-namespace rfb {
+using namespace rfb;
+using namespace win32;
-namespace win32 {
+static LogWriter vlog("DeviceFrameBuffer");
-static LogWriter vlog("FrameBuffer");
+BoolParameter DeviceFrameBuffer::useCaptureBlt("UseCaptureBlt",
+ "Use a slower capture method that ensures that alpha blended windows appear correctly",
+ true);
// -=- DeviceFrameBuffer class
@@ -67,10 +64,7 @@ DeviceFrameBuffer::DeviceFrameBuffer(HDC deviceContext, const Rect& wRect)
// -=- Get the display dimensions and pixel format
// Get the display dimensions
- RECT cr;
- if (!GetClipBox(device, &cr))
- throw rdr::SystemException("GetClipBox", GetLastError());
- deviceCoords = Rect(cr.left, cr.top, cr.right, cr.bottom);
+ deviceCoords = DeviceContext::getClipBox(device);
if (!wRect.is_empty())
deviceCoords = wRect.translate(deviceCoords.tl);
int w = deviceCoords.width();
@@ -120,7 +114,7 @@ DeviceFrameBuffer::grabRect(const Rect &rect) {
// 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 ? CAPTUREBLT | SRCCOPY : SRCCOPY)) {
+ (osVersion.isPlatformNT && useCaptureBlt) ? (CAPTUREBLT | SRCCOPY) : SRCCOPY)) {
if (ignoreGrabErrors)
vlog.error("BitBlt failed:%ld", GetLastError());
else
@@ -176,7 +170,7 @@ 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, 0, 0, 0, 0);
+ server->setCursor(0, 0, Point(), 0, 0);
return;
}
@@ -189,8 +183,10 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
BITMAP maskInfo;
if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), &maskInfo))
throw rdr::SystemException("GetObject() failed", GetLastError());
-
- assert(maskInfo.bmPlanes == 1 && maskInfo.bmBitsPixel == 1);
+ 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
@@ -278,8 +274,7 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
memcpy(cursorBm.data, cursor.data, cursor.dataLen());
}
- server->setCursor(cursor.width(), cursor.height(),
- cursor.hotspot.x, cursor.hotspot.y,
+ server->setCursor(cursor.width(), cursor.height(), cursor.hotspot,
cursorBm.data, cursor.mask.buf);
} catch (rdr::Exception& e) {
vlog.error(e.str());
@@ -292,7 +287,3 @@ DeviceFrameBuffer::updateColourMap() {
if (!format.trueColour)
copyDevicePaletteToDIB(device, this);
}
-
-}; // namespace win32
-
-}; // namespace rfb
diff --git a/rfb_win32/DeviceFrameBuffer.h b/rfb_win32/DeviceFrameBuffer.h
index 5e97b222..7718c339 100644
--- a/rfb_win32/DeviceFrameBuffer.h
+++ b/rfb_win32/DeviceFrameBuffer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -26,13 +26,12 @@
#ifndef __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
#define __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
-#define WIN32_LEAN_AND_MEAN
#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 {
@@ -85,6 +84,8 @@ namespace rfb {
// 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
@@ -98,22 +99,6 @@ namespace rfb {
bool ignoreGrabErrors;
};
- // -=- createDisplayDeviceFrameBuffer
- // createDisplayDeviceFrameBuffer must be passed the name of a display device,
- // and will return a new FrameBuffer object attached to that display
- // device.
- // If the device name is not specified then the default display is
- // returned.
-
- DeviceFrameBuffer *createDisplayDeviceFrameBuffer(const char *device=0);
-
- // -=- createDisplayFrameBuffers
- // Creates a set of framebuffers, one for each available display
- // device.
-
- typedef std::vector<DeviceFrameBuffer *> DeviceFrameBuffers;
- void createDisplayDeviceFrameBuffers(DeviceFrameBuffers *fbs);
-
};
};
diff --git a/rfb_win32/Dialog.cxx b/rfb_win32/Dialog.cxx
index 157cf5fe..398334f0 100644
--- a/rfb_win32/Dialog.cxx
+++ b/rfb_win32/Dialog.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,9 +25,15 @@
#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;
@@ -208,6 +214,33 @@ 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;
@@ -227,7 +260,8 @@ bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, boo
// Initialise and create the PropertySheet itself
PROPSHEETHEADER header;
header.dwSize = PROPSHEETHEADER_V1_SIZE;
- header.dwFlags = PSH_MODELESS | (showApply ? 0 : PSH_NOAPPLYNOW) /*| (showCtxtHelp ? 0 : PSH_NOCONTEXTHELP)*/;
+ 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;
@@ -245,9 +279,7 @@ bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, boo
centerWindow(handle, owner);
plog.info("created %lx", handle);
-#if (WINVER >= 0x0500)
#ifdef _DIALOG_CAPTURE
- // *** NOT TESTED
if (capture) {
plog.info("capturing \"%s\"", (const char*)CStr(title.buf));
char* tmpdir = getenv("TEMP");
@@ -264,15 +296,23 @@ bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, boo
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\\capture%d.bmp", tmpdir, i);
+ sprintf(filename, "%s\\%s.bmp", tmpdir, pageTitle.buf);
+ vlog.debug("writing to %s", filename);
saveBMP(filename, &fb);
i++;
}
ReleaseDC(handle, dc);
} else {
#endif
-#endif
try {
if (owner)
EnableWindow(owner, FALSE);
@@ -291,11 +331,9 @@ bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, boo
EnableWindow(owner, TRUE);
throw;
}
-#if (WINVER >= 0x0500)
#ifdef _DIALOG_CAPTURE
}
#endif
-#endif
plog.info("finished %lx", handle);
diff --git a/rfb_win32/Dialog.h b/rfb_win32/Dialog.h
index d46133a0..9784ba46 100644
--- a/rfb_win32/Dialog.h
+++ b/rfb_win32/Dialog.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -24,7 +24,6 @@
#ifndef __RFB_WIN32_DIALOG_H__
#define __RFB_WIN32_DIALOG_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <prsht.h>
#include <list>
diff --git a/rfb_win32/DynamicFn.cxx b/rfb_win32/DynamicFn.cxx
new file mode 100644
index 00000000..e933f249
--- /dev/null
+++ b/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/rfb_win32/DynamicFn.h b/rfb_win32/DynamicFn.h
new file mode 100644
index 00000000..57fdbec5
--- /dev/null
+++ b/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/rfb_win32/EventManager.cxx b/rfb_win32/EventManager.cxx
new file mode 100644
index 00000000..0f9993b7
--- /dev/null
+++ b/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/rfb_win32/EventManager.h b/rfb_win32/EventManager.h
new file mode 100644
index 00000000..bb66e340
--- /dev/null
+++ b/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/rfb_win32/msvcwarning.h b/rfb_win32/Handle.h
index e50d9c1a..d3baa580 100644
--- a/rfb_win32/msvcwarning.h
+++ b/rfb_win32/Handle.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -15,6 +15,29 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
-#pragma warning( disable : 4244 ) // loss of data e.g. int to char
-#pragma warning( disable : 4800 ) // forcing bool 'true' or 'false'
-#pragma warning( disable : 4786 ) // debug info truncated
+
+// 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/rfb_win32/IconInfo.h b/rfb_win32/IconInfo.h
new file mode 100644
index 00000000..cb33a42d
--- /dev/null
+++ b/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/rfb_win32/IntervalTimer.h b/rfb_win32/IntervalTimer.h
index 645d0ee9..ddfae493 100644
--- a/rfb_win32/IntervalTimer.h
+++ b/rfb_win32/IntervalTimer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/LaunchProcess.cxx b/rfb_win32/LaunchProcess.cxx
index 0a48d60c..56a712e6 100644
--- a/rfb_win32/LaunchProcess.cxx
+++ b/rfb_win32/LaunchProcess.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -19,9 +19,10 @@
// -=- LaunchProcess.cxx
#include <rfb_win32/LaunchProcess.h>
+#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Win32Util.h>
-
-#include <rfb/util.h>
+#include <rdr/Exception.h>
+#include <stdio.h>
using namespace rfb;
using namespace win32;
@@ -37,10 +38,11 @@ LaunchProcess::~LaunchProcess() {
}
-void LaunchProcess::start(HANDLE userToken) {
+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;
@@ -58,19 +60,15 @@ void LaunchProcess::start(HANDLE userToken) {
exePath.buf = tstrDup(exeName.buf);
}
- // - Start the VNC server
+ // - 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);
-#ifdef _DEBUG
- DWORD flags = CREATE_NEW_CONSOLE;
-#else
- DWORD flags = CREATE_NO_WINDOW;
-#endif
+ DWORD flags = createConsole ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW;
BOOL success;
- if (userToken)
+ 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);
@@ -81,12 +79,25 @@ void LaunchProcess::start(HANDLE userToken) {
WaitForInputIdle(procInfo.hProcess, 15000);
}
-void LaunchProcess::await() {
+void LaunchProcess::detach()
+{
if (!procInfo.hProcess)
return;
- WaitForSingleObject(procInfo.hProcess, INFINITE);
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/rfb_win32/LaunchProcess.h b/rfb_win32/LaunchProcess.h
index 6fd34e9c..38521dcd 100644
--- a/rfb_win32/LaunchProcess.h
+++ b/rfb_win32/LaunchProcess.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -24,9 +24,7 @@
#ifndef __RFB_WIN32_LAUNCHPROCESS_H__
#define __RFB_WIN32_LAUNCHPROCESS_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
#include <rfb_win32/TCharArray.h>
namespace rfb {
@@ -38,14 +36,28 @@ namespace rfb {
LaunchProcess(const TCHAR* exeName_, const TCHAR* params);
~LaunchProcess();
- // If userToken is 0 then starts as current user, otherwise
- // starts as the specified user. userToken must be a primary token.
- void start(HANDLE userToken);
+ // 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, and close the handles to it.
- void await();
+ // 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;
diff --git a/rfb_win32/LocalMem.h b/rfb_win32/LocalMem.h
new file mode 100644
index 00000000..a99d3241
--- /dev/null
+++ b/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/rfb_win32/LogicalPalette.h b/rfb_win32/LogicalPalette.h
new file mode 100644
index 00000000..204f1081
--- /dev/null
+++ b/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/rfb_win32/LowLevelKeyEvents.cxx b/rfb_win32/LowLevelKeyEvents.cxx
new file mode 100644
index 00000000..322d1f40
--- /dev/null
+++ b/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/rfb_win32/LowLevelKeyEvents.h b/rfb_win32/LowLevelKeyEvents.h
new file mode 100644
index 00000000..40d2ecfa
--- /dev/null
+++ b/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/rfb_win32/ModuleFileName.h b/rfb_win32/ModuleFileName.h
new file mode 100644
index 00000000..2264e89d
--- /dev/null
+++ b/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/rfb_win32/MonitorInfo.cxx b/rfb_win32/MonitorInfo.cxx
new file mode 100644
index 00000000..03772e97
--- /dev/null
+++ b/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/rfb_win32/MonitorInfo.h b/rfb_win32/MonitorInfo.h
new file mode 100644
index 00000000..acf27755
--- /dev/null
+++ b/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/rfb_win32/MsgBox.h b/rfb_win32/MsgBox.h
new file mode 100644
index 00000000..59571395
--- /dev/null
+++ b/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/rfb_win32/MsgWindow.cxx b/rfb_win32/MsgWindow.cxx
index 519d6ab9..95bd5237 100644
--- a/rfb_win32/MsgWindow.cxx
+++ b/rfb_win32/MsgWindow.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -113,4 +113,4 @@ MsgWindow::~MsgWindow() {
LRESULT
MsgWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
return SafeDefWindowProc(getHandle(), msg, wParam, lParam);
-} \ No newline at end of file
+}
diff --git a/rfb_win32/MsgWindow.h b/rfb_win32/MsgWindow.h
index 94baca38..92b6cf20 100644
--- a/rfb_win32/MsgWindow.h
+++ b/rfb_win32/MsgWindow.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -24,9 +24,7 @@
#ifndef __RFB_WIN32_MSG_WINDOW_H__
#define __RFB_WIN32_MSG_WINDOW_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
#include <rfb_win32/TCharArray.h>
namespace rfb {
diff --git a/rfb_win32/OSVersion.cxx b/rfb_win32/OSVersion.cxx
index 1976098f..3d74c956 100644
--- a/rfb_win32/OSVersion.cxx
+++ b/rfb_win32/OSVersion.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/OSVersion.h b/rfb_win32/OSVersion.h
index 1d529431..18ec003e 100644
--- a/rfb_win32/OSVersion.h
+++ b/rfb_win32/OSVersion.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -27,7 +27,6 @@
#ifndef __RFB_WIN32_OS_VERSION_H__
#define __RFB_WIN32_OS_VERSION_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace rfb {
diff --git a/rfb_win32/RegConfig.cxx b/rfb_win32/RegConfig.cxx
index fcb309b5..dd1c3b06 100644
--- a/rfb_win32/RegConfig.cxx
+++ b/rfb_win32/RegConfig.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -23,7 +23,7 @@
#include <rfb_win32/RegConfig.h>
#include <rfb/LogWriter.h>
#include <rfb/util.h>
-#include <rdr/HexOutStream.h>
+//#include <rdr/HexOutStream.h>
using namespace rfb;
using namespace rfb::win32;
@@ -32,90 +32,28 @@ using namespace rfb::win32;
static LogWriter vlog("RegConfig");
-class rfb::win32::RegReaderThread : public Thread {
-public:
- RegReaderThread(RegistryReader& reader, const HKEY key);
- ~RegReaderThread();
- virtual void run();
- virtual Thread* join();
-protected:
- RegistryReader& reader;
- RegKey key;
- HANDLE event;
-};
-
-RegReaderThread::RegReaderThread(RegistryReader& reader_, const HKEY key_) : Thread("RegConfig"), reader(reader_), key(key_) {
-}
-
-RegReaderThread::~RegReaderThread() {
-}
-
-void
-RegReaderThread::run() {
- vlog.debug("RegReaderThread started");
- while (key) {
- // - Wait for changes
- vlog.debug("waiting for changes");
- key.awaitChange(true, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);
-
- // - Load settings
- RegistryReader::loadRegistryConfig(key);
-
- // - Notify specified thread of changes
- if (reader.notifyThread)
- PostThreadMessage(reader.notifyThread->getThreadId(),
- reader.notifyMsg.message,
- reader.notifyMsg.wParam,
- reader.notifyMsg.lParam);
- else if (reader.notifyWindow)
- PostMessage(reader.notifyWindow,
- reader.notifyMsg.message,
- reader.notifyMsg.wParam,
- reader.notifyMsg.lParam);
- }
-}
-
-Thread*
-RegReaderThread::join() {
- RegKey old_key = key;
- key.close();
- if ((HKEY)old_key) {
- // *** Closing the key doesn't always seem to work
- // Writing to it always will, instead...
- vlog.debug("closing key");
- old_key.setString(_T("dummy"), _T(""));
- }
- return Thread::join();
-}
-
-
-RegistryReader::RegistryReader() : thread(0), notifyThread(0) {
- memset(&notifyMsg, 0, sizeof(notifyMsg));
+RegConfig::RegConfig(EventManager* em) : eventMgr(em), event(CreateEvent(0, TRUE, FALSE, 0)), callback(0) {
+ if (em->addEvent(event, this))
+ eventMgr = em;
}
-RegistryReader::~RegistryReader() {
- if (thread) delete thread->join();
+RegConfig::~RegConfig() {
+ if (eventMgr)
+ eventMgr->removeEvent(event);
}
-bool RegistryReader::setKey(const HKEY rootkey, const TCHAR* keyname) {
- if (thread) delete thread->join();
- thread = 0;
-
- RegKey key;
+bool RegConfig::setKey(const HKEY rootkey, const TCHAR* keyname) {
try {
key.createKey(rootkey, keyname);
- loadRegistryConfig(key);
+ processEvent(event);
+ return true;
} catch (rdr::Exception& e) {
vlog.debug(e.str());
return false;
}
- thread = new RegReaderThread(*this, key);
- if (thread) thread->start();
- return true;
}
-void
-RegistryReader::loadRegistryConfig(RegKey& key) {
+void RegConfig::loadRegistryConfig(RegKey& key) {
DWORD i = 0;
try {
while (1) {
@@ -131,21 +69,46 @@ RegistryReader::loadRegistryConfig(RegKey& key) {
}
}
-bool RegistryReader::setNotifyThread(Thread* thread, UINT winMsg, WPARAM wParam, LPARAM lParam) {
- notifyMsg.message = winMsg;
- notifyMsg.wParam = wParam;
- notifyMsg.lParam = lParam;
- notifyThread = thread;
- notifyWindow = 0;
- return true;
+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();
}
-bool RegistryReader::setNotifyWindow(HWND window, UINT winMsg, WPARAM wParam, LPARAM lParam) {
- notifyMsg.message = winMsg;
- notifyMsg.wParam = wParam;
- notifyMsg.lParam = lParam;
- notifyWindow = window;
- notifyThread = 0;
- return true;
+
+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/rfb_win32/RegConfig.h b/rfb_win32/RegConfig.h
index 3fced85e..e9c01b1d 100644
--- a/rfb_win32/RegConfig.h
+++ b/rfb_win32/RegConfig.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -26,27 +26,55 @@
#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 RegistryReader {
+ class RegConfig : EventHandler {
public:
- RegistryReader();
- ~RegistryReader();
+ RegConfig(EventManager* em);
+ ~RegConfig();
+
+ // Specify the registry key to read Configuration items from
bool setKey(const HKEY rootkey, const TCHAR* keyname);
- bool setNotifyThread(Thread* thread, UINT winMsg, WPARAM wParam=0, LPARAM lParam=0);
- bool setNotifyWindow(HWND window, UINT winMsg, WPARAM wParam=0, LPARAM lParam=0);
+
+ // 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:
- friend class RegReaderThread;
- Thread* thread;
- Thread* notifyThread;
- HWND notifyWindow;
- MSG notifyMsg;
+ // 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;
};
};
diff --git a/rfb_win32/Registry.cxx b/rfb_win32/Registry.cxx
index de9238f7..4ece4bac 100644
--- a/rfb_win32/Registry.cxx
+++ b/rfb_win32/Registry.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -18,14 +18,14 @@
// -=- Registry.cxx
-#include <rfb/LogWriter.h>
#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 <rfb_win32/Security.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
@@ -69,6 +69,7 @@ RegKey::~RegKey() {
void RegKey::setHKEY(HKEY k, bool fK) {
+ vlog.debug("setHKEY(%x,%d)", k, (int)fK);
close();
freeKey = fK;
key = k;
@@ -82,6 +83,7 @@ bool RegKey::createKey(const RegKey& root, const TCHAR* name) {
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;
}
@@ -91,6 +93,8 @@ void RegKey::openKey(const RegKey& root, const TCHAR* name, bool readOnly) {
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;
}
@@ -109,6 +113,7 @@ void RegKey::setDACL(const PACL acl, bool inherit) {
void RegKey::close() {
if (freeKey) {
+ vlog.debug("RegCloseKey(%x)", key);
RegCloseKey(key);
key = 0;
}
@@ -126,8 +131,8 @@ void RegKey::deleteValue(const TCHAR* name) const {
throw rdr::SystemException("RegDeleteValue", result);
}
-void RegKey::awaitChange(bool watchSubTree, DWORD filter) const {
- LONG result = RegNotifyChangeKeyValue(key, watchSubTree, filter, 0, FALSE);
+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);
}
@@ -206,6 +211,16 @@ 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);
@@ -224,12 +239,7 @@ TCHAR* RegKey::getRepresentation(const TCHAR* valname) const {
}
case REG_SZ:
if (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.buf, length);
- str.buf[len] = 0;
- return str.takeBuf();
+ return terminateData(data.buf, length);
} else {
return tstrDup(_T(""));
}
@@ -239,6 +249,22 @@ TCHAR* RegKey::getRepresentation(const TCHAR* valname) const {
_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");
}
@@ -270,3 +296,21 @@ const TCHAR* RegKey::getValueName(int i) {
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/rfb_win32/Registry.h b/rfb_win32/Registry.h
index 1998c497..68d535cd 100644
--- a/rfb_win32/Registry.h
+++ b/rfb_win32/Registry.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -22,9 +22,7 @@
#ifndef __RFB_WIN32_REGISTRY_H__
#define __RFB_WIN32_REGISTRY_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
#include <rfb_win32/Security.h>
#include <rfb/util.h>
@@ -45,9 +43,9 @@ namespace rfb {
~RegKey();
void setHKEY(HKEY key, bool freeKey);
- protected:
- HKEY operator=(const RegKey& k);
- HKEY operator=(HKEY k);
+ private:
+ RegKey& operator=(const RegKey& k);
+ HKEY& operator=(const HKEY& k);
public:
// Returns true if key was created, false if already existed
@@ -67,7 +65,9 @@ namespace rfb {
void deleteValue(const TCHAR* name) const;
- void awaitChange(bool watchSubTree, DWORD filter) 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;
@@ -91,10 +91,11 @@ namespace rfb {
bool isValue(const TCHAR* valname) const;
- // Get the name of value number "i"
+ // 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:
diff --git a/rfb_win32/SDisplay.cxx b/rfb_win32/SDisplay.cxx
index 4916c486..0af50649 100644
--- a/rfb_win32/SDisplay.cxx
+++ b/rfb_win32/SDisplay.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -20,21 +20,19 @@
//
// The SDisplay class encapsulates a particular system display.
-#include <assert.h>
-
#include <rfb_win32/SDisplay.h>
#include <rfb_win32/Service.h>
-#include <rfb_win32/WMShatter.h>
-#include <rfb_win32/osVersion.h>
-#include <rfb_win32/Win32Util.h>
-#include <rfb_win32/IntervalTimer.h>
+#include <rfb_win32/TsSessions.h>
#include <rfb_win32/CleanDesktop.h>
-
-#include <rfb/util.h>
-#include <rfb/LogWriter.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>
-#include <rfb/Configuration.h>
using namespace rdr;
using namespace rfb;
@@ -44,209 +42,37 @@ static LogWriter vlog("SDisplay");
// - SDisplay-specific configuration options
-BoolParameter rfb::win32::SDisplay::use_hooks("UseHooks",
- "Set hooks in the operating system to capture display updates more efficiently", true);
+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 in in use.", false);
+ "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 in in use.", false);
+ "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);
-// - WM_TIMER ID values
-
-#define TIMER_CURSOR 1
-#define TIMER_UPDATE 2
-#define TIMER_UPDATE_AND_POLL 3
-
-
-// -=- Polling settings
-
-const int POLLING_SEGMENTS = 16;
-
-const int FG_POLLING_FPS = 20;
-const int FG_POLLING_FS_INTERVAL = 1000 / FG_POLLING_FPS;
-const int FG_POLLING_INTERVAL = FG_POLLING_FS_INTERVAL / POLLING_SEGMENTS;
-
-const int BG_POLLING_FS_INTERVAL = 5000;
-const int BG_POLLING_INTERVAL = BG_POLLING_FS_INTERVAL / POLLING_SEGMENTS;
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// SDisplayCore
-//
-
-// The SDisplay Core object is created by SDisplay's start() method
-// and deleted by its stop() method.
-// The Core must be created in the current input desktop in order
-// to operate - SDisplay is responsible for ensuring that.
-// The structures contained in the Core are manipulated directly
-// by the SDisplay, which is also responsible for detecting when
-// a desktop-switch is required.
-
-class rfb::win32::SDisplayCore : public MsgWindow {
-public:
- SDisplayCore(SDisplay* display);
- ~SDisplayCore();
-
- void setPixelBuffer(DeviceFrameBuffer* pb_);
-
- bool isRestartRequired();
-
- virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
-
- // -=- Timers
- IntervalTimer pollTimer;
- IntervalTimer cursorTimer;
-
- // -=- Input handling
- rfb::win32::SPointer ptr;
- rfb::win32::SKeyboard kbd;
- rfb::win32::Clipboard clipboard;
-
- // -=- Hook handling objects used outside thread run() method
- WMCopyRect wm_copyrect;
- WMPoller wm_poller;
- WMCursor cursor;
- WMMonitor wm_monitor;
- WMHooks wm_hooks;
- WMBlockInput wm_input;
-
- // -=- Tidying the desktop
- CleanDesktop cleanDesktop;
- bool isWallpaperRemoved;
- bool isPatternRemoved;
- bool areEffectsDisabled;
-
- // -=- Full screen polling
- int poll_next_y;
- int poll_y_increment;
-
- // Are we using hooks?
- bool use_hooks;
- bool using_hooks;
-
- // State of the display object
- SDisplay* display;
-};
-
-SDisplayCore::SDisplayCore(SDisplay* display_)
-: MsgWindow(_T("SDisplayCore")), display(display_),
- using_hooks(0), use_hooks(rfb::win32::SDisplay::use_hooks),
- isWallpaperRemoved(rfb::win32::SDisplay::removeWallpaper),
- isPatternRemoved(rfb::win32::SDisplay::removePattern),
- areEffectsDisabled(rfb::win32::SDisplay::disableEffects),
- pollTimer(getHandle(), TIMER_UPDATE_AND_POLL),
- cursorTimer(getHandle(), TIMER_CURSOR) {
- setPixelBuffer(display->pb);
-}
-
-SDisplayCore::~SDisplayCore() {
-}
-
-void SDisplayCore::setPixelBuffer(DeviceFrameBuffer* pb) {
- poll_y_increment = (display->pb->height()+POLLING_SEGMENTS-1)/POLLING_SEGMENTS;
- poll_next_y = display->screenRect.tl.y;
- wm_hooks.setClipRect(display->screenRect);
- wm_copyrect.setClipRect(display->screenRect);
- wm_poller.setClipRect(display->screenRect);
-}
-
-
-bool SDisplayCore::isRestartRequired() {
- // - We must restart the SDesktop if:
- // 1. We are no longer in the input desktop.
- // 2. The use_hooks setting has changed.
-
- // - Check that we are in the input desktop
- if (rfb::win32::desktopChangeRequired())
- return true;
-
- // - Check that the hooks setting hasn't changed
- // NB: We can't just check using_hooks because that can be false
- // because they failed, even though use_hooks is true!
- if (use_hooks != rfb::win32::SDisplay::use_hooks)
- 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 != rfb::win32::SDisplay::removeWallpaper) ||
- (isPatternRemoved != rfb::win32::SDisplay::removePattern) ||
- (areEffectsDisabled != rfb::win32::SDisplay::disableEffects))
- return true;
-
- return false;
-}
-
-LRESULT SDisplayCore::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
- switch (msg) {
-
- case WM_TIMER:
-
- if (display->server && display->server->clientsReadyForUpdate()) {
-
- // - Check that the SDesktop doesn't need restarting
- if (isRestartRequired()) {
- display->restart();
- return 0;
- }
-
- // - Action depends on the timer message type
- switch (wParam) {
-
- // POLL THE SCREEN
- case TIMER_UPDATE_AND_POLL:
- // Handle window dragging, polling of consoles, etc.
- while (wm_poller.processEvent()) {}
-
- // Poll the next strip of the screen (in Screen coordinates)
- {
- Rect pollrect = display->screenRect;
- if (poll_next_y >= pollrect.br.y) {
- // Yes. Reset the counter and return
- poll_next_y = pollrect.tl.y;
- } else {
- // No. Poll the next section
- pollrect.tl.y = poll_next_y;
- poll_next_y += poll_y_increment;
- pollrect.br.y = min(poll_next_y, pollrect.br.y);
- display->add_changed(pollrect);
- }
- }
- break;
-
- case TIMER_CURSOR:
- display->triggerUpdate();
- break;
-
- };
-
- }
- return 0;
-
- };
-
- return MsgWindow::processMessage(msg, wParam, lParam);
-}
-
//////////////////////////////////////////////////////////////////////////////
//
// SDisplay
//
+typedef BOOL (WINAPI *_LockWorkStation_proto)();
+DynamicFn<_LockWorkStation_proto> _LockWorkStation(_T("user32.dll"), "LockWorkStation");
+
// -=- Constructor/Destructor
-SDisplay::SDisplay(const TCHAR* devName)
- : server(0), change_tracker(true), pb(0),
- deviceName(tstrDup(devName)), device(0), releaseDevice(false),
- core(0), statusLocation(0)
+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);
}
@@ -271,168 +97,246 @@ SDisplay::~SDisplay()
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");
}
- // Clear the change tracker
- change_tracker.clear();
+ // Initialise the change tracker and clipper
+ updates.clear();
+ clipper.setUpdateTracker(server);
// Create the framebuffer object
- recreatePixelBuffer();
+ recreatePixelBuffer(true);
// Create the SDisplayCore
- core = new SDisplayCore(this);
- assert(core);
-
- // Start display monitor and clipboard handler
- core->wm_monitor.setNotifier(this);
- core->clipboard.setNotifier(this);
+ 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)
- core->cleanDesktop.disablePattern();
+ cleanDesktop->disablePattern();
if (removeWallpaper)
- core->cleanDesktop.disableWallpaper();
+ cleanDesktop->disableWallpaper();
if (disableEffects)
- core->cleanDesktop.disableEffects();
-
- // Start hooks
- core->wm_hooks.setClipRect(screenRect);
- if (core->use_hooks) {
- // core->wm_hooks.setDiagnosticRange(0, 0x400-1);
- core->using_hooks = core->wm_hooks.setUpdateTracker(this);
- if (!core->using_hooks)
- vlog.debug("hook subsystem failed to initialise");
- }
-
- // Set up timers
- core->pollTimer.start(core->using_hooks ? BG_POLLING_INTERVAL : FG_POLLING_INTERVAL);
- core->cursorTimer.start(10);
+ cleanDesktop->disableEffects();
+ isWallpaperRemoved = removeWallpaper;
+ isPatternRemoved = removePattern;
+ areEffectsDisabled = disableEffects;
+}
- // Register an interest in faked copyrect events
- core->wm_copyrect.setUpdateTracker(&change_tracker);
- core->wm_copyrect.setClipRect(screenRect);
+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);
+}
- // Polling of particular windows on the desktop
- core->wm_poller.setUpdateTracker(&change_tracker);
- core->wm_poller.setClipRect(screenRect);
- vlog.debug("started");
+bool SDisplay::areHooksAvailable() {
+ return WMHooks::areAvailable();
+}
- if (statusLocation) *statusLocation = true;
+bool SDisplay::isDriverAvailable() {
+ return SDisplayCoreDriver::isAvailable();
}
-void SDisplay::stop()
-{
- vlog.debug("stopping");
- if (core) {
- // If SDisplay was actually active then perform the disconnect action
- CharArray action = disconnectAction.getData();
- if (stricmp(action.buf, "Logoff") == 0) {
- ExitWindowsEx(EWX_LOGOFF, 0);
- } else if (stricmp(action.buf, "Lock") == 0) {
- typedef BOOL (WINAPI *_LockWorkStation_proto)();
- DynamicFn<_LockWorkStation_proto> _LockWorkStation(_T("user32.dll"), "LockWorkStation");
- if (_LockWorkStation.isValid())
- (*_LockWorkStation)();
- else
- ExitWindowsEx(EWX_LOGOFF, 0);
- }
- }
- delete core;
- core = 0;
- delete pb;
- pb = 0;
- if (device) {
- if (releaseDevice)
- ReleaseDC(0, device);
- else
- DeleteDC(device);
- }
- device = 0;
- if (server)
- server->setPixelBuffer(0);
- server = 0;
- vlog.debug("stopped");
+bool SDisplay::isRestartRequired() {
+ // - We must restart the SDesktop if:
+ // 1. We are no longer in the input desktop.
+ // 2. The any setting has changed.
- if (statusLocation) *statusLocation = false;
+ // - 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::restart() {
- vlog.debug("restarting");
- // Close down the hooks
- delete core;
- core = 0;
+
+void SDisplay::restartCore() {
+ vlog.info("restarting");
+
+ // Stop the existing Core related resources
+ stopCore();
try {
- // Re-start the hooks if possible
- start(server);
- vlog.debug("restarted");
+ // Start a new Core if possible
+ startCore();
+ vlog.info("restarted");
} catch (rdr::Exception& e) {
- // If start() fails then we MUST disconnect all clients,
- // to cause the server to stop using the desktop.
+ // 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
+ // and the server will crash.
server->closeClients(e.str());
}
}
-void SDisplay::pointerEvent(const Point& pos, rdr::U8 buttonmask) {
+void SDisplay::pointerEvent(const Point& pos, int buttonmask) {
if (pb->getRect().contains(pos)) {
Point screenPos = pos.translate(screenRect.tl);
- core->ptr.pointerEvent(screenPos, buttonmask);
+ // - 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) {
- core->kbd.keyEvent(key, 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;
- core->clipboard.setClipText(clip_sz.buf);
+ clipboard->setClipText(clip_sz.buf);
}
void SDisplay::framebufferUpdateRequest()
{
- triggerUpdate();
+ SetEvent(updateEvent);
}
Point SDisplay::getFbSize() {
bool startAndStop = !core;
+
// If not started, do minimal initialisation to get desktop size.
- if (startAndStop) recreatePixelBuffer();
+ if (startAndStop)
+ recreatePixelBuffer();
Point result = Point(pb->width(), pb->height());
+
// Destroy the initialised structures.
- if (startAndStop) stop();
+ if (startAndStop)
+ stopCore();
return result;
}
void
-SDisplay::add_changed(const Region& rgn) {
- change_tracker.add_changed(rgn);
- triggerUpdate();
-}
-
-void
-SDisplay::add_copied(const Region& dest, const Point& delta) {
- change_tracker.add_copied(dest, delta);
- triggerUpdate();
-}
-
-
-void
SDisplay::notifyClipboardChanged(const char* text, int len) {
vlog.debug("clipboard text changed");
if (server)
@@ -462,36 +366,42 @@ SDisplay::notifyDisplayEvent(WMMonitor::Notifier::DisplayEventType evt) {
}
}
-bool
+void
SDisplay::processEvent(HANDLE event) {
if (event == updateEvent) {
- vlog.info("processEvent");
+ vlog.write(120, "processEvent");
ResetEvent(updateEvent);
// - If the SDisplay isn't even started then quit now
if (!core) {
vlog.error("not start()ed");
- return true;
+ return;
}
// - Ensure that the disableLocalInputs flag is respected
- core->wm_input.blockInputs(SDisplay::disableLocalInputs);
+ 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 (core->isRestartRequired()) {
- restart();
- return true;
+ if (isRestartRequired()) {
+ restartCore();
+ return;
}
-
- // *** window dragging can be improved - more frequent, more cunning about updates
- while (core->wm_copyrect.processEvent()) {}
-
+
+ // - 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 = core->cursor.getCursorInfo();
+ 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;
@@ -505,7 +415,7 @@ SDisplay::processEvent(HANDLE event) {
// Update the cursor position
// NB: First translate from Screen coordinates to Desktop
Point desktopPos = info.position.translate(screenRect.tl.negate());
- server->setCursorPos(desktopPos.x, desktopPos.y);
+ server->setCursorPos(desktopPos);
try_update = true;
old_cursor = info;
@@ -513,100 +423,102 @@ SDisplay::processEvent(HANDLE event) {
// Flush any changes to the server
try_update = flushChangeTracker() || try_update;
- if (try_update)
+ if (try_update) {
server->tryUpdate();
+ }
}
- } else {
- CloseHandle(event);
- return false;
+ return;
}
- return true;
+ throw rdr::Exception("No such event");
}
// -=- Protected methods
void
-SDisplay::recreatePixelBuffer() {
- vlog.debug("attaching to device %s", deviceName);
-
+SDisplay::recreatePixelBuffer(bool force) {
// Open the specified display device
- HDC new_device;
- if (deviceName.buf) {
- new_device = ::CreateDC(_T("DISPLAY"), deviceName.buf, NULL, NULL);
- releaseDevice = false;
- } else {
- // If no device is specified, open entire screen.
- // Doing this with CreateDC creates problems on multi-monitor systems.
- new_device = ::GetDC(0);
- releaseDevice = true;
+ // 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);
}
- if (!new_device)
- throw SystemException("cannot open the display", GetLastError());
- // Get the coordinates of the entire virtual display
+ // Get the coordinates of the specified dispay device
Rect newScreenRect;
- {
- WindowDC rootDC(0);
- RECT r;
- if (!GetClipBox(rootDC, &r))
- throw rdr::SystemException("GetClipBox", GetLastError());
- newScreenRect = Rect(r.left, r.top, r.right, r.bottom);
+ 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();
}
- // Create a DeviceFrameBuffer attached to it
- DeviceFrameBuffer* new_buffer = new DeviceFrameBuffer(new_device);
+ // 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;
+ }
- // Has anything actually changed about the screen or the buffer?
- if (!pb ||
- (!newScreenRect.equals(screenRect)) ||
- (!new_buffer->getPF().equal(pb->getPF())))
- {
- // Yes. Update the buffer state.
- screenRect = newScreenRect;
- vlog.debug("creating pixel buffer for device");
+ // Flush any existing changes to the server
+ flushChangeTracker();
- // 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;
- // Replace the old PixelBuffer
- if (pb) delete pb;
- if (device) DeleteDC(device);
- pb = new_buffer;
- device = new_device;
+ // Create a DeviceFrameBuffer attached to the new device
+ vlog.debug("creating pixel buffer");
+ DeviceFrameBuffer* new_buffer = new DeviceFrameBuffer(*new_device);
- // Initialise the pixels
- pb->grabRegion(pb->getRect());
+ // Replace the old PixelBuffer
+ screenRect = newScreenRect;
+ pb = new_buffer;
+ device = new_device;
- // Prevent future grabRect operations from throwing exceptions
- pb->setIgnoreGrabErrors(true);
+ // Initialise the pixels
+ pb->grabRegion(pb->getRect());
- // Update the SDisplayCore if required
- if (core)
- core->setPixelBuffer(pb);
+ // Prevent future grabRect operations from throwing exceptions
+ pb->setIgnoreGrabErrors(true);
- // Inform the server of the changes
- if (server)
- server->setPixelBuffer(pb);
+ // Update the clipping update tracker
+ clipper.setClipRect(pb->getRect());
- } else {
- delete new_buffer;
- DeleteDC(new_device);
- }
+ // 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 (change_tracker.is_empty())
+ if (updates.is_empty())
return false;
+
+ vlog.write(120, "flushChangeTracker");
+
// Translate the update coordinates from Screen coords to Desktop
- change_tracker.translate(screenRect.tl.negate());
- // Flush the updates through
- change_tracker.get_update(*server);
- change_tracker.clear();
- return true;
-}
+ updates.translate(screenRect.tl.negate());
-void SDisplay::triggerUpdate() {
- if (core)
- SetEvent(updateEvent);
+ // Clip the updates & flush them to the server
+ updates.copyTo(&clipper);
+ updates.clear();
+ return true;
}
diff --git a/rfb_win32/SDisplay.h b/rfb_win32/SDisplay.h
index c4c08bf3..6dbb50a5 100644
--- a/rfb_win32/SDisplay.h
+++ b/rfb_win32/SDisplay.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -20,31 +20,21 @@
//
// The SDisplay class encapsulates a system display.
-// *** THIS INTERFACE NEEDS TIDYING TO SEPARATE COORDINATE SYSTEMS BETTER ***
-
#ifndef __RFB_SDISPLAY_H__
#define __RFB_SDISPLAY_H__
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
#include <rfb/SDesktop.h>
#include <rfb/UpdateTracker.h>
#include <rfb/Configuration.h>
-#include <rfb/util.h>
-
-#include <winsock2.h>
-#include <rfb_win32/Win32Util.h>
-#include <rfb_win32/SocketManager.h>
-#include <rfb_win32/DeviceFrameBuffer.h>
+#include <rfb_win32/Handle.h>
+#include <rfb_win32/EventManager.h>
#include <rfb_win32/SInput.h>
#include <rfb_win32/Clipboard.h>
-#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/CleanDesktop.h>
#include <rfb_win32/WMCursor.h>
-#include <rfb_win32/WMHooks.h>
#include <rfb_win32/WMNotifier.h>
-#include <rfb_win32/WMWindowCopyRect.h>
-#include <rfb_win32/WMPoller.h>
+#include <rfb_win32/DeviceFrameBuffer.h>
+#include <rfb_win32/DeviceContext.h>
namespace rfb {
@@ -54,33 +44,33 @@ namespace rfb {
// -=- SDisplay
//
- class SDisplayCore;
+ 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,
- UpdateTracker,
- public SocketManager::EventHandler
+ public EventHandler
{
public:
- SDisplay(const TCHAR* device=0);
+ SDisplay();
virtual ~SDisplay();
// -=- SDesktop interface
virtual void start(VNCServer* vs);
virtual void stop();
- virtual void pointerEvent(const Point& pos, rdr::U8 buttonmask);
+ 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();
- // -=- UpdateTracker
-
- virtual void add_changed(const Region& rgn);
- virtual void add_copied(const Region& dest, const Point& delta);
-
// -=- Clipboard
virtual void notifyClipboardChanged(const char* text, int len);
@@ -92,7 +82,7 @@ namespace rfb {
// -=- EventHandler interface
HANDLE getUpdateEvent() {return updateEvent;}
- virtual bool processEvent(HANDLE event);
+ virtual void processEvent(HANDLE event);
// -=- Notification of whether or not SDisplay is started
@@ -100,38 +90,62 @@ namespace rfb {
friend class SDisplayCore;
- static BoolParameter use_hooks;
+ 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:
- void restart();
- void recreatePixelBuffer();
+ bool isRestartRequired();
+ void startCore();
+ void stopCore();
+ void restartCore();
+ void recreatePixelBuffer(bool force=false);
bool flushChangeTracker(); // true if flushed, false if empty
- void triggerUpdate();
-
VNCServer* server;
// -=- Display pixel buffer
DeviceFrameBuffer* pb;
- TCharArray deviceName;
- HDC device;
- bool releaseDevice;
+ DeviceContext* device;
// -=- The coordinates of Window's entire virtual Screen
Rect screenRect;
- // -=- All changes are collected in Display coords and merged
- SimpleUpdateTracker change_tracker;
+ // -=- 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
+ // Cursor
+ WMCursor* cursor;
WMCursor::Info old_cursor;
Region old_cursor_region;
Point cursor_renderpos;
diff --git a/rfb_win32/SDisplayCoreDriver.h b/rfb_win32/SDisplayCoreDriver.h
new file mode 100644
index 00000000..5fea75cc
--- /dev/null
+++ b/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/rfb_win32/SDisplayCorePolling.cxx b/rfb_win32/SDisplayCorePolling.cxx
new file mode 100644
index 00000000..fc57ecd0
--- /dev/null
+++ b/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/rfb_win32/SDisplayCorePolling.h b/rfb_win32/SDisplayCorePolling.h
new file mode 100644
index 00000000..9e1b5ad1
--- /dev/null
+++ b/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/rfb_win32/SDisplayCoreWMHooks.cxx b/rfb_win32/SDisplayCoreWMHooks.cxx
new file mode 100644
index 00000000..10b88e08
--- /dev/null
+++ b/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/rfb_win32/SDisplayCoreWMHooks.h b/rfb_win32/SDisplayCoreWMHooks.h
new file mode 100644
index 00000000..24fa5cdc
--- /dev/null
+++ b/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/rfb_win32/SInput.cxx b/rfb_win32/SInput.cxx
index 457a8619..db59287a 100644
--- a/rfb_win32/SInput.cxx
+++ b/rfb_win32/SInput.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -26,23 +26,30 @@
#define XK_CURRENCY
#include <rfb/keysymdef.h>
-// * Force the windows headers to include all the SendInput stuff
-#define _WIN32_WINNT 0x401
-
+#include <tchar.h>
#include <rfb_win32/SInput.h>
+#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Service.h>
-#include <rfb/LogWriter.h>
#include <rfb_win32/OSVersion.h>
-#include <rfb_win32/Win32Util.h>
-#include "keymap.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
@@ -68,7 +75,7 @@ win32::SPointer::SPointer()
}
void
-win32::SPointer::pointerEvent(const Point& pos, rdr::U8 buttonmask)
+win32::SPointer::pointerEvent(const Point& pos, int buttonmask)
{
// - We are specifying absolute coordinates
DWORD flags = MOUSEEVENTF_ABSOLUTE;
@@ -118,7 +125,7 @@ win32::SPointer::pointerEvent(const Point& pos, rdr::U8 buttonmask)
// 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 SM_CXVIRTUALSCREEN
+#ifdef RFB_HAVE_SENDINPUT
if (osVersion.isPlatformNT) {
if (!_SendInput.isValid())
throw rdr::Exception("SendInput not available");
diff --git a/rfb_win32/SInput.h b/rfb_win32/SInput.h
index dcd779ef..2a0b3e67 100644
--- a/rfb_win32/SInput.h
+++ b/rfb_win32/SInput.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -32,8 +32,6 @@
namespace rfb {
- class CMsgWriter;
-
namespace win32 {
// -=- Pointer event handling
@@ -44,7 +42,7 @@ namespace rfb {
// - 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, rdr::U8 buttonmask);
+ void pointerEvent(const Point& pos, int buttonmask);
protected:
Point last_position;
rdr::U8 last_buttonmask;
diff --git a/rfb_win32/Security.cxx b/rfb_win32/Security.cxx
new file mode 100644
index 00000000..985f00cb
--- /dev/null
+++ b/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/rfb_win32/Security.h b/rfb_win32/Security.h
index d92e314f..1e2e9068 100644
--- a/rfb_win32/Security.h
+++ b/rfb_win32/Security.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,16 +25,10 @@
#define __RFB_WIN32_SECURITY_H__
#include <rdr/types.h>
-#include <rdr/Exception.h>
-#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/LocalMem.h>
#include <rfb_win32/TCharArray.h>
-
-#include <lmcons.h>
-#include <Accctrl.h>
#include <aclapi.h>
-#include <list>
-
namespace rfb {
namespace win32 {
@@ -42,14 +36,7 @@ namespace rfb {
struct Trustee : public TRUSTEE {
Trustee(const TCHAR* name,
TRUSTEE_FORM form=TRUSTEE_IS_NAME,
- TRUSTEE_TYPE type=TRUSTEE_IS_UNKNOWN)
- {
- pMultipleTrustee = 0;
- MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
- TrusteeForm = form;
- TrusteeType = type;
- ptstrName = (TCHAR*)name;
- }
+ TRUSTEE_TYPE type=TRUSTEE_IS_UNKNOWN);
};
struct ExplicitAccess : public EXPLICIT_ACCESS {
@@ -57,86 +44,56 @@ namespace rfb {
TRUSTEE_FORM type,
DWORD perms,
ACCESS_MODE mode,
- DWORD inherit=0)
- {
- Trustee = rfb::win32::Trustee(name, type);
- grfAccessPermissions = perms;
- grfAccessMode = mode;
- grfInheritance = inherit;
- }
+ DWORD inherit=0);
};
// Helper class for building access control lists
struct AccessEntries {
- AccessEntries() : entries(0), entry_count(0) {}
- ~AccessEntries() {delete [] entries;}
- void 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;
- }
- }
+ AccessEntries();
+ ~AccessEntries();
+ void allocMinEntries(int count);
void 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 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++;
- }
+ 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 {
- Sid() : sid(0) {}
- Sid(PSID sid_) : sid(sid_) {}
- ~Sid() {
- if (sid) FreeSid(sid);
- }
- operator PSID() const {return sid;}
- PSID operator=(const PSID sid_) {
- if (sid) FreeSid(sid);
- sid = sid_;
- }
-
- static PSID 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());
- return sid;
- }
- static PSID 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());
- return sid;
- }
-
- protected:
- PSID sid;
+ 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) {}
@@ -145,22 +102,7 @@ namespace rfb {
};
// Create a new ACL based on supplied entries and, if supplied, existing ACL
- static PACL CreateACL(const AccessEntries& ae, PACL existing_acl=0) {
- 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;
- }
+ PACL CreateACL(const AccessEntries& ae, PACL existing_acl=0);
// Helper class for memory-management of self-relative SecurityDescriptors
struct SecurityDescriptorPtr : LocalMem {
@@ -172,24 +114,7 @@ namespace rfb {
// 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.
- static PSECURITY_DESCRIPTOR CreateSdWithDacl(const PACL dacl) {
- SECURITY_DESCRIPTOR absSD;
- if (!InitializeSecurityDescriptor(&absSD, SECURITY_DESCRIPTOR_REVISION))
- throw rdr::SystemException("InitializeSecurityDescriptor", GetLastError());
- Sid owner(Sid::SYSTEM());
- if (!SetSecurityDescriptorOwner(&absSD, owner, FALSE))
- throw rdr::SystemException("SetSecurityDescriptorOwner", GetLastError());
- Sid group(Sid::Administrators());
- 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();
- }
+ PSECURITY_DESCRIPTOR CreateSdWithDacl(const PACL dacl);
}
diff --git a/rfb_win32/Service.cxx b/rfb_win32/Service.cxx
index b00c2900..2b11a22d 100644
--- a/rfb_win32/Service.cxx
+++ b/rfb_win32/Service.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -20,15 +20,15 @@
#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/Win32Util.h>
#include <rfb_win32/OSVersion.h>
#include <rfb/Threading.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <logmessages/messages.h>
#include <rdr/Exception.h>
+#include <rfb/LogWriter.h>
-#include <logmessages/messages.h>
using namespace rdr;
using namespace rfb;
@@ -42,22 +42,26 @@ static LogWriter vlog("Service");
Service* service = 0;
VOID WINAPI serviceHandler(DWORD control) {
- vlog.debug("service control %u", control);
switch (control) {
case SERVICE_CONTROL_INTERROGATE:
+ vlog.info("cmd: report status");
service->setStatus();
- break;
+ return;
case SERVICE_CONTROL_PARAMCHANGE:
+ vlog.info("cmd: param change");
service->readParams();
- break;
+ return;
case SERVICE_CONTROL_SHUTDOWN:
+ vlog.info("cmd: OS shutdown");
service->osShuttingDown();
- break;
+ return;
case SERVICE_CONTROL_STOP:
+ vlog.info("cmd: stop");
service->setStatus(SERVICE_STOP_PENDING);
service->stop();
- break;
- }
+ return;
+ };
+ vlog.debug("cmd: unknown %lu", control);
}
@@ -87,11 +91,14 @@ const TCHAR* ServiceMsgWindow::baseName = _T("ServiceWindow:");
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) {
- vlog.error("unable to register service control handler");
- return;
+ 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);
@@ -166,9 +173,9 @@ Service::setStatus(DWORD state) {
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);
- stop();
}
vlog.debug("set status to %u(%u)", state, status.dwCheckPoint);
}
@@ -597,7 +604,7 @@ bool rfb::win32::stopService(const TCHAR* name) {
return true;
}
-void rfb::win32::printServiceStatus(const TCHAR* name) {
+DWORD rfb::win32::getServiceState(const TCHAR* name) {
if (osVersion.isPlatformNT) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
@@ -614,25 +621,25 @@ void rfb::win32::printServiceStatus(const TCHAR* name) {
if (!ControlService(service, SERVICE_CONTROL_INTERROGATE, (SERVICE_STATUS*)&status))
throw rdr::SystemException("unable to query the service", GetLastError());
- printf("Service is in the ");
- switch (status.dwCurrentState) {
- case SERVICE_RUNNING: printf("running"); break;
- case SERVICE_STOPPED: printf("stopped"); break;
- case SERVICE_STOP_PENDING: printf("stop pending"); break;
- default: printf("unknown (%lu)", status.dwCurrentState); break;
- };
- printf(" state.\n");
-
+ return status.dwCurrentState;
} else {
HWND service_window = findServiceWindow(name);
- printf("Service is in the ");
- if (!service_window) printf("stopped");
- else printf("running");
- printf(" state.\n");
+ 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;
-} \ No newline at end of file
+}
diff --git a/rfb_win32/Service.h b/rfb_win32/Service.h
index 164381a1..00abe108 100644
--- a/rfb_win32/Service.h
+++ b/rfb_win32/Service.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -27,7 +27,6 @@
#ifndef __RFB_WIN32_SERVICE_H__
#define __RFB_WIN32_SERVICE_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace rfb {
@@ -61,13 +60,13 @@ namespace rfb {
// - Service control notifications
// To get notified when the OS is shutting down
- virtual void osShuttingDown() = 0;
+ virtual void osShuttingDown() {};
// To get notified when the service parameters change
- virtual void readParams() = 0;
+ virtual void readParams() {};
// To cause the serviceMain() routine to return
- virtual void stop() = 0;
+ virtual void stop() {};
public:
SERVICE_STATUS_HANDLE status_handle;
@@ -111,7 +110,13 @@ namespace rfb {
bool startService(const TCHAR* name);
bool stopService(const TCHAR* name);
- void printServiceStatus(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();
diff --git a/rfb_win32/SocketManager.cxx b/rfb_win32/SocketManager.cxx
index 6d1980cc..1d52bc86 100644
--- a/rfb_win32/SocketManager.cxx
+++ b/rfb_win32/SocketManager.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -18,10 +18,8 @@
// -=- SocketManager.cxx
-#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
-#include <assert.h>
-
+#include <list>
#include <rfb/LogWriter.h>
#include <rfb_win32/SocketManager.h>
@@ -33,218 +31,183 @@ static LogWriter vlog("SocketManager");
// -=- SocketManager
-SocketManager::SocketManager() : sockets(0), events(0), nSockets(0), nAvail(0) {
+SocketManager::SocketManager() {
}
SocketManager::~SocketManager() {
- for (int i=0; i<nSockets; i++) {
- if (!sockets[i].is_event)
- WSACloseEvent(events[i]);
- }
- delete [] events;
- delete [] sockets;
}
-void SocketManager::addListener(network::SocketListener* sock_, network::SocketServer* srvr) {
- WSAEVENT event = WSACreateEvent();
- assert(event != WSA_INVALID_EVENT);
- addListener(sock_, event, srvr);
+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::addSocket(network::Socket* sock_, network::SocketServer* srvr) {
+
+void SocketManager::addListener(network::SocketListener* sock_,
+ network::SocketServer* srvr,
+ AddressChangeNotifier* acn) {
WSAEVENT event = WSACreateEvent();
- assert(event != WSA_INVALID_EVENT);
- addSocket(sock_, event, srvr);
+ 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");
+}
-BOOL SocketManager::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
- while (true) {
- // First check for idle timeout
- network::SocketServer* server = 0;
- int timeout = 0;
- for (int i=0; i<nSockets; i++) {
- if (!sockets[i].is_event &&
- sockets[i].server != server) {
- server = sockets[i].server;
- int t = server->checkTimeouts();
- if (t > 0 && (timeout == 0 || t < timeout))
- timeout = t;
- }
- }
- if (timeout == 0)
- timeout = INFINITE;
-
- // - Network IO is less common than messages - process it first
- DWORD result;
- if (nSockets) {
- result = WaitForMultipleObjects(nSockets, events, FALSE, 0);
- if (result == WAIT_TIMEOUT) {
- if (PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE))
- return msg->message != WM_QUIT;
-
- result = MsgWaitForMultipleObjects(nSockets, events, FALSE, timeout,
- QS_ALLINPUT);
- if (result == WAIT_OBJECT_0 + nSockets) {
- 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 + nSockets))) {
- int index = result - WAIT_OBJECT_0;
-
- // - Process a socket event
-
- if (sockets[index].is_event) {
- // Process a general Win32 event
- // NB: The handler must reset the event!
-
- if (!sockets[index].handler->processEvent(events[index])) {
- removeSocket(index);
- continue;
- }
- } else if (sockets[index].is_conn) {
- // Process data from an active connection
-
- // Cancel event notification for this socket
- if (WSAEventSelect(sockets[index].fd, events[index], 0) == SOCKET_ERROR)
- vlog.info("unable to disable WSAEventSelect:%u", WSAGetLastError());
-
- // Reset the event object
- WSAResetEvent(events[index]);
-
- // Call the socket server to process the event
- if (!sockets[index].server->processSocketEvent(sockets[index].sock.conn)) {
- removeSocket(index);
- continue;
- }
-
- // Re-instate the required socket event
- // If the read event is still valid, the event object gets set here
- if (WSAEventSelect(sockets[index].fd, events[index], FD_READ | FD_CLOSE) == SOCKET_ERROR)
- throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
-
- } else {
- // Accept an incoming connection
- vlog.debug("accepting incoming connection");
-
- // What kind of event is this?
- WSANETWORKEVENTS network_events;
- WSAEnumNetworkEvents(sockets[index].fd, events[index], &network_events);
- if (network_events.lNetworkEvents & FD_ACCEPT) {
- network::Socket* new_sock = sockets[index].sock.listener->accept();
- if ((sockets[index].server)->getDisable()) {
- delete new_sock;
- new_sock = 0;
- }
- if (new_sock) {
- sockets[index].server->addClient(new_sock);
- addSocket(new_sock, sockets[index].server);
- }
- } else if (network_events.lNetworkEvents & FD_CLOSE) {
- vlog.info("deleting listening socket");
- network::SocketListener* s = sockets[index].sock.listener;
- removeSocket(index);
- delete s;
- } else {
- vlog.error("unknown network event for listener");
- }
+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);
+}
- }
- } else if (result == WAIT_FAILED) {
- throw rdr::SystemException("unable to wait for events", GetLastError());
+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");
}
-void SocketManager::resizeArrays(int numSockets) {
- if (nAvail >= numSockets) return;
- while (nAvail < numSockets)
- nAvail = max(16, nAvail*2);
+int SocketManager::checkTimeouts() {
+ network::SocketServer* server = 0;
+ int timeout = EventManager::checkTimeouts();
- SocketInfo* newinfo = new SocketInfo[nAvail];
- HANDLE* newevents = new HANDLE[nAvail];
- for (int i=0; i<nSockets; i++) {
- newinfo[i] = sockets[i];
- newevents[i] = events[i];
- }
- delete [] sockets;
- delete [] events;
- sockets = newinfo;
- events = newevents;
-}
+ std::map<HANDLE,ListenInfo>::iterator i;
+ for (i=listeners.begin(); i!=listeners.end(); i++)
+ soonestTimeout(&timeout, i->second.server->checkTimeouts());
-void SocketManager::addSocket(network::Socket* sock, HANDLE event, network::SocketServer* server) {
- resizeArrays(nSockets+1);
+ 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);
+ }
- sockets[nSockets].sock.conn = sock;
- sockets[nSockets].fd = sock->getFd();
- sockets[nSockets].server = server;
- events[nSockets] = event;
- sockets[nSockets].is_conn = true;
- sockets[nSockets].is_event = false;
+ std::list<network::Socket*>::iterator k;
+ for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
+ remSocket(*k);
- if (WSAEventSelect(sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
- throw rdr::SystemException("unable to select on socket", WSAGetLastError());
- nSockets++;
+ return timeout;
}
-void SocketManager::addListener(network::SocketListener* sock, HANDLE event, network::SocketServer* server) {
- resizeArrays(nSockets+1);
- sockets[nSockets].sock.listener = sock;
- sockets[nSockets].fd = sock->getFd();
- sockets[nSockets].server = server;
- events[nSockets] = event;
- sockets[nSockets].is_conn = false;
- sockets[nSockets].is_event = false;
+void SocketManager::processEvent(HANDLE event) {
+ if (listeners.count(event)) {
+ ListenInfo li = listeners[event];
- if (WSAEventSelect(sock->getFd(), event, FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
- throw rdr::SystemException("unable to select on listener", WSAGetLastError());
- nSockets++;
-}
+ // Accept an incoming connection
+ vlog.debug("accepting incoming connection");
-void SocketManager::remListener(network::SocketListener* sock) {
- for (int index=0; index<nSockets; index++) {
- if (!sockets[index].is_conn &&
- !sockets[index].is_event) {
- vlog.debug("removing listening socket");
- removeSocket(index);
- delete sock;
+ // 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];
-void SocketManager::addEvent(HANDLE event, EventHandler* ecb) {
- resizeArrays(nSockets+1);
+ try {
+ // Process data from an active connection
- sockets[nSockets].handler = ecb;
- events[nSockets] = event;
- sockets[nSockets].is_conn = false;
- sockets[nSockets].is_event = true;
-
- nSockets++;
-}
+ // Cancel event notification for this socket
+ if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
+ throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
-void SocketManager::removeSocket(int index) {
- if (index >= nSockets)
- throw rdr::Exception("attempting to remove unregistered socket");
+ // Reset the event object
+ WSAResetEvent(event);
- if (!sockets[index].is_event)
- WSACloseEvent(events[index]);
+ // Call the socket server to process the event
+ ci.server->processSocketEvent(ci.sock);
+ if (ci.sock->isShutdown()) {
+ remSocket(ci.sock);
+ return;
+ }
- for (int i=index; i<nSockets-1; i++) {
- sockets[i] = sockets[i+1];
- events[i] = events[i+1];
+ // 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);
+ }
}
-
- nSockets--;
}
-
diff --git a/rfb_win32/SocketManager.h b/rfb_win32/SocketManager.h
index 791370f2..ef359749 100644
--- a/rfb_win32/SocketManager.h
+++ b/rfb_win32/SocketManager.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -30,23 +30,32 @@
#ifndef __RFB_WIN32_SOCKET_MGR_H__
#define __RFB_WIN32_SOCKET_MGR_H__
-#include <list>
-
+#include <map>
#include <network/Socket.h>
-#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/EventManager.h>
namespace rfb {
-
namespace win32 {
- class SocketManager {
+ 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);
+ void addListener(network::SocketListener* sock_,
+ network::SocketServer* srvr,
+ AddressChangeNotifier* acn = 0);
// Remove and delete a listening socket.
void remListener(network::SocketListener* sock);
@@ -54,50 +63,24 @@ namespace rfb {
// 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);
-
- // Add a Win32 event & handler for it to the SocketManager
- // This event will be blocked on along with the registered Sockets, and the
- // handler called whenever it is discovered to be set.
- // NB: SocketManager does NOT call ResetEvent on the event!
- // NB: If processEvent returns false then the event is no longer registered,
- // and the event object is assumed to have been closed by processEvent()
- struct EventHandler {
- virtual ~EventHandler() {}
- virtual bool processEvent(HANDLE event) = 0;
- };
- void addEvent(HANDLE event, EventHandler* ecb);
-
- // getMessage
- //
- // Either return a message from the thread's message queue or process a socket
- // event.
- // Returns whenever a message needs processing. Returns false if message is
- // WM_QUIT, true for all other messages.
- BOOL getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg);
+ void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);
protected:
- void addListener(network::SocketListener* sock, HANDLE event, network::SocketServer* server);
- void addSocket(network::Socket* sock, HANDLE event, network::SocketServer* server);
- void resizeArrays(int numSockets);
- void removeSocket(int index);
- struct SocketInfo {
- union {
- network::Socket* conn;
- network::SocketListener* listener;
- } sock;
- SOCKET fd;
- bool is_conn;
- bool is_event;
- union {
- network::SocketServer* server;
- EventHandler* handler;
- };
+ 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;
};
- SocketInfo* sockets;
- HANDLE* events;
- int nSockets;
- int nAvail;
+ std::map<HANDLE, ListenInfo> listeners;
+ std::map<HANDLE, ConnInfo> connections;
};
}
diff --git a/rfb_win32/TCharArray.cxx b/rfb_win32/TCharArray.cxx
index f8f03a69..fd4c0783 100644
--- a/rfb_win32/TCharArray.cxx
+++ b/rfb_win32/TCharArray.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/TCharArray.h b/rfb_win32/TCharArray.h
index 399e00a7..dde63b78 100644
--- a/rfb_win32/TCharArray.h
+++ b/rfb_win32/TCharArray.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -40,10 +40,10 @@
#ifndef __RFB_WIN32_TCHARARRAY_H__
#define __RFB_WIN32_TCHARARRAY_H__
-#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
#include <tchar.h>
-
#include <rfb/util.h>
+#include <rfb/Password.h>
namespace rfb {
@@ -98,6 +98,20 @@ namespace rfb {
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
@@ -105,6 +119,7 @@ namespace rfb {
#define tstrContains wstrContains
typedef WCharArray TCharArray;
typedef WStr TStr;
+ typedef WPlainPasswd TPlainPasswd;
#else
#define tstrDup strDup
#define tstrFree strFree
@@ -112,8 +127,9 @@ namespace rfb {
#define tstrContains strContains
typedef CharArray TCharArray;
typedef CStr TStr;
+ typedef PlainPasswd TPlainPasswd;
#endif
};
-#endif \ No newline at end of file
+#endif
diff --git a/rfb_win32/Threading.cxx b/rfb_win32/Threading.cxx
new file mode 100644
index 00000000..c41ac38b
--- /dev/null
+++ b/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/rfb_win32/Threading.h b/rfb_win32/Threading.h
new file mode 100644
index 00000000..850f04dd
--- /dev/null
+++ b/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/rfb_win32/TrayIcon.h b/rfb_win32/TrayIcon.h
index 85680f3f..dc5102a9 100644
--- a/rfb_win32/TrayIcon.h
+++ b/rfb_win32/TrayIcon.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -23,7 +23,6 @@
#ifndef __RFB_WIN32_TRAY_ICON_H__
#define __RFB_WIN32_TRAY_ICON_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <rfb_win32/MsgWindow.h>
diff --git a/rfb_win32/TsSessions.cxx b/rfb_win32/TsSessions.cxx
new file mode 100644
index 00000000..efe75640
--- /dev/null
+++ b/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/rfb_win32/TsSessions.h b/rfb_win32/TsSessions.h
new file mode 100644
index 00000000..b15ada71
--- /dev/null
+++ b/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/rfb_win32/WMCursor.cxx b/rfb_win32/WMCursor.cxx
index 871d9376..4d696cbc 100644
--- a/rfb_win32/WMCursor.cxx
+++ b/rfb_win32/WMCursor.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -20,11 +20,10 @@
// *** DOESN'T SEEM TO WORK WITH GetCursorInfo POS CODE BUILT-IN UNDER NT4SP6
// *** INSTEAD, WE LOOK FOR Win2000/Win98 OR ABOVE
-#define WINVER 0x0500
#include <rfb_win32/WMCursor.h>
#include <rfb_win32/OSVersion.h>
-#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/DynamicFn.h>
#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
@@ -35,12 +34,19 @@ 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), library(0), use_getCursorInfo(false), cursor(0) {
-#if (WINVER >= 0x0500)
+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));
@@ -48,13 +54,12 @@ WMCursor::WMCursor() : hooks(0), library(0), use_getCursorInfo(false), cursor(0)
// Use GetCursorInfo if OS version is sufficient
use_getCursorInfo = (is_win98 || is_win2K) && _GetCursorInfo.isValid();
-#else
-#pragma message ("not building in GetCursorInfo support")
#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");
+ vlog.info("falling back to cursor hooking: %p", hooks);
} else {
delete hooks;
hooks = 0;
@@ -63,18 +68,18 @@ WMCursor::WMCursor() : hooks(0), library(0), use_getCursorInfo(false), cursor(0)
} else {
vlog.info("using GetCursorInfo");
}
- cursor = (HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
}
WMCursor::~WMCursor() {
- if (hooks) delete hooks;
- if (library) FreeLibrary(library);
+ vlog.debug("deleting WMCursorHooks (%p)", hooks);
+ if (hooks)
+ delete hooks;
}
WMCursor::Info
WMCursor::getCursorInfo() {
Info result;
-#if (WINVER >= 0x0500)
+#ifdef RFB_HAVE_GETCURSORINFO
if (use_getCursorInfo) {
CURSORINFO info;
info.cbSize = sizeof(CURSORINFO);
@@ -88,7 +93,8 @@ WMCursor::getCursorInfo() {
#endif
// Fall back to the old way of doing things
POINT pos;
- if (hooks) cursor = hooks->getCursor();
+ if (hooks)
+ cursor = hooks->getCursor();
result.cursor = cursor;
result.visible = cursor != 0;
GetCursorPos(&pos);
diff --git a/rfb_win32/WMCursor.h b/rfb_win32/WMCursor.h
index a96822a7..41f9ee84 100644
--- a/rfb_win32/WMCursor.h
+++ b/rfb_win32/WMCursor.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,12 +25,10 @@
#ifndef __RFB_WIN32_WM_CURSOR_H__
#define __RFB_WIN32_WM_CURSOR_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <rfb_win32/WMHooks.h>
namespace rfb {
-
namespace win32 {
class WMCursor {
@@ -53,13 +51,11 @@ namespace rfb {
Info getCursorInfo();
protected:
WMCursorHooks* hooks;
- HMODULE library;
bool use_getCursorInfo;
HCURSOR cursor;
};
};
-
};
#endif // __RFB_WIN32_WM_CURSOR_H__
diff --git a/rfb_win32/WMHooks.cxx b/rfb_win32/WMHooks.cxx
index 26a2363c..2d690538 100644
--- a/rfb_win32/WMHooks.cxx
+++ b/rfb_win32/WMHooks.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -18,10 +18,11 @@
// -=- WMHooks.cxx
-#include <wm_hooks/wm_hooks.h>
-
#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>
@@ -32,11 +33,29 @@ 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) {}
+ 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;
};
@@ -48,52 +67,62 @@ Mutex hook_mgr_lock;
HCURSOR hook_cursor = (HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
-bool
-StartHookThread() {
- if (hook_mgr) return true;
- vlog.debug("opening hook thread");
+static bool StartHookThread() {
+ if (hook_mgr)
+ return true;
+ vlog.debug("creating thread");
hook_mgr = new WMHooksThread();
- if (!WM_Hooks_Install(hook_mgr->getThreadId(), 0)) {
+ 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;
}
-void
-StopHookThread() {
- if (!hook_mgr) return;
- if (!hooks.empty() || !cursor_hooks.empty()) return;
- vlog.debug("closing hook thread");
+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;
}
-bool
-AddHook(WMHooks* hook) {
+static bool AddHook(WMHooks* hook) {
vlog.debug("adding hook");
Lock l(hook_mgr_lock);
- if (!StartHookThread()) return false;
+ if (!StartHookThread())
+ return false;
hooks.push_back(hook);
return true;
}
-bool
-AddCursorHook(WMCursorHooks* hook) {
+static bool AddCursorHook(WMCursorHooks* hook) {
vlog.debug("adding cursor hook");
Lock l(hook_mgr_lock);
- if (cursor_hooks.empty()) WM_Hooks_EnableCursorShape(TRUE);
- if (!StartHookThread()) return false;
+ 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;
}
-bool
-RemHook(WMHooks* hook) {
+static bool RemHook(WMHooks* hook) {
{
vlog.debug("removing hook");
Lock l(hook_mgr_lock);
@@ -103,76 +132,107 @@ RemHook(WMHooks* hook) {
return true;
}
-bool
-RemCursorHook(WMCursorHooks* hook) {
+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();
- if (cursor_hooks.empty()) WM_Hooks_EnableCursorShape(FALSE);
return true;
}
-void
-NotifyHooksRegion(const Region& r) {
+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)->new_changes.add_changed(r);
- if (!(*i)->notified) {
- (*i)->notified = true;
- PostMessage((*i)->getHandle(), WM_USER, 0, 0);
- }
- }
+ for (i=hooks.begin(); i!=hooks.end(); i++)
+ (*i)->NotifyHooksRegion(r);
}
-void
-NotifyHooksCursor(HCURSOR c) {
+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() {
- UINT windowMsg = WM_Hooks_WindowChanged();
- UINT clientAreaMsg = WM_Hooks_WindowClientAreaChanged();
- UINT borderMsg = WM_Hooks_WindowBorderChanged();
- UINT rectangleMsg = WM_Hooks_RectangleChanged();
- UINT cursorMsg = WM_Hooks_CursorChanged();
+ // 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
- UINT diagnosticMsg = WM_Hooks_Diagnostic();
+ 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 == windowMsg) {
+
+ 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))
- {
- NotifyHooksRegion(Rect(wrect.left, wrect.top,
- wrect.right, wrect.bottom));
-
+ 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)) {
- NotifyHooksRegion(Rect(wrect.left+pt.x, wrect.top+pt.y,
- wrect.right+pt.x, wrect.bottom+pt.y));
+ 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) &&
@@ -187,14 +247,19 @@ WMHooksThread::run() {
changed.assign_subtract(Rect(crect.left+pt.x, crect.top+pt.y,
crect.right+pt.x, crect.bottom+pt.y));
}
- NotifyHooksRegion(changed);
+ 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()) {
- NotifyHooksRegion(r);
+ updates[activeRgn].assign_union(r);
+ updateDelayTimer.start(updateDelayMs);
}
+
} else if (msg.message == cursorMsg) {
NotifyHooksCursor((HCURSOR)msg.lParam);
#ifdef _DEBUG
@@ -205,7 +270,7 @@ WMHooksThread::run() {
}
vlog.debug("stopping hook thread - processed %d events", count);
- WM_Hooks_Remove(getThreadId());
+ (*WM_Hooks_Remove)(getThreadId());
}
Thread*
@@ -219,65 +284,52 @@ WMHooksThread::join() {
// -=- WMHooks class
-rfb::win32::WMHooks::WMHooks()
- : clipper(0), new_changes(true), fg_window(0),
- notified(false), MsgWindow(_T("WMHooks")) {
+rfb::win32::WMHooks::WMHooks() : updateEvent(0) {
}
rfb::win32::WMHooks::~WMHooks() {
RemHook(this);
- if (clipper) delete clipper;
}
-LRESULT
-rfb::win32::WMHooks::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
- switch (msg) {
- case WM_USER:
- {
- // *** Yield, to allow the triggering update event to be processed
- // BEFORE we try to grab the resulting changes.
- // *** IMPROVES THINGS NOTICABLY ON WinXP
- Sleep(0);
- // ***
-
- Lock l(hook_mgr_lock);
- notified = false;
- new_changes.get_update(*clipper);
- new_changes.clear();
- }
- break;
- }
- return MsgWindow::processMessage(msg, wParam, lParam);
+bool rfb::win32::WMHooks::setEvent(HANDLE ue) {
+ if (updateEvent)
+ RemHook(this);
+ updateEvent = ue;
+ return AddHook(this);
}
-bool
-rfb::win32::WMHooks::setClipRect(const Rect& r) {
- clip_region = r;
- if (clipper) clipper->set_clip_region(clip_region);
+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::setUpdateTracker(UpdateTracker* ut) {
- if (clipper) delete clipper;
- clipper = new ClippedUpdateTracker(*ut);
- clipper->set_clip_region(clip_region);
- return AddHook(this);
+bool rfb::win32::WMHooks::areAvailable() {
+ WMHooksThread wmht;
+ return wmht.WM_Hooks_Install.isValid();
}
#ifdef _DEBUG
void
rfb::win32::WMHooks::setDiagnosticRange(UINT min, UINT max) {
- WM_Hooks_SetDiagnosticRange(min, 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
-Mutex blockMutex;
-int blockCount = 0;
-
rfb::win32::WMBlockInput::WMBlockInput() : active(false) {
}
@@ -285,22 +337,40 @@ 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 (on == active) return true;
- vlog.debug("blockInput changed");
+ if (active == on) return true;
Lock l(blockMutex);
- int newCount = blockCount;
- if (on)
- newCount++;
- else
- newCount--;
- if (WM_Hooks_EnableRealInputs(newCount==0, newCount==0)) {
- vlog.debug("set blocking to %d", newCount);
- blockCount = newCount;
- active = on;
- return true;
- }
- return false;
+ int newCount = on ? blockCount+1 : blockCount-1;
+ if (!blockRealInputs(newCount > 0))
+ return false;
+ blockCount = newCount;
+ active = on;
+ return true;
}
diff --git a/rfb_win32/WMHooks.h b/rfb_win32/WMHooks.h
index 791df763..4713b416 100644
--- a/rfb_win32/WMHooks.h
+++ b/rfb_win32/WMHooks.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -21,43 +21,50 @@
#ifndef __RFB_WIN32_WM_HOOKS_H__
#define __RFB_WIN32_WM_HOOKS_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <rfb/UpdateTracker.h>
#include <rdr/Exception.h>
-#include <rfb_win32/MsgWindow.h>
+#include <rfb_win32/Win32Util.h>
namespace rfb {
namespace win32 {
- class WMHooks : public MsgWindow {
+ // -=- 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();
- bool setClipRect(const Rect& cr);
- bool setUpdateTracker(UpdateTracker* ut);
+ // 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);
- virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+ // 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:
- ClippedUpdateTracker* clipper;
- Region clip_region;
-
- void* fg_window;
- Rect fg_window_rect;
-
- public:
- SimpleUpdateTracker new_changes;
- bool notified;
+ 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();
diff --git a/rfb_win32/WMNotifier.cxx b/rfb_win32/WMNotifier.cxx
index 9773abf5..20a5445f 100644
--- a/rfb_win32/WMNotifier.cxx
+++ b/rfb_win32/WMNotifier.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -30,7 +30,7 @@ using namespace rfb::win32;
static LogWriter vlog("WMMonitor");
-WMMonitor::WMMonitor() : MsgWindow(_T("WMMonitor")) {
+WMMonitor::WMMonitor() : MsgWindow(_T("WMMonitor")), notifier(0) {
}
WMMonitor::~WMMonitor() {
diff --git a/rfb_win32/WMNotifier.h b/rfb_win32/WMNotifier.h
index 564d176f..a7609642 100644
--- a/rfb_win32/WMNotifier.h
+++ b/rfb_win32/WMNotifier.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/WMPoller.cxx b/rfb_win32/WMPoller.cxx
index f568b211..f8505342 100644
--- a/rfb_win32/WMPoller.cxx
+++ b/rfb_win32/WMPoller.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -35,35 +35,19 @@ BoolParameter rfb::win32::WMPoller::poll_console_windows("PollConsoleWindows",
// -=- WMPoller class
-rfb::win32::WMPoller::WMPoller() : clipper(0) {
-}
-
-rfb::win32::WMPoller::~WMPoller() {
- if (clipper) delete clipper;
-}
-
bool
rfb::win32::WMPoller::processEvent() {
PollInfo info;
- if (clipper && poll_console_windows) {
+ if (poll_console_windows && ut) {
::EnumWindows(WMPoller::enumWindowProc, (LPARAM) &info);
- clipper->add_changed(info.poll_include);
+ ut->add_changed(info.poll_include);
}
return false;
}
bool
-rfb::win32::WMPoller::setClipRect(const Rect& r) {
- clip_region = r;
- if (clipper) clipper->set_clip_region(clip_region);
- return true;
-}
-
-bool
-rfb::win32::WMPoller::setUpdateTracker(UpdateTracker* ut) {
- if (clipper) delete clipper;
- clipper = new ClippedUpdateTracker(*ut);
- clipper->set_clip_region(clip_region);
+rfb::win32::WMPoller::setUpdateTracker(UpdateTracker* ut_) {
+ ut = ut_;
return true;
}
diff --git a/rfb_win32/WMPoller.h b/rfb_win32/WMPoller.h
index 3f3f402a..851b69f4 100644
--- a/rfb_win32/WMPoller.h
+++ b/rfb_win32/WMPoller.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -28,7 +28,6 @@
#ifndef __RFB_WIN32_WM_POLLER_H__
#define __RFB_WIN32_WM_POLLER_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <rfb/UpdateTracker.h>
#include <rfb/Configuration.h>
@@ -39,11 +38,9 @@ namespace rfb {
class WMPoller {
public:
- WMPoller();
- ~WMPoller();
+ WMPoller() : ut(0) {}
bool processEvent();
- bool setClipRect(const Rect& cr);
bool setUpdateTracker(UpdateTracker* ut);
static BoolParameter poll_console_windows;
@@ -55,9 +52,7 @@ namespace rfb {
static bool checkPollWindow(HWND w);
static void pollWindow(HWND w, PollInfo* info);
static BOOL CALLBACK enumWindowProc(HWND w, LPARAM lp);
-
- ClippedUpdateTracker* clipper;
- Region clip_region;
+ UpdateTracker* ut;
};
};
diff --git a/rfb_win32/WMShatter.cxx b/rfb_win32/WMShatter.cxx
index f6a74848..e68abfb1 100644
--- a/rfb_win32/WMShatter.cxx
+++ b/rfb_win32/WMShatter.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/WMShatter.h b/rfb_win32/WMShatter.h
index 7b81678f..3ea63b1a 100644
--- a/rfb_win32/WMShatter.h
+++ b/rfb_win32/WMShatter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -33,11 +33,9 @@
#ifndef __RFB_WIN32_SHATTER_H__
#define __RFB_WIN32_SHATTER_H__
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace rfb {
-
namespace win32 {
bool IsSafeWM(HWND window, UINT msg, WPARAM wParam, LPARAM lParam);
@@ -47,7 +45,6 @@ namespace rfb {
LRESULT SafeDispatchMessage(const MSG* msg);
};
-
};
#endif // __RFB_WIN32_SHATTER_H__
diff --git a/rfb_win32/WMWindowCopyRect.cxx b/rfb_win32/WMWindowCopyRect.cxx
index 46d85eac..63c1da2e 100644
--- a/rfb_win32/WMWindowCopyRect.cxx
+++ b/rfb_win32/WMWindowCopyRect.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -29,55 +29,39 @@ static LogWriter vlog("WMCopyRect");
// -=- WMHooks class
-rfb::win32::WMCopyRect::WMCopyRect() : clipper(0), fg_window(0) {
-}
-
-rfb::win32::WMCopyRect::~WMCopyRect() {
- if (clipper) delete clipper;
+rfb::win32::WMCopyRect::WMCopyRect() : ut(0), fg_window(0) {
}
bool
rfb::win32::WMCopyRect::processEvent() {
- if (clipper) {
- // 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)) {
- // 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;
- clipper->add_copied(copy_dest, delta);
- clipper->add_changed(Region(fg_window_rect).subtract(copy_dest));
- }
+ // 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;
}
+ fg_window = window;
+ fg_window_rect = winrect;
} else {
fg_window = 0;
}
+ } else {
+ fg_window = 0;
}
return false;
}
bool
-rfb::win32::WMCopyRect::setClipRect(const Rect& r) {
- clip_region = r;
- if (clipper) clipper->set_clip_region(clip_region);
- return true;
-}
-
-bool
-rfb::win32::WMCopyRect::setUpdateTracker(UpdateTracker* ut) {
- if (clipper) delete clipper;
- clipper = new ClippedUpdateTracker(*ut);
- clipper->set_clip_region(clip_region);
+rfb::win32::WMCopyRect::setUpdateTracker(UpdateTracker* ut_) {
+ ut = ut_;
return true;
}
diff --git a/rfb_win32/WMWindowCopyRect.h b/rfb_win32/WMWindowCopyRect.h
index 0750d86e..5a0e876d 100644
--- a/rfb_win32/WMWindowCopyRect.h
+++ b/rfb_win32/WMWindowCopyRect.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -36,15 +36,12 @@ namespace rfb {
class WMCopyRect {
public:
WMCopyRect();
- ~WMCopyRect();
bool processEvent();
- bool setClipRect(const Rect& cr);
bool setUpdateTracker(UpdateTracker* ut);
protected:
- ClippedUpdateTracker* clipper;
- Region clip_region;
+ UpdateTracker* ut;
void* fg_window;
Rect fg_window_rect;
};
diff --git a/rfb_win32/Win32Util.cxx b/rfb_win32/Win32Util.cxx
index 28fae2e8..ef8039ab 100644
--- a/rfb_win32/Win32Util.cxx
+++ b/rfb_win32/Win32Util.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -18,221 +18,30 @@
// Win32Util.cxx
+#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Win32Util.h>
-#include <rdr/Exception.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/Handle.h>
#include <rdr/HexOutStream.h>
-
+#include <rdr/Exception.h>
namespace rfb {
namespace win32 {
-LogicalPalette::LogicalPalette() : palette(0), numEntries(0) {
- 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::~LogicalPalette() {
- if (palette)
- if (!DeleteObject(palette))
- throw rdr::SystemException("del palette failed", GetLastError());
-}
-
-void LogicalPalette::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;
-}
-
-
-static LogWriter dcLog("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());
- }
-
- // -=- Munge the bitmap info here
- switch (bi.bmiHeader.biBitCount) {
- case 1:
- case 4:
- bi.bmiHeader.biBitCount = 8;
- break;
- case 24:
- bi.bmiHeader.biBitCount = 32;
- break;
- }
- bi.bmiHeader.biPlanes = 1;
-
- format.trueColour = bi.bmiHeader.biBitCount > 8;
- format.bigEndian = 0;
- format.bpp = format.depth = 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
- dcLog.info("16-bit High Color");
- rMask = 0x7c00;
- bMask = 0x001f;
- gMask = 0x03e0;
- format.depth = 15;
- break;
- case 24:
- case 32:
- // RGB 888 - True Colour
- dcLog.info("24/32-bit High Color");
- rMask = 0xff0000;
- gMask = 0x00ff00;
- bMask = 0x0000ff;
- format.depth = 24;
- break;
- default:
- dcLog.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;
- dcLog.info("BitFields format: %lu, (%lx, %lx, %lx)",
- bi.bmiHeader.biBitCount, rMask, gMask, bMask);
- if (format.bpp == 32)
- format.depth = 24; // ...probably
- 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);
- }
-
- return format;
-}
-
-
-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);
-}
-
-
-CompatibleBitmap::CompatibleBitmap(HDC hdc, int width, int height) {
- hbmp = CreateCompatibleBitmap(hdc, width, height);
- if (!hbmp)
- throw rdr::SystemException("CreateCompatibleBitmap() failed",
- GetLastError());
-}
-CompatibleBitmap::~CompatibleBitmap() {
- if (hbmp) DeleteObject(hbmp);
-}
-
-
-PaletteSelector::PaletteSelector(HDC dc, HPALETTE pal) : device(dc), redrawRequired(false) {
- oldPal = SelectPalette(dc, pal, FALSE);
- redrawRequired = RealizePalette(dc) > 0;
-}
-PaletteSelector::~PaletteSelector() {
- if (oldPal) SelectPalette(device, oldPal, TRUE);
-}
-
-
-IconInfo::IconInfo(HICON icon) {
- if (!GetIconInfo(icon, this))
- throw rdr::SystemException("GetIconInfo() failed", GetLastError());
-}
-IconInfo::~IconInfo() {
- if (hbmColor)
- DeleteObject(hbmColor);
- if (hbmMask)
- DeleteObject(hbmMask);
-}
-
-
-ModuleFileName::ModuleFileName(HMODULE module) : TCharArray(MAX_PATH) {
- if (!module) module = GetModuleHandle(0);
- if (!GetModuleFileName(module, buf, MAX_PATH))
- buf[0] = 0;
-}
-
FileVersionInfo::FileVersionInfo(const TCHAR* filename) {
// Get executable name
ModuleFileName exeName;
- if (!filename) filename = exeName.buf;
+ 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;
@@ -249,7 +58,7 @@ FileVersionInfo::FileVersionInfo(const TCHAR* filename) {
const TCHAR* FileVersionInfo::getVerString(const TCHAR* name, DWORD langId) {
char langIdBuf[sizeof(langId)];
for (int i=sizeof(langIdBuf)-1; i>=0; i--) {
- langIdBuf[i] = langId & 0xff;
+ langIdBuf[i] = (char) (langId & 0xff);
langId = langId >> 8;
}
@@ -273,173 +82,31 @@ bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file) {
}
-static LogWriter dfbLog("DynamicFn");
-
-DynamicFnBase::DynamicFnBase(const TCHAR* dllName, const char* fnName) : dllHandle(0), fnPtr(0) {
- dllHandle = LoadLibrary(dllName);
- if (!dllHandle) {
- dfbLog.info("DLL %s not found (%d)", (const char*)CStr(dllName), GetLastError());
- return;
- }
- fnPtr = GetProcAddress(dllHandle, fnName);
- if (!fnPtr)
- dfbLog.info("proc %s not found in %s (%d)", fnName, (const char*)CStr(dllName), GetLastError());
-}
-
-DynamicFnBase::~DynamicFnBase() {
- if (dllHandle)
- FreeLibrary(dllHandle);
-}
-
-
-static LogWriter miLog("MonitorInfo");
-
-MonitorInfo::MonitorInfo(HWND window) {
-#if (WINVER >= 0x0500)
- typedef HMONITOR (WINAPI *_MonitorFromWindow_proto)(HWND,DWORD);
- rfb::win32::DynamicFn<_MonitorFromWindow_proto> _MonitorFromWindow(_T("user32.dll"), "MonitorFromWindow");
- typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
- rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
-
- // Can we dynamically link to the monitor functions?
- if (_MonitorFromWindow.isValid()) {
- if (_GetMonitorInfo.isValid()) {
- HMONITOR monitor = (*_MonitorFromWindow)(window, MONITOR_DEFAULTTONEAREST);
- miLog.debug("monitor=%lx", monitor);
- if (monitor) {
- memset(this, 0, sizeof(MONITORINFOEXA));
- cbSize = sizeof(MONITORINFOEXA);
- if ((*_GetMonitorInfo)(monitor, this)) {
- miLog.debug("monitor is %d,%d-%d,%d", rcMonitor.left, rcMonitor.top, rcMonitor.right, rcMonitor.bottom);
- miLog.debug("work area is %d,%d-%d,%d", rcWork.left, rcWork.top, rcWork.right, rcWork.bottom);
- miLog.debug("device is \"%s\"", szDevice);
- return;
- }
- miLog.error("failed to get monitor info: %ld", GetLastError());
- }
- } else {
- miLog.debug("GetMonitorInfo not found");
- }
- } else {
- miLog.debug("MonitorFromWindow not found");
- }
-#else
-#pragma message ("not building in GetMonitorInfo")
- cbSize = sizeof(MonitorInfo);
- szDevice[0] = 0;
-#endif
-
- // Legacy fallbacks - just return the desktop settings
- miLog.debug("using legacy fall-backs");
- HWND desktop = GetDesktopWindow();
- GetWindowRect(desktop, &rcMonitor);
- SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
- dwFlags = 0;
-}
-
-
-#if (WINVER >= 0x0500)
-
-struct moveToMonitorData {
- HWND window;
- const char* monitorName;
-};
-
-typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
-static rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
-
-static BOOL CALLBACK moveToMonitorEnumProc(HMONITOR monitor,
- HDC dc,
- LPRECT pos,
- LPARAM d) {
- moveToMonitorData* data = (moveToMonitorData*)d;
- MONITORINFOEXA info;
- memset(&info, 0, sizeof(info));
- info.cbSize = sizeof(info);
-
- if ((*_GetMonitorInfo)(monitor, &info)) {
- if (stricmp(data->monitorName, info.szDevice) == 0) {
- SetWindowPos(data->window, 0,
- info.rcMonitor.left, info.rcMonitor.top,
- info.rcMonitor.right, info.rcMonitor.bottom,
- SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-#endif
-
-void moveToMonitor(HWND handle, const char* device) {
- miLog.debug("moveToMonitor %s", device);
-
-#if (WINVER >= 0x500)
- typedef BOOL (WINAPI *_EnumDisplayMonitors_proto)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
- rfb::win32::DynamicFn<_EnumDisplayMonitors_proto> _EnumDisplayMonitors(_T("user32.dll"), "EnumDisplayMonitors");
- if (!_EnumDisplayMonitors.isValid()) {
- miLog.debug("EnumDisplayMonitors not found");
- return;
- }
-
- moveToMonitorData data;
- data.window = handle;
- data.monitorName = device;
-
- (*_EnumDisplayMonitors)(0, 0, &moveToMonitorEnumProc, (LPARAM)&data);
-#endif
-}
-
-
-void centerWindow(HWND handle, HWND parent, bool clipToParent) {
+void centerWindow(HWND handle, HWND parent) {
RECT r;
- if (parent && IsWindowVisible(parent)) {
- if (!GetWindowRect(parent, &r)) return;
- } else {
- MonitorInfo mi(handle);
+ MonitorInfo mi(parent ? parent : handle);
+ if (!parent || !IsWindowVisible(parent) || !GetWindowRect(parent, &r))
r=mi.rcWork;
- }
- centerWindow(handle, r, clipToParent);
+ centerWindow(handle, r);
+ mi.clipTo(handle);
}
-void centerWindow(HWND handle, const RECT& r, bool clipToRect) {
+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;
- if (clipToRect) {
- w = min(r.right-r.left, w);
- h = min(r.bottom-r.top, h);
- }
int x = (r.left + r.right - w)/2;
int y = (r.top + r.bottom - h)/2;
- UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | (clipToRect ? 0 : SWP_NOSIZE);
- SetWindowPos(handle, 0, x, y, w, h, flags);
+ UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE;
+ SetWindowPos(handle, 0, x, y, 0, 0, flags);
}
-
-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);
+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/rfb_win32/Win32Util.h b/rfb_win32/Win32Util.h
index 5f0ab5a0..8cc1a2b9 100644
--- a/rfb_win32/Win32Util.h
+++ b/rfb_win32/Win32Util.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,105 +25,12 @@
#ifndef __RFB_WIN32_GDIUTIL_H__
#define __RFB_WIN32_GDIUTIL_H__
-#include <rfb/ColourMap.h>
-#include <rfb/PixelFormat.h>
-#include <rfb/Rect.h>
#include <rfb_win32/TCharArray.h>
namespace rfb {
namespace win32 {
- class LogicalPalette {
- public:
- LogicalPalette();
- ~LogicalPalette();
- void setEntries(int start, int count, const Colour* cols);
- HPALETTE getHandle() {return palette;}
- protected:
- HPALETTE palette;
- int numEntries;
- };
-
- class DeviceContext {
- public:
- DeviceContext() : dc(0) {}
- virtual ~DeviceContext() {}
- operator HDC() const {return dc;}
- PixelFormat getPF() const;
- static PixelFormat getPF(HDC dc);
- protected:
- HDC dc;
- };
-
- class WindowDC : public DeviceContext {
- public:
- WindowDC(HWND wnd);
- virtual ~WindowDC();
- protected:
- HWND hwnd;
- };
-
- class CompatibleDC : public DeviceContext {
- public:
- CompatibleDC(HDC existing);
- virtual ~CompatibleDC();
- };
-
- class BitmapDC : public CompatibleDC {
- public:
- BitmapDC(HDC hdc, HBITMAP hbitmap);
- ~BitmapDC();
- protected:
- HBITMAP oldBitmap;
- };
-
- class CompatibleBitmap {
- public:
- CompatibleBitmap(HDC hdc, int width, int height);
- virtual ~CompatibleBitmap();
- operator HBITMAP() const {return hbmp;}
- protected:
- HBITMAP hbmp;
- };
-
- 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;
- }
-
- class PaletteSelector {
- public:
- PaletteSelector(HDC dc, HPALETTE pal);
- ~PaletteSelector();
- bool isRedrawRequired() {return redrawRequired;}
- protected:
- HPALETTE oldPal;
- HDC device;
- bool redrawRequired;
- };
-
- struct IconInfo : public ICONINFO {
- IconInfo(HICON icon);
- ~IconInfo();
- };
-
- struct ModuleFileName : public TCharArray {
- ModuleFileName(HMODULE module=0);
- };
-
struct FileVersionInfo : public TCharArray {
FileVersionInfo(const TCHAR* filename=0);
const TCHAR* getVerString(const TCHAR* name, DWORD langId = 0x080904b0);
@@ -131,84 +38,15 @@ namespace rfb {
bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file);
- class DynamicFnBase {
- public:
- DynamicFnBase(const TCHAR* dllName, const char* fnName);
- ~DynamicFnBase();
- bool isValid() const {return fnPtr != 0;}
- protected:
- void* fnPtr;
- HMODULE dllHandle;
- };
-
- template<class T> class DynamicFn : public DynamicFnBase {
- public:
- DynamicFn(const TCHAR* dllName, const char* fnName) : DynamicFnBase(dllName, fnName) {}
- T operator *() const {return (T)fnPtr;};
- };
-
- // Structure containing info on the monitor nearest the window.
- // Copes with multi-monitor OSes and older ones.
-#if (WINVER >= 0x0500)
- struct MonitorInfo : MONITORINFOEXA {
- MonitorInfo(HWND hwnd);
- };
-#else
- struct MonitorInfo {
- MonitorInfo(HWND hwnd);
- DWORD cbSize;
- RECT rcMonitor;
- RECT rcWork;
- DWORD dwFlags;
- char szDevice[1]; // Always null...
- };
-#endif
- void moveToMonitor(HWND handle, const char* device);
-
- class Handle {
- public:
- Handle(HANDLE h_=0) : h(h_) {}
- ~Handle() {
- if (h) CloseHandle(h);
- }
- operator HANDLE() {return h;}
- HANDLE h;
- };
-
// 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, bool clipToRect=false);
- void centerWindow(HWND handle, HWND parent, bool clipToRect=false);
+ void centerWindow(HWND handle, const RECT& r);
+ void centerWindow(HWND handle, HWND parent);
- // MsgBox helper function. Define rfb::win32::AppName somewhere in your
- // code and MsgBox will use its value in informational messages.
- extern TStr AppName;
- int MsgBox(HWND parent, const TCHAR* message, UINT flags);
-
- // 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(""));
- }
- };
-
- // 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;
- };
+ // resizeWindow resizes a window about its center
+ void resizeWindow(HWND handle, int width, int height);
};
diff --git a/rfb_win32/keymap.h b/rfb_win32/keymap.h
index 69ce66f2..a340d09d 100644
--- a/rfb_win32/keymap.h
+++ b/rfb_win32/keymap.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb_win32/rfb_win32.dsp b/rfb_win32/rfb_win32.dsp
index e9b746ca..664e3966 100644
--- a/rfb_win32/rfb_win32.dsp
+++ b/rfb_win32/rfb_win32.dsp
@@ -42,7 +42,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release"
# 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 ".." /FI"msvcwarning.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
@@ -65,7 +65,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug"
# 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 ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_LIB" /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
@@ -88,7 +88,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug_Unicode"
# 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 ".." /FI"msvcwarning.h" /D "_LIB" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_LIB" /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
@@ -134,6 +134,10 @@ 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
@@ -146,6 +150,14 @@ 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
@@ -158,6 +170,14 @@ 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
@@ -186,6 +206,18 @@ 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
@@ -210,10 +242,18 @@ 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
@@ -250,6 +290,10 @@ 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
@@ -262,6 +306,14 @@ 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
@@ -270,6 +322,10 @@ 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
@@ -282,10 +338,26 @@ 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
@@ -302,6 +374,30 @@ 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
@@ -330,6 +426,18 @@ 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
@@ -358,6 +466,10 @@ 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
@@ -366,6 +478,10 @@ 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