Initial commit

This commit is contained in:
matt
2020-09-20 12:16:44 +00:00
parent 09a4460ddb
commit 408c005d3e
839 changed files with 190481 additions and 0 deletions

15
win/CMakeLists.txt Normal file
View File

@@ -0,0 +1,15 @@
include_directories(${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/win)
configure_file(resdefs.h.in ${CMAKE_CURRENT_BINARY_DIR}/resdefs.h)
IF(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-D_DEBUG)
ENDIF()
add_subdirectory(rfb_win32)
if(BUILD_WINVNC)
add_subdirectory(vncconfig)
add_subdirectory(winvnc)
add_subdirectory(wm_hooks)
endif()

View File

@@ -0,0 +1,47 @@
//
// Values are 32 bit values layed out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-------------------------------+
// |Sev|C|R| Facility | Code |
// +---+-+-+-----------------------+-------------------------------+
//
// where
//
// Sev - is the severity code
//
// 00 - Success
// 01 - Informational
// 10 - Warning
// 11 - Error
//
// C - is the Customer code flag
//
// R - is a reserved bit
//
// Facility - is the facility code
//
// Code - is the facility's status code
//
//
// Define the facility codes
//
//
// Define the severity codes
//
//
// MessageId: VNC4LogMessage
//
// MessageText:
//
// %1: %2
//
//
//
#define VNC4LogMessage 0x00000001L

View File

@@ -0,0 +1,7 @@
MessageId=0x1
Severity=Success
SymbolicName=VNC4LogMessage
Language=English
%1: %2

View File

@@ -0,0 +1,2 @@
LANGUAGE 0x9,0x1
1 11 MSG00001.bin

3
win/resdefs.h.in Normal file
View File

@@ -0,0 +1,3 @@
#define __VERSIONSTR "@VERSION@\0"
#define __RCVERSION @RCVERSION@
#define __RCVERSIONSTR "@RCVERSION@\0"

View File

@@ -0,0 +1,49 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rfb_win32/AboutDialog.h>
#include <rfb_win32/Win32Util.h>
#include <rfb_win32/TCharArray.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("AboutDialog");
AboutDialog AboutDialog::instance;
AboutDialog::AboutDialog() : Dialog(GetModuleHandle(0)) {
}
bool AboutDialog::showDialog() {
return Dialog::showDialog(MAKEINTRESOURCE(DialogId));
}
void AboutDialog::initDialog() {
// Set the build time field
SetWindowText(GetDlgItem(handle, BuildTime), TStr(buildTime));
// Get our executable's version info
FileVersionInfo verInfo;
SetWindowText(GetDlgItem(handle, Version), verInfo.getVerString(_T("ProductVersion")));
SetWindowText(GetDlgItem(handle, Copyright), verInfo.getVerString(_T("LegalCopyright")));
SetWindowText(GetDlgItem(handle, Description), verInfo.getVerString(_T("ProductName")));
}

View File

@@ -0,0 +1,55 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- AboutDialog.h
#ifndef __RFB_WIN32_ABOUT_DIALOG_H__
#define __RFB_WIN32_ABOUT_DIALOG_H__
#include <rfb_win32/Dialog.h>
#include <rfb/util.h>
extern const char* buildTime;
namespace rfb {
namespace win32 {
class AboutDialog : Dialog {
public:
AboutDialog();
virtual bool showDialog();
virtual void initDialog();
static AboutDialog instance;
typedef WORD LabelId;
static const LabelId DialogId; // Resource ID of the About dialog
static const LabelId BuildTime; // Resource ID of the BuildTime label in the dialog
static const LabelId Version; // etc...
static const LabelId Copyright;
static const LabelId Description;
protected:
WORD dialogId;
};
};
};
#endif

View File

@@ -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

View File

@@ -0,0 +1,40 @@
set(RFB_WIN32_SOURCES
AboutDialog.cxx
Clipboard.cxx
CurrentUser.cxx
DeviceContext.cxx
DeviceFrameBuffer.cxx
Dialog.cxx
DIBSectionBuffer.cxx
EventManager.cxx
LaunchProcess.cxx
ListViewControl.cxx
MonitorInfo.cxx
MsgWindow.cxx
RegConfig.cxx
Registry.cxx
SecurityPage.cxx
SDisplayCorePolling.cxx
SDisplayCoreWMHooks.cxx
SDisplay.cxx
Security.cxx
Service.cxx
SInput.cxx
SocketManager.cxx
TCharArray.cxx
TsSessions.cxx
Win32Util.cxx
WMCursor.cxx
WMHooks.cxx
WMNotifier.cxx
WMPoller.cxx
WMShatter.cxx
WMWindowCopyRect.cxx)
if(BUILD_WINVNC)
set(RFB_WIN32_SOURCES ${RFB_WIN32_SOURCES} CleanDesktop.cxx)
endif()
add_library(rfb_win32 STATIC ${RFB_WIN32_SOURCES})
target_link_libraries(rfb_win32 user32.lib comctl32.lib wtsapi32.lib version.lib)

View File

@@ -0,0 +1,271 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- CleanDesktop.cxx
#include <windows.h>
#include <wininet.h>
#include <shlobj.h>
#include <rfb_win32/CleanDesktop.h>
#include <rfb_win32/CurrentUser.h>
#include <rfb_win32/Registry.h>
#include <rfb/LogWriter.h>
#include <rdr/Exception.h>
#include <os/os.h>
#include <set>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("CleanDesktop");
struct ActiveDesktop {
ActiveDesktop() : handle(0) {
// - Contact Active Desktop
HRESULT result = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
IID_IActiveDesktop, (PVOID*)&handle);
if (result != S_OK)
throw rdr::SystemException("failed to contact Active Desktop", result);
}
~ActiveDesktop() {
if (handle)
handle->Release();
}
// enableItem
// enables or disables the Nth Active Desktop item
bool enableItem(int i, bool enable_) {
COMPONENT item;
memset(&item, 0, sizeof(item));
item.dwSize = sizeof(item);
HRESULT hr = handle->GetDesktopItem(i, &item, 0);
if (hr != S_OK) {
vlog.error("unable to GetDesktopItem %d: %ld", i, hr);
return false;
}
item.fChecked = enable_;
vlog.debug("%sbling %d: \"%s\"", enable_ ? "ena" : "disa", i, (const char*)CStr(item.wszFriendlyName));
hr = handle->ModifyDesktopItem(&item, COMP_ELEM_CHECKED);
return hr == S_OK;
}
// enable
// Attempts to enable/disable Active Desktop, returns true if the setting changed,
// false otherwise.
// If Active Desktop *can* be enabled/disabled then that is done.
// If Active Desktop is always on (XP/2K3) then instead the individual items are
// disabled, and true is returned to indicate that they need to be restored later.
bool enable(bool enable_) {
bool modifyComponents = false;
vlog.debug("ActiveDesktop::enable");
// - Firstly, try to disable Active Desktop entirely
HRESULT hr;
COMPONENTSOPT adOptions;
memset(&adOptions, 0, sizeof(adOptions));
adOptions.dwSize = sizeof(adOptions);
// Attempt to actually disable/enable AD
hr = handle->GetDesktopItemOptions(&adOptions, 0);
if (hr == S_OK) {
// If Active Desktop is already in the desired state then return false (no change)
// NB: If AD is enabled AND restoreItems is set then we regard it as disabled...
if (((adOptions.fActiveDesktop==0) && restoreItems.empty()) == (enable_==false))
return false;
adOptions.fActiveDesktop = enable_;
hr = handle->SetDesktopItemOptions(&adOptions, 0);
}
// Apply the change, then test whether it actually took effect
if (hr == S_OK)
hr = handle->ApplyChanges(AD_APPLY_REFRESH);
if (hr == S_OK)
hr = handle->GetDesktopItemOptions(&adOptions, 0);
if (hr == S_OK)
modifyComponents = (adOptions.fActiveDesktop==0) != (enable_==false);
if (hr != S_OK) {
vlog.error("failed to get/set Active Desktop options: %ld", hr);
return false;
}
if (enable_) {
// - We are re-enabling Active Desktop. If there are components in restoreItems
// then restore them!
std::set<int>::const_iterator i;
for (i=restoreItems.begin(); i!=restoreItems.end(); i++) {
enableItem(*i, true);
}
restoreItems.clear();
} else if (modifyComponents) {
// - Disable all currently enabled items, and add the disabled ones to restoreItems
int itemCount = 0;
hr = handle->GetDesktopItemCount(&itemCount, 0);
if (hr != S_OK) {
vlog.error("failed to get desktop item count: %ld", hr);
return false;
}
for (int i=0; i<itemCount; i++) {
if (enableItem(i, false))
restoreItems.insert(i);
}
}
// - Apply whatever changes we have made, but DON'T save them!
hr = handle->ApplyChanges(AD_APPLY_REFRESH);
return hr == S_OK;
}
IActiveDesktop* handle;
std::set<int> restoreItems;
};
DWORD SysParamsInfo(UINT action, UINT param, PVOID ptr, UINT ini) {
DWORD r = ERROR_SUCCESS;
if (!SystemParametersInfo(action, param, ptr, ini)) {
r = GetLastError();
vlog.info("SPI error: %lu", r);
}
return r;
}
CleanDesktop::CleanDesktop() : restoreActiveDesktop(false),
restoreWallpaper(false),
restoreEffects(false) {
CoInitialize(0);
}
CleanDesktop::~CleanDesktop() {
enableEffects();
enableWallpaper();
CoUninitialize();
}
void CleanDesktop::disableWallpaper() {
try {
ImpersonateCurrentUser icu;
vlog.debug("disable desktop wallpaper/Active Desktop");
// -=- First attempt to remove the wallpaper using Active Desktop
try {
ActiveDesktop ad;
if (ad.enable(false))
restoreActiveDesktop = true;
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
}
// -=- Switch of normal wallpaper and notify apps
SysParamsInfo(SPI_SETDESKWALLPAPER, 0, (PVOID) "", SPIF_SENDCHANGE);
restoreWallpaper = true;
} catch (rdr::Exception& e) {
vlog.info("%s", e.str());
}
}
void CleanDesktop::enableWallpaper() {
try {
ImpersonateCurrentUser icu;
if (restoreActiveDesktop) {
vlog.debug("restore Active Desktop");
// -=- First attempt to re-enable Active Desktop
try {
ActiveDesktop ad;
ad.enable(true);
restoreActiveDesktop = false;
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
}
}
if (restoreWallpaper) {
vlog.debug("restore desktop wallpaper");
// -=- Then restore the standard wallpaper if required
SysParamsInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
restoreWallpaper = false;
}
} catch (rdr::Exception& e) {
vlog.info("%s", e.str());
}
}
void CleanDesktop::disableEffects() {
try {
ImpersonateCurrentUser icu;
vlog.debug("disable desktop effects");
SysParamsInfo(SPI_SETFONTSMOOTHING, FALSE, 0, SPIF_SENDCHANGE);
if (SysParamsInfo(SPI_GETUIEFFECTS, 0, &uiEffects, 0) == ERROR_CALL_NOT_IMPLEMENTED) {
SysParamsInfo(SPI_GETCOMBOBOXANIMATION, 0, &comboBoxAnim, 0);
SysParamsInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradientCaptions, 0);
SysParamsInfo(SPI_GETHOTTRACKING, 0, &hotTracking, 0);
SysParamsInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &listBoxSmoothScroll, 0);
SysParamsInfo(SPI_GETMENUANIMATION, 0, &menuAnim, 0);
SysParamsInfo(SPI_SETCOMBOBOXANIMATION, 0, FALSE, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETGRADIENTCAPTIONS, 0, FALSE, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETHOTTRACKING, 0, FALSE, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, FALSE, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETMENUANIMATION, 0, FALSE, SPIF_SENDCHANGE);
} else {
SysParamsInfo(SPI_SETUIEFFECTS, 0, FALSE, SPIF_SENDCHANGE);
// We *always* restore UI effects overall, since there is no Windows GUI to do it
uiEffects = TRUE;
}
restoreEffects = true;
} catch (rdr::Exception& e) {
vlog.info("%s", e.str());
}
}
void CleanDesktop::enableEffects() {
try {
if (restoreEffects) {
ImpersonateCurrentUser icu;
vlog.debug("restore desktop effects");
RegKey desktopCfg;
desktopCfg.openKey(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"));
SysParamsInfo(SPI_SETFONTSMOOTHING, desktopCfg.getInt(_T("FontSmoothing"), 0) != 0, 0, SPIF_SENDCHANGE);
if (SysParamsInfo(SPI_SETUIEFFECTS, 0, (void*)(intptr_t)uiEffects, SPIF_SENDCHANGE) == ERROR_CALL_NOT_IMPLEMENTED) {
SysParamsInfo(SPI_SETCOMBOBOXANIMATION, 0, (void*)(intptr_t)comboBoxAnim, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETGRADIENTCAPTIONS, 0, (void*)(intptr_t)gradientCaptions, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETHOTTRACKING, 0, (void*)(intptr_t)hotTracking, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, (void*)(intptr_t)listBoxSmoothScroll, SPIF_SENDCHANGE);
SysParamsInfo(SPI_SETMENUANIMATION, 0, (void*)(intptr_t)menuAnim, SPIF_SENDCHANGE);
}
restoreEffects = false;
}
} catch (rdr::Exception& e) {
vlog.info("%s", e.str());
}
}

View File

@@ -0,0 +1,57 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- CleanDesktop.h
#ifndef __RFB_WIN32_CLEANDESKTOP_H__
#define __RFB_WIN32_CLEANDESKTOP_H__
#include <rfb_win32/TCharArray.h>
namespace rfb {
namespace win32 {
class CleanDesktop {
public:
CleanDesktop();
~CleanDesktop();
void disableWallpaper();
void enableWallpaper();
void disablePattern();
void enablePattern();
void disableEffects();
void enableEffects();
private:
bool restoreActiveDesktop;
bool restoreWallpaper;
bool restorePattern;
bool restoreEffects;
BOOL uiEffects;
BOOL comboBoxAnim, gradientCaptions, hotTracking, listBoxSmoothScroll, menuAnim;
};
}; // win32
}; // rfb
#endif // __RFB_WIN32_CLEANDESKTOP_H__

201
win/rfb_win32/Clipboard.cxx Normal file
View File

@@ -0,0 +1,201 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Clipboard.cxx
#include <rfb_win32/Clipboard.h>
#include <rfb_win32/WMShatter.h>
#include <rfb/util.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("Clipboard");
//
// -=- CR/LF handlers
//
char*
dos2unix(const char* text) {
int len = strlen(text)+1;
char* unix = new char[strlen(text)+1];
int i, j=0;
for (i=0; i<len; i++) {
if (text[i] != '\x0d')
unix[j++] = text[i];
}
return unix;
}
char*
unix2dos(const char* text) {
int len = strlen(text)+1;
char* dos = new char[strlen(text)*2+1];
int i, j=0;
for (i=0; i<len; i++) {
if (text[i] == '\x0a')
dos[j++] = '\x0d';
dos[j++] = text[i];
}
return dos;
}
//
// -=- ISO-8859-1 (Latin 1) filter (in-place)
//
void
removeNonISOLatin1Chars(char* text) {
int len = strlen(text);
int i=0, j=0;
for (; i<len; i++) {
if (((text[i] >= 1) && (text[i] <= 127)) ||
((text[i] >= 160) && (text[i] <= 255)))
text[j++] = text[i];
}
text[j] = 0;
}
//
// -=- Clipboard object
//
Clipboard::Clipboard()
: MsgWindow(_T("Clipboard")), notifier(0), next_window(0) {
next_window = SetClipboardViewer(getHandle());
vlog.debug("registered clipboard handler");
}
Clipboard::~Clipboard() {
vlog.debug("removing %p from chain (next is %p)", getHandle(), next_window);
ChangeClipboardChain(getHandle(), next_window);
}
LRESULT
Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CHANGECBCHAIN:
vlog.debug("change clipboard chain (%I64x, %I64x)",
(long long)wParam, (long long)lParam);
if ((HWND) wParam == next_window)
next_window = (HWND) lParam;
else if (next_window != 0)
SendMessage(next_window, msg, wParam, lParam);
else
vlog.error("bad clipboard chain change!");
break;
case WM_DRAWCLIPBOARD:
{
HWND owner = GetClipboardOwner();
if (owner == getHandle()) {
vlog.debug("local clipboard changed by me");
} else {
vlog.debug("local clipboard changed by %p", owner);
// Open the clipboard
if (OpenClipboard(getHandle())) {
// Get the clipboard data
HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
if (cliphandle) {
char* clipdata = (char*) GlobalLock(cliphandle);
// Notify clients
if (notifier) {
if (!clipdata) {
notifier->notifyClipboardChanged(0, 0);
} else {
CharArray unix_text;
unix_text.buf = dos2unix(clipdata);
removeNonISOLatin1Chars(unix_text.buf);
notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf));
}
} else {
vlog.debug("no clipboard notifier registered");
}
// Release the buffer and close the clipboard
GlobalUnlock(cliphandle);
}
CloseClipboard();
}
}
}
if (next_window)
SendMessage(next_window, msg, wParam, lParam);
return 0;
};
return MsgWindow::processMessage(msg, wParam, lParam);
};
void
Clipboard::setClipText(const char* text) {
HANDLE clip_handle = 0;
try {
// - Firstly, we must open the clipboard
if (!OpenClipboard(getHandle()))
throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());
// - Pre-process the supplied clipboard text into DOS format
CharArray dos_text;
dos_text.buf = unix2dos(text);
removeNonISOLatin1Chars(dos_text.buf);
int dos_text_len = strlen(dos_text.buf);
// - Allocate global memory for the data
clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, dos_text_len+1);
char* data = (char*) GlobalLock(clip_handle);
memcpy(data, dos_text.buf, dos_text_len+1);
data[dos_text_len] = 0;
GlobalUnlock(clip_handle);
// - Next, we must clear out any existing data
if (!EmptyClipboard())
throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());
// - Set the new clipboard data
if (!SetClipboardData(CF_TEXT, clip_handle))
throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
clip_handle = 0;
vlog.debug("set clipboard");
} catch (rdr::Exception& e) {
vlog.debug("%s", e.str());
}
// - Close the clipboard
if (!CloseClipboard())
vlog.debug("unable to close Win32 clipboard: %lu", GetLastError());
else
vlog.debug("closed clipboard");
if (clip_handle) {
vlog.debug("freeing clipboard handle");
GlobalFree(clip_handle);
}
}

66
win/rfb_win32/Clipboard.h Normal file
View File

@@ -0,0 +1,66 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Clipboard.h
//
// The Clipboard is used to set the system clipboard, and to get callbacks
// when the system clipboard has changed.
#ifndef __RFB_WIN32_CLIPBOARD_H__
#define __RFB_WIN32_CLIPBOARD_H__
#include <rfb/SDesktop.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/DeviceFrameBuffer.h>
namespace rfb {
namespace win32 {
class Clipboard : MsgWindow {
public:
// -=- Abstract base class for callback recipients
class Notifier {
public:
virtual void notifyClipboardChanged(const char* text, int len) = 0;
virtual ~Notifier() {};
};
Clipboard();
~Clipboard();
// - Set the notifier to use
void setNotifier(Notifier* cbn) {notifier = cbn;}
// - Set the clipboard contents
void setClipText(const char* text);
protected:
// - Internal MsgWindow callback
virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
Notifier* notifier;
HWND next_window;
};
};
};
#endif // __RFB_WIN32_CLIPBOARD_H__

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,121 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Currentuser.cxx
#include <stdlib.h>
#include <rfb/LogWriter.h>
#include <rfb_win32/CurrentUser.h>
#include <rfb_win32/Service.h>
#include <lmcons.h>
#include <wtsapi32.h>
using namespace rfb;
using namespace win32;
static LogWriter vlog("CurrentUser");
const TCHAR* shellIconClass = _T("Shell_TrayWnd");
BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam) {
TCHAR className[16];
if (GetClassName(hwnd, className, sizeof(className)) &&
(_tcscmp(className, shellIconClass) == 0)) {
vlog.debug("located tray icon window (%s)", (const char*)CStr(className));
DWORD processId = 0;
GetWindowThreadProcessId(hwnd, &processId);
if (!processId)
return TRUE;
Handle process = OpenProcess(MAXIMUM_ALLOWED, FALSE, processId);
if (!process.h)
return TRUE;
if (!OpenProcessToken(process, MAXIMUM_ALLOWED, (HANDLE*)lParam))
return TRUE;
vlog.debug("obtained user token");
return FALSE;
}
return TRUE;
}
BOOL CALLBACK enumDesktops(LPTSTR lpszDesktop, LPARAM lParam) {
HDESK desktop = OpenDesktop(lpszDesktop, 0, FALSE, DESKTOP_ENUMERATE);
vlog.debug("opening \"%s\"", lpszDesktop);
if (!desktop) {
vlog.info("desktop \"%s\" inaccessible", (const char*)CStr(lpszDesktop));
return TRUE;
}
BOOL result = EnumDesktopWindows(desktop, enumWindows, lParam);
if (!CloseDesktop(desktop))
vlog.info("unable to close desktop: %ld", GetLastError());
return result;
}
CurrentUserToken::CurrentUserToken() {
if (isServiceProcess()) {
// Try to get the user token using the Terminal Services APIs
WTSQueryUserToken(-1, &h);
} 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);
h = INVALID_HANDLE_VALUE;
}
}
}
ImpersonateCurrentUser::ImpersonateCurrentUser() {
RegCloseKey(HKEY_CURRENT_USER);
if (!isServiceProcess())
return;
if (!token.canImpersonate())
throw rdr::Exception("Cannot impersonate unsafe or null token");
if (!ImpersonateLoggedOnUser(token)) {
DWORD err = GetLastError();
if (err != ERROR_CALL_NOT_IMPLEMENTED)
throw rdr::SystemException("Failed to impersonate user", GetLastError());
}
}
ImpersonateCurrentUser::~ImpersonateCurrentUser() {
if (!RevertToSelf()) {
DWORD err = GetLastError();
if (err != ERROR_CALL_NOT_IMPLEMENTED)
exit(err);
}
RegCloseKey(HKEY_CURRENT_USER);
}
UserName::UserName() : TCharArray(UNLEN+1) {
DWORD len = UNLEN+1;
if (!GetUserName(buf, &len))
throw rdr::SystemException("GetUserName failed", GetLastError());
}
UserSID::UserSID() {
CurrentUserToken token;
if (!token.canImpersonate())
return;
setSID(Sid::FromToken(token.h));
}

View File

@@ -0,0 +1,84 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// CurrentUser.h
// Helper class providing the session's logged on username, if
// a user is logged on. Also allows processes running under
// XP/2K3 etc to masquerade as the logged on user for security
// purposes
#ifndef __RFB_WIN32_CURRENT_USER_H__
#define __RFB_WIN32_CURRENT_USER_H__
#include <rfb_win32/Handle.h>
#include <rfb_win32/Security.h>
namespace rfb {
namespace win32 {
// CurrentUserToken
// CurrentUserToken is a Handle containing the security token
// for the currently logged-on user, or null if no user is
// logged on.
//
// 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 canImpersonate() const { return h; }
bool noUserLoggedOn() const { return !h; }
};
// ImpersonateCurrentUser
// Throws an exception on failure.
// Succeeds (trivially) if process is not running as service.
// Fails if CurrentUserToken is not valid.
// Fails if cannot impersonate token.
// Succeeds otherwise.
struct ImpersonateCurrentUser {
ImpersonateCurrentUser();
~ImpersonateCurrentUser();
CurrentUserToken token;
};
// UserName
// Returns the name of the user the thread is currently running as.
// Raises a SystemException in case of error.
struct UserName : public TCharArray {
UserName();
};
// UserSID
// Returns the SID of the currently logged-on user (i.e. the session user)
struct UserSID : public Sid {
UserSID();
};
}
}
#endif

View File

@@ -0,0 +1,180 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rfb_win32/DIBSectionBuffer.h>
#include <rfb_win32/DeviceContext.h>
#include <rfb_win32/BitmapInfo.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace win32;
static LogWriter vlog("DIBSectionBuffer");
DIBSectionBuffer::DIBSectionBuffer(HWND window_)
: bitmap(0), window(window_), device(0) {
memset(&format, 0, sizeof(format));
}
DIBSectionBuffer::DIBSectionBuffer(HDC device_)
: bitmap(0), window(0), device(device_) {
memset(&format, 0, sizeof(format));
}
DIBSectionBuffer::~DIBSectionBuffer() {
if (bitmap)
DeleteObject(bitmap);
}
void DIBSectionBuffer::setPF(const PixelFormat& pf) {
if (memcmp(&getPF(), &pf, sizeof(pf)) == 0) {
vlog.debug("pixel format unchanged by setPF()");
return;
}
if (!pf.trueColour)
throw rfb::Exception("palette format not supported");
format = pf;
recreateBuffer();
}
void DIBSectionBuffer::setSize(int w, int h) {
if (width_ == w && height_ == h) {
vlog.debug("size unchanged by setSize()");
return;
}
width_ = w;
height_ = h;
recreateBuffer();
}
inline void initMaxAndShift(DWORD mask, int* max, int* shift) {
for ((*shift) = 0; (mask & 1) == 0; (*shift)++) mask >>= 1;
(*max) = (rdr::U16)mask;
}
void DIBSectionBuffer::recreateBuffer() {
HBITMAP new_bitmap = 0;
rdr::U8* new_data = 0;
if (width_ && height_ && (format.depth != 0)) {
BitmapInfo bi;
memset(&bi, 0, sizeof(bi));
UINT iUsage = DIB_RGB_COLORS;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = format.bpp;
bi.bmiHeader.biSizeImage = (format.bpp / 8) * width_ * height_;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biWidth = width_;
bi.bmiHeader.biHeight = -height_;
bi.bmiHeader.biCompression = (format.bpp > 8) ? BI_BITFIELDS : BI_RGB;
bi.mask.red = format.pixelFromRGB((rdr::U16)~0, 0, 0);
bi.mask.green = format.pixelFromRGB(0, (rdr::U16)~0, 0);
bi.mask.blue = format.pixelFromRGB(0, 0, (rdr::U16)~0);
// Create a DIBSection to draw into
if (device)
new_bitmap = ::CreateDIBSection(device, (BITMAPINFO*)&bi.bmiHeader, iUsage,
(void**)&new_data, NULL, 0);
else
new_bitmap = ::CreateDIBSection(WindowDC(window), (BITMAPINFO*)&bi.bmiHeader, iUsage,
(void**)&new_data, NULL, 0);
if (!new_bitmap) {
int err = GetLastError();
throw rdr::SystemException("unable to create DIB section", err);
}
vlog.debug("recreateBuffer()");
} else {
vlog.debug("one of area or format not set");
}
if (new_bitmap && bitmap) {
vlog.debug("preserving bitmap contents");
// Copy the contents across
if (device) {
BitmapDC src_dev(device, bitmap);
BitmapDC dest_dev(device, new_bitmap);
BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY);
} else {
WindowDC wndDC(window);
BitmapDC src_dev(wndDC, bitmap);
BitmapDC dest_dev(wndDC, new_bitmap);
BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY);
}
}
if (bitmap) {
// Delete the old bitmap
DeleteObject(bitmap);
bitmap = 0;
data = 0;
}
if (new_bitmap) {
int bpp, depth;
int redMax, greenMax, blueMax;
int redShift, greenShift, blueShift;
// Set up the new bitmap
bitmap = new_bitmap;
data = new_data;
// Determine the *actual* DIBSection format
DIBSECTION ds;
if (!GetObject(bitmap, sizeof(ds), &ds))
throw rdr::SystemException("GetObject", GetLastError());
// Correct the "stride" of the DIB
// *** This code DWORD aligns each row - is that right???
stride = width_;
int bytesPerRow = stride * format.bpp/8;
if (bytesPerRow % 4) {
bytesPerRow += 4 - (bytesPerRow % 4);
stride = (bytesPerRow * 8) / format.bpp;
vlog.info("adjusting DIB stride: %d to %d", width_, stride);
}
// Calculate the PixelFormat for the DIB
bpp = depth = ds.dsBm.bmBitsPixel;
// Get the truecolour format used by the DIBSection
initMaxAndShift(ds.dsBitfields[0], &redMax, &redShift);
initMaxAndShift(ds.dsBitfields[1], &greenMax, &greenShift);
initMaxAndShift(ds.dsBitfields[2], &blueMax, &blueShift);
// Calculate the effective depth
depth = 0;
Pixel bits = ds.dsBitfields[0] | ds.dsBitfields[1] | ds.dsBitfields[2];
while (bits) {
depth++;
bits = bits >> 1;
}
if (depth > bpp)
throw Exception("Bad DIBSection format (depth exceeds bpp)");
format = PixelFormat(bpp, depth, false, true,
redMax, greenMax, blueMax,
redShift, greenShift, blueShift);
}
}

View File

@@ -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.
*/
// -=- DIBSectionBuffer.h
// A DIBSectionBuffer acts much like a standard PixelBuffer, but is associated
// with a particular window on-screen and can be drawn into that window if
// required, using the standard Win32 drawing operations.
#ifndef __RFB_WIN32_DIB_SECTION_BUFFER_H__
#define __RFB_WIN32_DIB_SECTION_BUFFER_H__
#include <windows.h>
#include <rfb/PixelBuffer.h>
#include <rfb/Region.h>
#include <rfb/Exception.h>
namespace rfb {
namespace win32 {
//
// -=- DIBSectionBuffer
//
class DIBSectionBuffer : public FullFramePixelBuffer {
public:
DIBSectionBuffer(HWND window);
DIBSectionBuffer(HDC device);
virtual ~DIBSectionBuffer();
virtual void setPF(const PixelFormat &pf);
virtual void setSize(int w, int h);
// *** virtual void copyRect(const Rect &dest, const Point &move_by_delta);
public:
HBITMAP bitmap;
protected:
void recreateBuffer();
HWND window;
HDC device;
};
};
};
#endif // __RFB_WIN32_DIB_SECTION_BUFFER_H__

View File

@@ -0,0 +1,200 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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) {
bool trueColour, bigEndian;
int bpp, depth;
int redMax, greenMax, blueMax;
int redShift, greenShift, blueShift;
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
trueColour = bi.bmiHeader.biBitCount > 8;
bigEndian = 0;
bpp = bi.bmiHeader.biBitCount;
if (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("%d-bit BitFields: (%lx, %lx, %lx)",
bi.bmiHeader.biBitCount, rMask, gMask, bMask);
break;
};
// Convert the data we just retrieved
initMaxAndShift(rMask, &redMax, &redShift);
initMaxAndShift(gMask, &greenMax, &greenShift);
initMaxAndShift(bMask, &blueMax, &blueShift);
// Calculate the depth from the colour shifts
depth = 0;
Pixel bits = rMask | gMask | bMask;
while (bits) {
depth++;
bits = bits >> 1;
}
// Check that the depth & bpp are valid
if (depth > bpp) {
vlog.error("depth exceeds bits per pixel!");
bpp = depth;
}
// Correct the bits-per-pixel to something we're happy with
if (bpp <= 16)
bpp = 16;
else if (bpp <= 32)
bpp = 32;
} else {
// Palettised format - depth reflects number of colours,
// but bits-per-pixel is ALWAYS 8
depth = bpp;
if (bpp < 8)
bpp = 8;
vlog.info("%d-colour palettised", 1<<depth);
// Aren't really used, but set them to keep the compiler happy
redMax = redShift = 0;
greenMax = greenShift = 0;
blueMax = blueShift = 0;
}
return PixelFormat(bpp, depth, bigEndian, trueColour,
redMax, greenMax, blueMax,
redShift, greenShift, blueShift);
}
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);
}

View File

@@ -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

View File

@@ -0,0 +1,323 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- DeviceFrameBuffer.cxx
//
// The DeviceFrameBuffer class encapsulates the pixel data of the system
// display.
#include <vector>
#include <rfb_win32/DeviceFrameBuffer.h>
#include <rfb_win32/DeviceContext.h>
#include <rfb_win32/IconInfo.h>
#include <rfb/VNCServer.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace win32;
static LogWriter vlog("DeviceFrameBuffer");
BoolParameter DeviceFrameBuffer::useCaptureBlt("UseCaptureBlt",
"Use a slower capture method that ensures that alpha blended windows appear correctly",
true);
// -=- DeviceFrameBuffer class
DeviceFrameBuffer::DeviceFrameBuffer(HDC deviceContext, const Rect& wRect)
: DIBSectionBuffer(deviceContext), device(deviceContext),
ignoreGrabErrors(false)
{
// -=- Firstly, let's check that the device has suitable capabilities
int capabilities = GetDeviceCaps(device, RASTERCAPS);
if (!(capabilities & RC_BITBLT)) {
throw Exception("device does not support BitBlt");
}
if (!(capabilities & RC_DI_BITMAP)) {
throw Exception("device does not support GetDIBits");
}
/*
if (GetDeviceCaps(device, PLANES) != 1) {
throw Exception("device does not support planar displays");
}
*/
// -=- Get the display dimensions and pixel format
// Get the display dimensions
deviceCoords = DeviceContext::getClipBox(device);
if (!wRect.is_empty())
deviceCoords = wRect.translate(deviceCoords.tl);
int w = deviceCoords.width();
int h = deviceCoords.height();
// We can't handle uneven widths :(
if (w % 2) w--;
// Configure the underlying DIB to match the device
DIBSectionBuffer::setPF(DeviceContext::getPF(device));
DIBSectionBuffer::setSize(w, h);
}
DeviceFrameBuffer::~DeviceFrameBuffer() {
}
void
DeviceFrameBuffer::setPF(const PixelFormat &pf) {
throw Exception("setPF not supported");
}
void
DeviceFrameBuffer::setSize(int w, int h) {
throw Exception("setSize not supported");
}
#ifndef CAPTUREBLT
#define CAPTUREBLT 0x40000000
#endif
void
DeviceFrameBuffer::grabRect(const Rect &rect) {
BitmapDC tmpDC(device, bitmap);
// Map the rectangle coords from VNC Desktop-relative to device relative - usually (0,0)
Point src = desktopToDevice(rect.tl);
if (!::BitBlt(tmpDC, rect.tl.x, rect.tl.y,
rect.width(), rect.height(), device, src.x, src.y,
useCaptureBlt ? (CAPTUREBLT | SRCCOPY) : SRCCOPY)) {
if (ignoreGrabErrors)
vlog.error("BitBlt failed:%ld", GetLastError());
else
throw rdr::SystemException("BitBlt failed", GetLastError());
}
}
void
DeviceFrameBuffer::grabRegion(const Region &rgn) {
std::vector<Rect> rects;
std::vector<Rect>::const_iterator i;
rgn.get_rects(&rects);
for(i=rects.begin(); i!=rects.end(); i++) {
grabRect(*i);
}
::GdiFlush();
}
void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
{
// - If hCursor is null then there is no cursor - clear the old one
if (hCursor == 0) {
server->setCursor(0, 0, Point(), NULL);
return;
}
try {
int width, height;
rdr::U8Array buffer;
// - Get the size and other details about the cursor.
IconInfo iconInfo((HICON)hCursor);
BITMAP maskInfo;
if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), &maskInfo))
throw rdr::SystemException("GetObject() failed", GetLastError());
if (maskInfo.bmPlanes != 1)
throw rdr::Exception("unsupported multi-plane cursor");
if (maskInfo.bmBitsPixel != 1)
throw rdr::Exception("unsupported cursor mask format");
width = maskInfo.bmWidth;
height = maskInfo.bmHeight;
if (!iconInfo.hbmColor)
height /= 2;
buffer.buf = new rdr::U8[width * height * 4];
Point hotspot = Point(iconInfo.xHotspot, iconInfo.yHotspot);
if (iconInfo.hbmColor) {
// Colour cursor
BITMAPV5HEADER bi;
BitmapDC dc(device, iconInfo.hbmColor);
memset(&bi, 0, sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = width;
bi.bV5Height = -height; // Negative for top-down
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
bi.bV5RedMask = 0x000000FF;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x00FF0000;
bi.bV5AlphaMask = 0xFF000000;
if (!GetDIBits(dc, iconInfo.hbmColor, 0, height,
buffer.buf, (LPBITMAPINFO)&bi, DIB_RGB_COLORS))
throw rdr::SystemException("GetDIBits", GetLastError());
// We may not get the RGBA order we want, so shuffle things around
int ridx, gidx, bidx, aidx;
ridx = __builtin_ffs(bi.bV5RedMask) / 8;
gidx = __builtin_ffs(bi.bV5GreenMask) / 8;
bidx = __builtin_ffs(bi.bV5BlueMask) / 8;
// Usually not set properly
aidx = 6 - ridx - gidx - bidx;
if ((bi.bV5RedMask != ((unsigned)0xff << ridx*8)) ||
(bi.bV5GreenMask != ((unsigned)0xff << gidx*8)) ||
(bi.bV5BlueMask != ((unsigned)0xff << bidx*8)))
throw rdr::Exception("unsupported cursor colour format");
rdr::U8* rwbuffer = buffer.buf;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
rdr::U8 r, g, b, a;
r = rwbuffer[ridx];
g = rwbuffer[gidx];
b = rwbuffer[bidx];
a = rwbuffer[aidx];
rwbuffer[0] = r;
rwbuffer[1] = g;
rwbuffer[2] = b;
rwbuffer[3] = a;
rwbuffer += 4;
}
}
} else {
// B/W cursor
rdr::U8Array mask(maskInfo.bmWidthBytes * maskInfo.bmHeight);
rdr::U8* andMask = mask.buf;
rdr::U8* xorMask = mask.buf + height * maskInfo.bmWidthBytes;
if (!GetBitmapBits(iconInfo.hbmMask,
maskInfo.bmWidthBytes * maskInfo.bmHeight, mask.buf))
throw rdr::SystemException("GetBitmapBits", GetLastError());
bool doOutline = false;
rdr::U8* rwbuffer = buffer.buf;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int byte = y * maskInfo.bmWidthBytes + x / 8;
int bit = 7 - x % 8;
if (!(andMask[byte] & (1 << bit))) {
// Valid pixel, so make it opaque
rwbuffer[3] = 0xff;
// Black or white?
if (xorMask[byte] & (1 << bit))
rwbuffer[0] = rwbuffer[1] = rwbuffer[2] = 0xff;
else
rwbuffer[0] = rwbuffer[1] = rwbuffer[2] = 0;
} else if (xorMask[byte] & (1 << bit)) {
// Replace any XORed pixels with black, because RFB doesn't support
// XORing of cursors. XORing is used for the I-beam cursor, which is most
// often used over a white background, but also sometimes over a black
// background. We set the XOR'd pixels to black, then draw a white outline
// around the whole cursor.
rwbuffer[0] = rwbuffer[1] = rwbuffer[2] = 0;
rwbuffer[3] = 0xff;
doOutline = true;
} else {
// Transparent pixel
rwbuffer[0] = rwbuffer[1] = rwbuffer[2] = rwbuffer[3] = 0;
}
rwbuffer += 4;
}
}
if (doOutline) {
vlog.debug("drawing cursor outline!");
// The buffer needs to be slightly larger to make sure there
// is room for the outline pixels
rdr::U8Array outline((width + 2)*(height + 2)*4);
memset(outline.buf, 0, (width + 2)*(height + 2)*4);
// Pass 1, outline everything
rdr::U8* in = buffer.buf;
rdr::U8* out = outline.buf + width*4 + 4;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Visible pixel?
if (in[3] > 0) {
// Outline above...
memset(out - (width+2)*4 - 4, 0xff, 4 * 3);
// ...besides...
memset(out - 4, 0xff, 4 * 3);
// ...and above
memset(out + (width+2)*4 - 4, 0xff, 4 * 3);
}
in += 4;
out += 4;
}
// outline is slightly larger
out += 2*4;
}
// Pass 2, overwrite with actual cursor
in = buffer.buf;
out = outline.buf + width*4 + 4;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (in[3] > 0)
memcpy(out, in, 4);
in += 4;
out += 4;
}
out += 2*4;
}
width += 2;
height += 2;
hotspot.x += 1;
hotspot.y += 1;
delete [] buffer.buf;
buffer.buf = outline.takeBuf();
}
}
server->setCursor(width, height, hotspot, buffer.buf);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
}
}

View File

@@ -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.
*/
// -=- DeviceFrameBuffer.h
//
// The DeviceFrameBuffer class encapsulates the pixel data of a supplied
// Device Context Handle (HDC)
// *** THIS INTERFACE NEEDS TIDYING TO SEPARATE COORDINATE SYSTEMS BETTER ***
#ifndef __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
#define __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
#include <windows.h>
#include <rfb_win32/DIBSectionBuffer.h>
#include <rfb/Cursor.h>
#include <rfb/Region.h>
#include <rfb/Exception.h>
#include <rfb/Configuration.h>
namespace rfb {
class VNCServer;
namespace win32 {
// -=- DeviceFrameBuffer interface
// DeviceFrameBuffer is passed an HDC referring to a window or to
// the entire display. It may also be passed a rectangle specifying
// the Device-relative coordinates of the actual rectangle to treat
// as the desktop.
// Coordinate systems start getting really annoying here. There are
// three different "origins" to which coordinates might be relative:
//
// Desktop - VNC coordinates, top-left always (0,0)
// Device - DC coordinates. Top-left *usually (0,0) but could be other.
// Window - coordinates relative to the specified sub-rectangle within
// the supplied DC.
// Screen - Coordinates relative to the entire Windows virtual screen.
// The virtual screen includes all monitors that are part of
// the Windows desktop.
// The data member is made to point to an internal mirror of the
// current display data. Individual rectangles or regions of the
// buffer can be brought up to date by calling the grab functions.
class DeviceFrameBuffer : public DIBSectionBuffer {
public:
DeviceFrameBuffer(HDC deviceContext, const Rect& area_=Rect());
virtual ~DeviceFrameBuffer();
// - FrameBuffer overrides
virtual void grabRect(const Rect &rect);
virtual void grabRegion(const Region &region);
// - DIBSectionBuffer overrides
virtual void setPF(const PixelFormat& pf);
virtual void setSize(int w, int h);
// - DeviceFrameBuffer specific methods
void setCursor(HCURSOR c, VNCServer* server);
// Set whether grabRect should ignore errors or throw exceptions
// Only set this if you are sure you'll capture the errors some other way!
void setIgnoreGrabErrors(bool ie) {ignoreGrabErrors=ie;}
static BoolParameter useCaptureBlt;
protected:
// Translate supplied Desktop coordinates into Device-relative coordinates
// This translation may have been affected at start-time by the supplied sub-rect.
Point desktopToDevice(const Point p) const {return p.translate(deviceCoords.tl);}
HDC device;
Rect deviceCoords;
bool ignoreGrabErrors;
};
};
};
#endif // __RFB_WIN32_DEVICE_FRAME_BUFFER_H__

385
win/rfb_win32/Dialog.cxx Normal file
View File

@@ -0,0 +1,385 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2010 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Dialog.cxx
// Base-class for any Dialog classes we might require
#include <rfb_win32/Dialog.h>
#include <rfb_win32/TCharArray.h>
#include <rfb/LogWriter.h>
#include <rdr/Exception.h>
#include <rfb_win32/Win32Util.h>
#ifdef _DIALOG_CAPTURE
#ifdef PropSheet_IndexToId
#include <rfb_win32/DeviceFrameBuffer.h>
#include <extra/LoadBMP.cxx>
#else
#undef _DIALOG_CAPTURE
#pragma message(" NOTE: Not building Dialog Capture support.")
#endif
#endif
using namespace rfb;
using namespace rfb::win32;
static LogWriter dlog("Dialog");
static LogWriter plog("PropSheet");
Dialog::Dialog(HINSTANCE inst_)
: inst(inst_), handle(0), alreadyShowing(false)
{
}
Dialog::~Dialog()
{
}
bool Dialog::showDialog(const TCHAR* resource, HWND owner)
{
if (alreadyShowing) return false;
handle = 0;
alreadyShowing = true;
INT_PTR result = DialogBoxParam(inst, resource, owner,
staticDialogProc, (LPARAM)this);
if (result<0)
throw rdr::SystemException("DialogBoxParam failed", GetLastError());
alreadyShowing = false;
return (result == 1);
}
bool Dialog::isItemChecked(int id) {
return SendMessage(GetDlgItem(handle, id), BM_GETCHECK, 0, 0) == BST_CHECKED;
}
int Dialog::getItemInt(int id) {
BOOL trans;
int result = GetDlgItemInt(handle, id, &trans, TRUE);
if (!trans)
throw rdr::Exception("unable to read dialog Int");
return result;
}
TCHAR* Dialog::getItemString(int id) {
TCharArray tmp(256);
if (!GetDlgItemText(handle, id, tmp.buf, 256))
tmp.buf[0] = 0;
return tmp.takeBuf();
}
void Dialog::setItemChecked(int id, bool state) {
SendMessage(GetDlgItem(handle, id), BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0);
}
void Dialog::setItemInt(int id, int value) {
SetDlgItemInt(handle, id, value, TRUE);
}
void Dialog::setItemString(int id, const TCHAR* s) {
SetDlgItemText(handle, id, s);
}
void Dialog::enableItem(int id, bool state) {
EnableWindow(GetDlgItem(handle, id), state);
}
INT_PTR CALLBACK Dialog::staticDialogProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
if (msg == WM_INITDIALOG)
SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (!self) return FALSE;
return ((Dialog*)self)->dialogProc(hwnd, msg, wParam, lParam);
}
BOOL Dialog::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
handle = hwnd;
initDialog();
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (onOk()) {
EndDialog(hwnd, 1);
return TRUE;
}
return FALSE;
case IDCANCEL:
EndDialog(hwnd, 0);
return TRUE;
default:
return onCommand(LOWORD(wParam), HIWORD(wParam));
};
case WM_HELP:
return onHelp(((HELPINFO*)lParam)->iCtrlId);
}
return FALSE;
}
PropSheetPage::PropSheetPage(HINSTANCE inst, const TCHAR* id) : Dialog(inst), propSheet(0) {
page.dwSize = sizeof(page);
page.dwFlags = 0; // PSP_USECALLBACK;
page.hInstance = inst;
page.pszTemplate = id;
page.pfnDlgProc = staticPageProc;
page.lParam = (LPARAM)this;
page.pfnCallback = 0; // staticPageProc;
}
PropSheetPage::~PropSheetPage() {
}
INT_PTR CALLBACK PropSheetPage::staticPageProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
if (msg == WM_INITDIALOG)
SetWindowLongPtr(hwnd, GWLP_USERDATA, ((PROPSHEETPAGE*)lParam)->lParam);
LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (!self) return FALSE;
return ((PropSheetPage*)self)->dialogProc(hwnd, msg, wParam, lParam);
}
BOOL PropSheetPage::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
handle = hwnd;
initDialog();
return TRUE;
case WM_NOTIFY:
switch (((NMHDR*)lParam)->code) {
case PSN_APPLY:
onOk();
return FALSE;
};
return FALSE;
case WM_COMMAND:
return onCommand(LOWORD(wParam), HIWORD(wParam));
case WM_HELP:
return onHelp(((HELPINFO*)lParam)->iCtrlId);
}
return FALSE;
}
PropSheet::PropSheet(HINSTANCE inst_, const TCHAR* title_, std::list<PropSheetPage*> pages_, HICON icon_)
: icon(icon_), pages(pages_), inst(inst_), title(tstrDup(title_)), handle(0), alreadyShowing(0) {
}
PropSheet::~PropSheet() {
}
// For some reason, DLGTEMPLATEEX isn't defined in the Windows headers - go figure...
struct DLGTEMPLATEEX {
WORD dlgVer;
WORD signature;
DWORD helpID;
DWORD exStyle;
DWORD style;
WORD cDlgItems;
short x;
short y;
short cx;
short cy;
};
static int CALLBACK removeCtxtHelp(HWND hwnd, UINT message, LPARAM lParam) {
if (message == PSCB_PRECREATE) {
// Remove the context-help style, to remove the titlebar ? button
// *** Nasty hack to cope with new & old dialog template formats...
if (((DLGTEMPLATEEX*)lParam)->signature == 0xffff)
((DLGTEMPLATEEX*)lParam)->style &= ~DS_CONTEXTHELP;
else
((LPDLGTEMPLATE)lParam)->style &= ~DS_CONTEXTHELP;
}
return TRUE;
}
bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, bool capture) {
if (alreadyShowing) return false;
alreadyShowing = true;
int count = pages.size();
HPROPSHEETPAGE* hpages = new HPROPSHEETPAGE[count];
try {
// Create the PropertSheet page GDI objects.
std::list<PropSheetPage*>::iterator pspi;
int i = 0;
for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
hpages[i] = CreatePropertySheetPage(&((*pspi)->page));
(*pspi)->setPropSheet(this);
i++;
}
// Initialise and create the PropertySheet itself
PROPSHEETHEADER header;
header.dwSize = sizeof(PROPSHEETHEADER); // Requires comctl32.dll 4.71 or greater, ie IE 4 or later
header.dwFlags = PSH_MODELESS | (showApply ? 0 : PSH_NOAPPLYNOW) | (showCtxtHelp ? 0 : PSH_USECALLBACK);
header.pfnCallback = removeCtxtHelp;
header.hwndParent = owner;
header.hInstance = inst;
header.pszCaption = title.buf;
header.nPages = count;
header.nStartPage = 0;
header.phpage = hpages;
if (icon) {
header.hIcon = icon;
header.dwFlags |= PSH_USEHICON;
}
handle = (HWND)PropertySheet(&header);
if ((handle == 0) || (handle == (HWND)-1))
throw rdr::SystemException("PropertySheet failed", GetLastError());
centerWindow(handle, owner);
plog.info("created %p", handle);
#ifdef _DIALOG_CAPTURE
if (capture) {
plog.info("capturing \"%s\"", (const char*)CStr(title.buf));
char* tmpdir = getenv("TEMP");
HDC dc = GetWindowDC(handle);
DeviceFrameBuffer fb(dc);
int i=0;
while (true) {
int id = PropSheet_IndexToId(handle, i);
if (!id) break;
PropSheet_SetCurSelByID(handle, id);
MSG msg;
while (PeekMessage(&msg, handle, 0, 0, PM_REMOVE)) {
if (!PropSheet_IsDialogMessage(handle, &msg))
DispatchMessage(&msg);
}
fb.grabRect(fb.getRect());
TCHAR title[128];
if (!GetWindowText(PropSheet_GetCurrentPageHwnd(handle), title, sizeof(title)))
_stprintf(title, _T("capture%d"), i);
CharArray pageTitle(strDup(title));
for (int j=0; j<strlen(pageTitle.buf); j++) {
if (pageTitle.buf[j] == '/' || pageTitle.buf[j] == '\\' || pageTitle.buf[j] == ':')
pageTitle.buf[j] = '-';
}
char filename[256];
sprintf(filename, "%s\\%s.bmp", tmpdir, pageTitle.buf);
vlog.debug("writing to %s", filename);
saveBMP(filename, &fb);
i++;
}
ReleaseDC(handle, dc);
} else {
#endif
try {
if (owner)
EnableWindow(owner, FALSE);
// Run the PropertySheet
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
if (!PropSheet_IsDialogMessage(handle, &msg))
DispatchMessage(&msg);
if (!PropSheet_GetCurrentPageHwnd(handle))
break;
}
if (owner)
EnableWindow(owner, TRUE);
} catch (...) {
if (owner)
EnableWindow(owner, TRUE);
throw;
}
#ifdef _DIALOG_CAPTURE
}
#endif
plog.info("finished %p", handle);
DestroyWindow(handle);
handle = 0;
alreadyShowing = false;
// Clear up the pages' GDI objects
for (pspi=pages.begin(); pspi!=pages.end(); pspi++)
(*pspi)->setPropSheet(0);
delete [] hpages; hpages = 0;
return true;
} catch (rdr::Exception&) {
alreadyShowing = false;
std::list<PropSheetPage*>::iterator pspi;
for (pspi=pages.begin(); pspi!=pages.end(); pspi++)
(*pspi)->setPropSheet(0);
delete [] hpages; hpages = 0;
throw;
}
}
void PropSheet::reInitPages() {
std::list<PropSheetPage*>::iterator pspi;
for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
if ((*pspi)->handle)
(*pspi)->initDialog();
}
}
bool PropSheet::commitPages() {
bool result = true;
std::list<PropSheetPage*>::iterator pspi;
for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
if ((*pspi)->handle)
result = result && (*pspi)->onOk();
}
return result;
}
void PropSheetPage::setChanged(bool changed) {
if (propSheet) {
if (changed)
PropSheet_Changed(propSheet->handle, handle);
else
PropSheet_UnChanged(propSheet->handle, handle);
}
}

159
win/rfb_win32/Dialog.h Normal file
View File

@@ -0,0 +1,159 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2010 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- RegConfig.h
// Class which monitors the registry and reads in the registry settings
// whenever they change, or are added or removed.
#ifndef __RFB_WIN32_DIALOG_H__
#define __RFB_WIN32_DIALOG_H__
#include <windows.h>
#include <prsht.h>
#include <list>
#include <rfb_win32/TCharArray.h>
namespace rfb {
namespace win32 {
// Dialog - A simple Win32 Dialog box. A derived class of Dialog overrides the
// initDialog(), command() and ok() methods to take appropriate action. A
// simple dialog box can be displayed by creating a Dialog object and calling
// show().
class Dialog {
public:
Dialog(HINSTANCE inst);
virtual ~Dialog();
// showDialog() displays the dialog box. It returns when it has been dismissed,
// returning true if "OK" was pressed, false otherwise. The resource
// argument identifies the dialog resource (often a MAKEINTRESOURCE macro
// expansion), and owner is an optional window handle - the corresponding
// window is disabled while the dialog box is displayed.
bool showDialog(const TCHAR* resource, HWND owner=0);
// initDialog() is called upon receipt of the WM_INITDIALOG message.
virtual void initDialog() {}
// onCommand() is called upon receipt of a WM_COMMAND message item other than IDOK
// or IDCANCEL. It should return true if the command has been handled.
virtual bool onCommand(int item, int cmd) { return false; }
// onHelp() is called upon receipt of a WM_MENU message. This indicates that
// context-specific help should be displayed, for a dialog control, for example.
// It should return true if the command has been handled.
virtual bool onHelp(int item) { return false; }
// onOk() is called when the OK button is pressed. The hwnd argument is the
// dialog box's window handle.
virtual bool onOk() { return true; }
// Read the states of items
bool isItemChecked(int id);
int getItemInt(int id);
TCHAR* getItemString(int id); // Recipient owns string storage
// Set the states of items
void setItemChecked(int id, bool state);
void setItemInt(int id, int value);
void setItemString(int id, const TCHAR* s);
// enableItem is used to grey out an item, making it inaccessible, or to
// re-enable it.
void enableItem(int id, bool state);
protected:
static INT_PTR CALLBACK staticDialogProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam);
virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HINSTANCE inst;
HWND handle;
bool alreadyShowing;
};
// PropertySheetPage
// Class used to define property pages within a PropertySheet.
// Each page is associated with a particular dialog resource, indicated by
// the "id" parameter supplied to the constructor.
class PropSheetPage;
class PropSheet {
public:
PropSheet(HINSTANCE inst, const TCHAR* title, std::list<PropSheetPage*> pages, HICON icon=0);
virtual ~PropSheet();
// Display the PropertySheet
bool showPropSheet(HWND owner, bool showApply = false, bool showCtxtHelp = false, bool capture=false);
// Calls initDialog again for each page that has already had it called.
// Note: If a page hasn't been seen yet, it won't have been called.
// Note: This must only be called while the property sheet is visible.
void reInitPages();
// Calls onOk for each page that has had initDialog called, and returns
// false if any one of them returns false, or true otherwise. ALL the
// onOk() methods will be called, even if one of them fails.
// Note: If a page hasn't been seen yet, it won't have been called.
// Note: This must only be called while the property sheet is visible.
bool commitPages();
friend class PropSheetPage;
protected:
HWND owner;
HICON icon;
std::list<PropSheetPage*> pages;
HINSTANCE inst;
TCharArray title;
HWND handle;
bool alreadyShowing;
};
class PropSheetPage : public Dialog {
public:
PropSheetPage(HINSTANCE inst, const TCHAR* id);
virtual ~PropSheetPage();
void setChanged(bool changed);
friend class PropSheet;
protected:
void setPropSheet(PropSheet* ps) {propSheet = ps;};
static INT_PTR CALLBACK staticPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
PROPSHEETPAGE page;
PropSheet* propSheet;
};
};
};
#endif // __RFB_WIN32_DIALOG_H__

View File

@@ -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 (unsigned int i=0; i<eventCount; i++) {
if (events[i] == event) {
for (unsigned 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;
}
}
}

View File

@@ -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];
unsigned int eventCount;
};
};
};
#endif

43
win/rfb_win32/Handle.h Normal file
View File

@@ -0,0 +1,43 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// Wrapper for Win32 HANDLEs that can/must be CloseHandle()d.
#ifndef __RFB_WIN32_HANDLE_H__
#define __RFB_WIN32_HANDLE_H__
#include <windows.h>
namespace rfb {
namespace win32 {
class Handle {
public:
Handle(HANDLE h_=0) : h(h_) {}
~Handle() {
if (h) CloseHandle(h);
}
operator HANDLE() {return h;}
HANDLE h;
};
};
};
#endif

44
win/rfb_win32/IconInfo.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,70 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- IntervalTimer.h
//
// Simple wrapper for standard Win32 timers
#ifndef __RFB_WIN32_INTERVAL_TIMER_H__
#define __RFB_WIN32_INTERVAL_TIMER_H__
namespace rfb {
namespace win32 {
struct IntervalTimer {
IntervalTimer(HWND hwnd_, int id_)
: hwnd(hwnd_), id(id_), active(false) {
}
IntervalTimer() : hwnd(0), id(0), active(false) {
}
~IntervalTimer() {
stop();
}
void start(int interval_) {
if (!active || interval_ != interval) {
interval = interval_;
if (!SetTimer(hwnd, id, interval, 0))
throw rdr::SystemException("SetTimer", GetLastError());
active = true;
}
}
void stop() {
if (active)
KillTimer(hwnd, id);
active = false;
}
void setHWND(HWND hwnd_) {hwnd=hwnd_;}
void setId(int id_) {id = id_;}
int getId() const {return id;}
bool isActive() const {return active;}
private:
HWND hwnd;
int id;
bool active;
int interval;
};
}; // win32
}; // rfb
#endif // __RFB_WIN32_INTERVAL_TIMER_H__

View File

@@ -0,0 +1,113 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- LaunchProcess.cxx
#include <rfb_win32/LaunchProcess.h>
#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Win32Util.h>
#include <rdr/Exception.h>
#include <stdio.h>
using namespace rfb;
using namespace win32;
LaunchProcess::LaunchProcess(const TCHAR* exeName_, const TCHAR* params_)
: exeName(tstrDup(exeName_)), params(tstrDup(params_)) {
memset(&procInfo, 0, sizeof(procInfo));
}
LaunchProcess::~LaunchProcess() {
await();
}
void LaunchProcess::start(HANDLE userToken, bool createConsole) {
if (procInfo.hProcess && (WaitForSingleObject(procInfo.hProcess, 0) != WAIT_OBJECT_0))
return;
await();
returnCode = STILL_ACTIVE;
DWORD size;
char desktopName[256];
char buf[256];
HDESK desktop = GetThreadDesktop(GetCurrentThreadId());
if (!GetUserObjectInformation(desktop, UOI_NAME, buf, 256, &size))
throw rdr::SystemException("unable to launch process", GetLastError());
snprintf(desktopName, 256, "WinSta0\\%s", buf);
// - Create storage for the process startup information
STARTUPINFO sinfo;
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.lpDesktop = desktopName;
// - Concoct a suitable command-line
TCharArray exePath;
if (!tstrContains(exeName.buf, _T('\\'))) {
ModuleFileName filename;
TCharArray path; splitPath(filename.buf, &path.buf, 0);
exePath.buf = new TCHAR[_tcslen(path.buf) + _tcslen(exeName.buf) + 2];
_stprintf(exePath.buf, _T("%s\\%s"), path.buf, exeName.buf);
} else {
exePath.buf = tstrDup(exeName.buf);
}
// - Start the process
// Note: We specify the exe's precise path in the ApplicationName parameter,
// AND include the name as the first part of the CommandLine parameter,
// because CreateProcess doesn't make ApplicationName argv[0] in C programs.
TCharArray cmdLine(_tcslen(exeName.buf) + 3 + _tcslen(params.buf) + 1);
_stprintf(cmdLine.buf, _T("\"%s\" %s"), exeName.buf, params.buf);
DWORD flags = createConsole ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW;
BOOL success;
if (userToken != INVALID_HANDLE_VALUE)
success = CreateProcessAsUser(userToken, exePath.buf, cmdLine.buf, 0, 0, FALSE, flags, 0, 0, &sinfo, &procInfo);
else
success = CreateProcess(exePath.buf, cmdLine.buf, 0, 0, FALSE, flags, 0, 0, &sinfo, &procInfo);
if (!success)
throw rdr::SystemException("unable to launch process", GetLastError());
// Wait for it to finish initialising
WaitForInputIdle(procInfo.hProcess, 15000);
}
void LaunchProcess::detach()
{
if (!procInfo.hProcess)
return;
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
memset(&procInfo, 0, sizeof(procInfo));
}
bool LaunchProcess::await(DWORD timeoutMs) {
if (!procInfo.hProcess)
return true;
DWORD result = WaitForSingleObject(procInfo.hProcess, timeoutMs);
if (result == WAIT_OBJECT_0) {
GetExitCodeProcess(procInfo.hProcess, &returnCode);
detach();
return true;
} else if (result == WAIT_FAILED) {
throw rdr::SystemException("await() failed", GetLastError());
}
return false;
}

View File

@@ -0,0 +1,71 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- LaunchProcess.h
// Helper class to launch a names process from the same directory as
// the current process executable resides in.
#ifndef __RFB_WIN32_LAUNCHPROCESS_H__
#define __RFB_WIN32_LAUNCHPROCESS_H__
#include <windows.h>
#include <rfb_win32/TCharArray.h>
namespace rfb {
namespace win32 {
class LaunchProcess {
public:
LaunchProcess(const TCHAR* exeName_, const TCHAR* params);
~LaunchProcess();
// start() starts the specified process with the supplied
// command-line.
// If userToken is INVALID_HANDLE_VALUE then starts the process
// as the current user, otherwise as the specified user.
// If createConsole is true then CREATE_CONSOLE_WINDOW is passed
// as an extra flag to the process creation call.
void start(HANDLE userToken, bool createConsole=false);
// Detach from the child process. After detaching from a child
// process, no other methods should be called on the object
// that started it
void detach();
// Wait for the process to quit, up to the specified timeout, and
// close the handles to it once it has quit.
// If the process quits within the timeout then true is returned
// and returnCode is set. If it has not quit then false is returned.
// If an error occurs then an exception will be thrown.
bool await(DWORD timeoutMs=INFINITE);
PROCESS_INFORMATION procInfo;
DWORD returnCode;
protected:
TCharArray exeName;
TCharArray params;
};
};
};
#endif

View File

@@ -0,0 +1,103 @@
// ListViewControl.cxx: implementation of the ListViewControl class.
//
//////////////////////////////////////////////////////////////////////
#include <tchar.h>
#include "ListViewControl.h"
#include "commctrl.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
using namespace rfb;
using namespace rfb::win32;
ListViewControl::ListViewControl()
{
}
bool ListViewControl::IsSelectedLVItem(DWORD idListView,
HWND hDlg, int numberItem)
{
return (ListView_GetItemState(GetDlgItem(hDlg, idListView),
numberItem, LVIS_SELECTED) == LVIS_SELECTED);
}
void ListViewControl::SelectLVItem(DWORD idListView, HWND hDlg, int numberItem)
{
ListView_SetItemState(GetDlgItem(hDlg, idListView),
numberItem, LVIS_SELECTED, LVIS_SELECTED);
}
BOOL ListViewControl::InitLVColumns(DWORD idListView, HWND hDlg, int width, int columns,
TCHAR *title[], DWORD mask, DWORD LVStyle, DWORD format)
{
(void)ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, idListView), LVStyle);
TCHAR szText[256];
LVCOLUMN lvc;
int iCol;
lvc.mask = mask;
for (iCol = 0; iCol < columns; iCol++) {
lvc.iSubItem = iCol;
lvc.pszText = szText;
lvc.cx = width;
lvc.fmt = format;
_tcscpy(szText, title[iCol]);
if (ListView_InsertColumn(GetDlgItem(hDlg, idListView), iCol, &lvc) == -1)
return FALSE;
}
return TRUE;
}
BOOL ListViewControl::InsertLVItem(DWORD idListView, HWND hDlg, int number, TCHAR * texts[],
int columns)
{
int i;
LVITEM lvI;
lvI.mask = LVIF_TEXT| LVIF_STATE;
lvI.state = 0;
lvI.stateMask = 0;
lvI.iItem = number;
lvI.iSubItem = 0;
lvI.pszText = texts[0];
if(ListView_InsertItem(GetDlgItem(hDlg, idListView), &lvI) == -1)
return FALSE;
for (i =1; i < columns; i++) {
SetLVItemText(
idListView, hDlg,
number, i, texts[i]);
}
return TRUE;
}
void ListViewControl::SetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
int namberColumn, TCHAR * text)
{
ListView_SetItemText(
GetDlgItem(hDlg, idListView),
numberItem, namberColumn, text);
}
void ListViewControl::GetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
int namberColumn, TCHAR * text)
{
ListView_GetItemText(GetDlgItem(hDlg, idListView), numberItem,
namberColumn, text, 256);
}
void ListViewControl::DeleteLVItem(DWORD idListView, HWND hDlg, int number)
{
(void)ListView_DeleteItem(GetDlgItem(hDlg, idListView), number);
}
void ListViewControl::DeleteAllLVItem(DWORD idListView, HWND hDlg)
{
(void)ListView_DeleteAllItems(GetDlgItem(hDlg, idListView));
}
ListViewControl::~ListViewControl()
{
}

View File

@@ -0,0 +1,35 @@
// ListViewControl.h: interface for the ListViewControl class.
//
//////////////////////////////////////////////////////////////////////
#ifndef AFX_LISTVIEWCONTROL_H__
#define AFX_LISTVIEWCONTROL_H__
#include <windows.h>
#include "commctrl.h"
namespace rfb {
namespace win32 {
class ListViewControl
{
public:
ListViewControl();
bool IsSelectedLVItem(DWORD idListView, HWND hDlg, int numberItem);
void SelectLVItem(DWORD idListView, HWND hDlg, int numberItem);
BOOL InitLVColumns(DWORD idListView, HWND hDlg, int width, int columns,
TCHAR * title[], DWORD mask, DWORD style, DWORD format);
BOOL InsertLVItem(DWORD idListView, HWND hDlg, int number, TCHAR * texts[],
int columns);
void SetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
int namberColumn, TCHAR * text);
void GetLVItemText(DWORD idListView, HWND hDlg, int numberItem,
int namberColumn, TCHAR * text);
void DeleteLVItem(DWORD idListView, HWND hDlg, int number);
void DeleteAllLVItem(DWORD idListView, HWND hDlg);
virtual ~ListViewControl();
};
};
};
#endif

45
win/rfb_win32/LocalMem.h Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,138 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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 <tchar.h>
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Win32Util.h>
#include <rdr/Exception.h>
#include <rfb/LogWriter.h>
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
using namespace rfb;
using namespace win32;
static LogWriter vlog("MonitorInfo");
static void fillMonitorInfo(HMONITOR monitor, MonitorInfo* mi) {
vlog.debug("monitor=%p", monitor);
memset(mi, 0, sizeof(MONITORINFOEXA));
mi->cbSize = sizeof(MONITORINFOEXA);
if (!GetMonitorInfo(monitor, mi))
throw rdr::SystemException("failed to GetMonitorInfo", GetLastError());
vlog.debug("monitor is %ld,%ld-%ld,%ld", mi->rcMonitor.left, mi->rcMonitor.top, mi->rcMonitor.right, mi->rcMonitor.bottom);
vlog.debug("work area is %ld,%ld-%ld,%ld", mi->rcWork.left, mi->rcWork.top, mi->rcWork.right, mi->rcWork.bottom);
vlog.debug("device is \"%s\"", mi->szDevice);
}
MonitorInfo::MonitorInfo(HWND window) {
cbSize = sizeof(MonitorInfo);
szDevice[0] = 0;
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
if (!monitor)
throw rdr::SystemException("failed to get monitor", GetLastError());
fillMonitorInfo(monitor, this);
}
MonitorInfo::MonitorInfo(const RECT& r) {
cbSize = sizeof(MonitorInfo);
szDevice[0] = 0;
HMONITOR monitor = MonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);
if (!monitor)
throw rdr::SystemException("failed to get monitor", GetLastError());
fillMonitorInfo(monitor, this);
}
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;
}
MonitorInfo::MonitorInfo(const char* devName) {
monitorByNameData data;
data.info = this;
data.monitorName = devName;
EnumDisplayMonitors(0, 0, &monitorByNameEnumProc, (LPARAM)&data);
}
void MonitorInfo::moveTo(HWND handle) {
vlog.debug("moveTo monitor=%s", szDevice);
MonitorInfo mi(handle);
if (strcmp(szDevice, mi.szDevice) != 0) {
centerWindow(handle, rcWork);
clipTo(handle);
}
}
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);
}

View File

@@ -0,0 +1,55 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// Helper class used to obtain information about a particular monitor.
#ifndef __RFB_WIN32_MONITORINFO_H__
#define __RFB_WIN32_MONITORINFO_H__
#include <windows.h>
namespace rfb {
namespace win32 {
// Structure containing info on the monitor nearest the window.
struct MonitorInfo : MONITORINFOEXA {
// 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

63
win/rfb_win32/MsgBox.h Normal file
View File

@@ -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

118
win/rfb_win32/MsgWindow.cxx Normal file
View File

@@ -0,0 +1,118 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2010 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- MsgWindow.cxx
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/WMShatter.h>
#include <rfb/LogWriter.h>
#include <rdr/Exception.h>
#include <malloc.h>
#include <tchar.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("MsgWindow");
//
// -=- MsgWindowClass
//
class MsgWindowClass {
public:
MsgWindowClass();
~MsgWindowClass();
ATOM classAtom;
HINSTANCE instance;
};
LRESULT CALLBACK MsgWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
LRESULT result = 0;
if (msg == WM_CREATE)
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)((CREATESTRUCT*)lParam)->lpCreateParams);
else if (msg == WM_DESTROY)
SetWindowLongPtr(wnd, GWLP_USERDATA, 0);
MsgWindow* _this = (MsgWindow*) GetWindowLongPtr(wnd, GWLP_USERDATA);
if (!_this) {
vlog.info("null _this in %p, message %x", wnd, msg);
return SafeDefWindowProc(wnd, msg, wParam, lParam);
}
try {
result = _this->processMessage(msg, wParam, lParam);
} catch (rdr::Exception& e) {
vlog.error("untrapped: %s", e.str());
}
return result;
};
MsgWindowClass::MsgWindowClass() : classAtom(0) {
WNDCLASS wndClass;
wndClass.style = 0;
wndClass.lpfnWndProc = MsgWindowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = instance = GetModuleHandle(0);
wndClass.hIcon = 0;
wndClass.hCursor = 0;
wndClass.hbrBackground = 0;
wndClass.lpszMenuName = 0;
wndClass.lpszClassName = _T("rfb::win32::MsgWindowClass");
classAtom = RegisterClass(&wndClass);
if (!classAtom) {
throw rdr::SystemException("unable to register MsgWindow window class", GetLastError());
}
}
MsgWindowClass::~MsgWindowClass() {
if (classAtom) {
UnregisterClass((const TCHAR*)(intptr_t)classAtom, instance);
}
}
static MsgWindowClass baseClass;
//
// -=- MsgWindow
//
MsgWindow::MsgWindow(const TCHAR* name_) : name(tstrDup(name_)), handle(0) {
vlog.debug("creating window \"%s\"", (const char*)CStr(name.buf));
handle = CreateWindow((const TCHAR*)(intptr_t)baseClass.classAtom,
name.buf, WS_OVERLAPPED, 0, 0, 10, 10, 0, 0,
baseClass.instance, this);
if (!handle) {
throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
}
vlog.debug("created window \"%s\" (%p)", (const char*)CStr(name.buf), handle);
}
MsgWindow::~MsgWindow() {
if (handle)
DestroyWindow(handle);
vlog.debug("destroyed window \"%s\" (%p)", (const char*)CStr(name.buf), handle);
}
LRESULT
MsgWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
return SafeDefWindowProc(getHandle(), msg, wParam, lParam);
}

53
win/rfb_win32/MsgWindow.h Normal file
View File

@@ -0,0 +1,53 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- MsgWindow.h
// Base-class for any hidden message-handling windows used in the rfb::win32
// implementation.
#ifndef __RFB_WIN32_MSG_WINDOW_H__
#define __RFB_WIN32_MSG_WINDOW_H__
#include <windows.h>
#include <rfb_win32/TCharArray.h>
namespace rfb {
namespace win32 {
class MsgWindow {
public:
MsgWindow(const TCHAR* _name);
virtual ~MsgWindow();
const TCHAR* getName() {return name.buf;}
HWND getHandle() const {return handle;}
virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
protected:
TCharArray name;
HWND handle;
};
};
};
#endif // __RFB_WIN32_MSG_WINDOW_H__

113
win/rfb_win32/RegConfig.cxx Normal file
View File

@@ -0,0 +1,113 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- RegConfig.cxx
#include <malloc.h>
#include <rfb_win32/RegConfig.h>
#include <rfb/LogWriter.h>
#include <rfb/util.h>
//#include <rdr/HexOutStream.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("RegConfig");
RegConfig::RegConfig(EventManager* em) : eventMgr(em), event(CreateEvent(0, TRUE, FALSE, 0)), callback(0) {
if (em->addEvent(event, this))
eventMgr = em;
}
RegConfig::~RegConfig() {
if (eventMgr)
eventMgr->removeEvent(event);
}
bool RegConfig::setKey(const HKEY rootkey, const TCHAR* keyname) {
try {
key.createKey(rootkey, keyname);
processEvent(event);
return true;
} catch (rdr::Exception& e) {
vlog.debug("%s", e.str());
return false;
}
}
void RegConfig::loadRegistryConfig(RegKey& key) {
DWORD i = 0;
try {
while (1) {
TCharArray name(tstrDup(key.getValueName(i++)));
if (!name.buf) break;
TCharArray value(key.getRepresentation(name.buf));
if (!value.buf || !Configuration::setParam(CStr(name.buf), CStr(value.buf)))
vlog.info("unable to process %s", name.buf);
}
} catch (rdr::SystemException& e) {
if (e.err != 6)
vlog.error("%s", e.str());
}
}
void RegConfig::processEvent(HANDLE event_) {
vlog.info("registry changed");
// Reinstate the registry change notifications
ResetEvent(event);
key.awaitChange(true, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET, event);
// Load settings
loadRegistryConfig(key);
// Notify the callback, if supplied
if (callback)
callback->regConfigChanged();
}
RegConfigThread::RegConfigThread() : config(&eventMgr), thread_id(-1) {
}
RegConfigThread::~RegConfigThread() {
PostThreadMessage(thread_id, WM_QUIT, 0, 0);
wait();
}
bool RegConfigThread::start(const HKEY rootKey, const TCHAR* keyname) {
if (config.setKey(rootKey, keyname)) {
Thread::start();
while (thread_id == (DWORD)-1)
Sleep(0);
return true;
}
return false;
}
void RegConfigThread::worker() {
DWORD result = 0;
MSG msg;
thread_id = GetCurrentThreadId();
while ((result = eventMgr.getMessage(&msg, 0, 0, 0)) > 0) {}
if (result < 0)
throw rdr::SystemException("RegConfigThread failed", GetLastError());
}

85
win/rfb_win32/RegConfig.h Normal file
View File

@@ -0,0 +1,85 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- RegConfig.h
// Class which monitors the registry and reads in the registry settings
// whenever they change, or are added or removed.
#ifndef __RFB_WIN32_REG_CONFIG_H__
#define __RFB_WIN32_REG_CONFIG_H__
#include <os/Thread.h>
#include <rfb/Configuration.h>
#include <rfb_win32/Registry.h>
#include <rfb_win32/EventManager.h>
#include <rfb_win32/Handle.h>
namespace rfb {
namespace win32 {
class RegConfig : EventHandler {
public:
RegConfig(EventManager* em);
~RegConfig();
// Specify the registry key to read Configuration items from
bool setKey(const HKEY rootkey, const TCHAR* keyname);
// Support for a callback, run in the RegConfig host thread whenever
// the registry configuration changes
class Callback {
public:
virtual ~Callback() {}
virtual void regConfigChanged() = 0;
};
void setCallback(Callback* cb) { callback = cb; }
// Read entries from the specified key into the Configuration
static void loadRegistryConfig(RegKey& key);
protected:
// EventHandler interface and trigger event
virtual void processEvent(HANDLE event);
EventManager* eventMgr;
Handle event;
Callback* callback;
RegKey key;
};
class RegConfigThread : os::Thread {
public:
RegConfigThread();
~RegConfigThread();
// Start the thread, reading from the specified key
bool start(const HKEY rootkey, const TCHAR* keyname);
protected:
virtual void worker();
EventManager eventMgr;
RegConfig config;
DWORD thread_id;
};
};
};
#endif // __RFB_WIN32_REG_CONFIG_H__

311
win/rfb_win32/Registry.cxx Normal file
View File

@@ -0,0 +1,311 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Registry.cxx
#include <rfb_win32/Registry.h>
#include <rfb_win32/Security.h>
#include <rdr/MemOutStream.h>
#include <rdr/HexOutStream.h>
#include <rdr/HexInStream.h>
#include <stdlib.h>
#include <rfb/LogWriter.h>
// These flags are required to control access control inheritance,
// but are not defined by VC6's headers. These definitions comes
// from the Microsoft Platform SDK.
#ifndef PROTECTED_DACL_SECURITY_INFORMATION
#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L)
#endif
#ifndef UNPROTECTED_DACL_SECURITY_INFORMATION
#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L)
#endif
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("Registry");
RegKey::RegKey() : key(0), freeKey(false), valueNameBufLen(0) {}
RegKey::RegKey(const HKEY k) : key(0), freeKey(false), valueNameBufLen(0) {
LONG result = RegOpenKeyEx(k, 0, 0, KEY_ALL_ACCESS, &key);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegOpenKeyEx(HKEY)", result);
vlog.debug("duplicated %p to %p", k, key);
freeKey = true;
}
RegKey::RegKey(const RegKey& k) : key(0), freeKey(false), valueNameBufLen(0) {
LONG result = RegOpenKeyEx(k.key, 0, 0, KEY_ALL_ACCESS, &key);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegOpenKeyEx(RegKey&)", result);
vlog.debug("duplicated %p to %p", k.key, key);
freeKey = true;
}
RegKey::~RegKey() {
close();
}
void RegKey::setHKEY(HKEY k, bool fK) {
vlog.debug("setHKEY(%p,%d)", k, (int)fK);
close();
freeKey = fK;
key = k;
}
bool RegKey::createKey(const RegKey& root, const TCHAR* name) {
close();
LONG result = RegCreateKey(root.key, name, &key);
if (result != ERROR_SUCCESS) {
vlog.error("RegCreateKey(%p, %s): %lx", root.key, name, result);
throw rdr::SystemException("RegCreateKeyEx", result);
}
vlog.debug("createKey(%p,%s) = %p", root.key, (const char*)CStr(name), key);
freeKey = true;
return true;
}
void RegKey::openKey(const RegKey& root, const TCHAR* name, bool readOnly) {
close();
LONG result = RegOpenKeyEx(root.key, name, 0, readOnly ? KEY_READ : KEY_ALL_ACCESS, &key);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegOpenKeyEx (open)", result);
vlog.debug("openKey(%p,%s,%s) = %p", root.key, (const char*)CStr(name),
readOnly ? "ro" : "rw", key);
freeKey = true;
}
void RegKey::setDACL(const PACL acl, bool inherit) {
DWORD result;
if ((result = SetSecurityInfo(key, SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION |
(inherit ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION),
0, 0, acl, 0)) != ERROR_SUCCESS)
throw rdr::SystemException("RegKey::setDACL failed", result);
}
void RegKey::close() {
if (freeKey) {
vlog.debug("RegCloseKey(%p)", key);
RegCloseKey(key);
key = 0;
}
}
void RegKey::deleteKey(const TCHAR* name) const {
LONG result = RegDeleteKey(key, name);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegDeleteKey", result);
}
void RegKey::deleteValue(const TCHAR* name) const {
LONG result = RegDeleteValue(key, name);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegDeleteValue", result);
}
void RegKey::awaitChange(bool watchSubTree, DWORD filter, HANDLE event) const {
LONG result = RegNotifyChangeKeyValue(key, watchSubTree, filter, event, event != 0);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegNotifyChangeKeyValue", result);
}
RegKey::operator HKEY() const {return key;}
void RegKey::setExpandString(const TCHAR* valname, const TCHAR* value) const {
LONG result = RegSetValueEx(key, valname, 0, REG_EXPAND_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR));
if (result != ERROR_SUCCESS) throw rdr::SystemException("setExpandString", result);
}
void RegKey::setString(const TCHAR* valname, const TCHAR* value) const {
LONG result = RegSetValueEx(key, valname, 0, REG_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR));
if (result != ERROR_SUCCESS) throw rdr::SystemException("setString", result);
}
void RegKey::setBinary(const TCHAR* valname, const void* value, int length) const {
LONG result = RegSetValueEx(key, valname, 0, REG_BINARY, (const BYTE*)value, length);
if (result != ERROR_SUCCESS) throw rdr::SystemException("setBinary", result);
}
void RegKey::setInt(const TCHAR* valname, int value) const {
LONG result = RegSetValueEx(key, valname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
if (result != ERROR_SUCCESS) throw rdr::SystemException("setInt", result);
}
void RegKey::setBool(const TCHAR* valname, bool value) const {
setInt(valname, value ? 1 : 0);
}
TCHAR* RegKey::getString(const TCHAR* valname) const {return getRepresentation(valname);}
TCHAR* RegKey::getString(const TCHAR* valname, const TCHAR* def) const {
try {
return getString(valname);
} catch(rdr::Exception&) {
return tstrDup(def);
}
}
void RegKey::getBinary(const TCHAR* valname, void** data, int* length) const {
TCharArray hex(getRepresentation(valname));
if (!rdr::HexInStream::hexStrToBin(CStr(hex.buf), (char**)data, length))
throw rdr::Exception("getBinary failed");
}
void RegKey::getBinary(const TCHAR* valname, void** data, int* length, void* def, int deflen) const {
try {
getBinary(valname, data, length);
} catch(rdr::Exception&) {
if (deflen) {
*data = new char[deflen];
memcpy(*data, def, deflen);
} else
*data = 0;
*length = deflen;
}
}
int RegKey::getInt(const TCHAR* valname) const {
TCharArray tmp(getRepresentation(valname));
return _ttoi(tmp.buf);
}
int RegKey::getInt(const TCHAR* valname, int def) const {
try {
return getInt(valname);
} catch(rdr::Exception&) {
return def;
}
}
bool RegKey::getBool(const TCHAR* valname) const {
return getInt(valname) > 0;
}
bool RegKey::getBool(const TCHAR* valname, bool def) const {
return getInt(valname, def ? 1 : 0) > 0;
}
static inline TCHAR* terminateData(char* data, int length)
{
// We must terminate the string, just to be sure. Stupid Win32...
int len = length/sizeof(TCHAR);
TCharArray str(len+1);
memcpy(str.buf, data, length);
str.buf[len] = 0;
return str.takeBuf();
}
TCHAR* RegKey::getRepresentation(const TCHAR* valname) const {
DWORD type, length;
LONG result = RegQueryValueEx(key, valname, 0, &type, 0, &length);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("get registry value length", result);
CharArray data(length);
result = RegQueryValueEx(key, valname, 0, &type, (BYTE*)data.buf, &length);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("get registry value", result);
switch (type) {
case REG_BINARY:
{
TCharArray hex(rdr::HexOutStream::binToHexStr(data.buf, length));
return hex.takeBuf();
}
case REG_SZ:
if (length) {
return terminateData(data.buf, length);
} else {
return tstrDup(_T(""));
}
case REG_DWORD:
{
TCharArray tmp(16);
_stprintf(tmp.buf, _T("%lu"), *((DWORD*)data.buf));
return tmp.takeBuf();
}
case REG_EXPAND_SZ:
{
if (length) {
TCharArray str(terminateData(data.buf, length));
DWORD required = ExpandEnvironmentStrings(str.buf, 0, 0);
if (required==0)
throw rdr::SystemException("ExpandEnvironmentStrings", GetLastError());
TCharArray result(required);
length = ExpandEnvironmentStrings(str.buf, result.buf, required);
if (required<length)
rdr::Exception("unable to expand environment strings");
return result.takeBuf();
} else {
return tstrDup(_T(""));
}
}
default:
throw rdr::Exception("unsupported registry type");
}
}
bool RegKey::isValue(const TCHAR* valname) const {
try {
TCharArray tmp(getRepresentation(valname));
return true;
} catch(rdr::Exception&) {
return false;
}
}
const TCHAR* RegKey::getValueName(int i) {
DWORD maxValueNameLen;
LONG result = RegQueryInfoKey(key, 0, 0, 0, 0, 0, 0, 0, &maxValueNameLen, 0, 0, 0);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegQueryInfoKey", result);
if (valueNameBufLen < maxValueNameLen + 1) {
valueNameBufLen = maxValueNameLen + 1;
delete [] valueName.buf;
valueName.buf = new TCHAR[valueNameBufLen];
}
DWORD length = valueNameBufLen;
result = RegEnumValue(key, i, valueName.buf, &length, NULL, 0, 0, 0);
if (result == ERROR_NO_MORE_ITEMS) return 0;
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegEnumValue", result);
return valueName.buf;
}
const TCHAR* RegKey::getKeyName(int i) {
DWORD maxValueNameLen;
LONG result = RegQueryInfoKey(key, 0, 0, 0, 0, &maxValueNameLen, 0, 0, 0, 0, 0, 0);
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegQueryInfoKey", result);
if (valueNameBufLen < maxValueNameLen + 1) {
valueNameBufLen = maxValueNameLen + 1;
delete [] valueName.buf;
valueName.buf = new TCHAR[valueNameBufLen];
}
DWORD length = valueNameBufLen;
result = RegEnumKeyEx(key, i, valueName.buf, &length, NULL, 0, 0, 0);
if (result == ERROR_NO_MORE_ITEMS) return 0;
if (result != ERROR_SUCCESS)
throw rdr::SystemException("RegEnumKey", result);
return valueName.buf;
}

112
win/rfb_win32/Registry.h Normal file
View File

@@ -0,0 +1,112 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Registry.h
// C++ wrappers around the Win32 Registry APIs
#ifndef __RFB_WIN32_REGISTRY_H__
#define __RFB_WIN32_REGISTRY_H__
#include <windows.h>
#include <rfb_win32/Security.h>
#include <rfb/util.h>
namespace rfb {
namespace win32 {
class RegKey {
public:
// No key open
RegKey();
// Duplicate the specified existing key
RegKey(const HKEY k);
RegKey(const RegKey& k);
// Calls close() internally
~RegKey();
void setHKEY(HKEY key, bool freeKey);
private:
RegKey& operator=(const RegKey& k);
HKEY& operator=(const HKEY& k);
public:
// Returns true if key was created, false if already existed
bool createKey(const RegKey& root, const TCHAR* name);
// Opens key if it exists, or raises an exception if not
void openKey(const RegKey& root, const TCHAR* name, bool readOnly=false);
// Set the (discretionary) access control list for the key
void setDACL(const PACL acl, bool inheritFromParent=true);
// Closes current key, if required
void close();
// Delete a subkey/value
void deleteKey(const TCHAR* name) const;
void deleteValue(const TCHAR* name) const;
// Block waiting for a registry change, OR return immediately and notify the
// event when there is a change, if specified
void awaitChange(bool watchSubTree, DWORD filter, HANDLE event=0) const;
void setExpandString(const TCHAR* valname, const TCHAR* s) const;
void setString(const TCHAR* valname, const TCHAR* s) const;
void setBinary(const TCHAR* valname, const void* data, int length) const;
void setInt(const TCHAR* valname, int i) const;
void setBool(const TCHAR* valname, bool b) const;
TCHAR* getString(const TCHAR* valname) const;
TCHAR* getString(const TCHAR* valname, const TCHAR* def) const;
void getBinary(const TCHAR* valname, void** data, int* length) const;
void getBinary(const TCHAR* valname, void** data, int* length, void* def, int deflength) const;
int getInt(const TCHAR* valname) const;
int getInt(const TCHAR* valname, int def) const;
bool getBool(const TCHAR* valname) const;
bool getBool(const TCHAR* valname, bool def) const;
TCHAR* getRepresentation(const TCHAR* valname) const;
bool isValue(const TCHAR* valname) const;
// Get the name of value/key number "i"
// If there are fewer than "i" values then return 0
// NAME IS OWNED BY RegKey OBJECT!
const TCHAR* getValueName(int i);
const TCHAR* getKeyName(int i);
operator HKEY() const;
protected:
HKEY key;
bool freeKey;
TCharArray valueName;
DWORD valueNameBufLen;
};
};
};
#endif // __RFB_WIN32_REG_CONFIG_H__

509
win/rfb_win32/SDisplay.cxx Normal file
View File

@@ -0,0 +1,509 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- SDisplay.cxx
//
// The SDisplay class encapsulates a particular system display.
#include <rfb_win32/SDisplay.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/TsSessions.h>
#include <rfb_win32/CleanDesktop.h>
#include <rfb_win32/CurrentUser.h>
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/SDisplayCorePolling.h>
#include <rfb_win32/SDisplayCoreWMHooks.h>
#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/ledStates.h>
using namespace rdr;
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("SDisplay");
// - SDisplay-specific configuration options
IntParameter rfb::win32::SDisplay::updateMethod("UpdateMethod",
"How to discover desktop updates; 0 - Polling, 1 - Application hooking, 2 - Driver hooking.", 1);
BoolParameter rfb::win32::SDisplay::disableLocalInputs("DisableLocalInputs",
"Disable local keyboard and pointer input while the server is in use", false);
StringParameter rfb::win32::SDisplay::disconnectAction("DisconnectAction",
"Action to perform when all clients have disconnected. (None, Lock, Logoff)", "None");
StringParameter displayDevice("DisplayDevice",
"Display device name of the monitor to be remoted, or empty to export the whole desktop.", "");
BoolParameter rfb::win32::SDisplay::removeWallpaper("RemoveWallpaper",
"Remove the desktop wallpaper when the server is in use.", false);
BoolParameter rfb::win32::SDisplay::disableEffects("DisableEffects",
"Disable desktop user interface effects when the server is in use.", false);
//////////////////////////////////////////////////////////////////////////////
//
// SDisplay
//
// -=- Constructor/Destructor
SDisplay::SDisplay()
: server(0), pb(0), device(0),
core(0), ptr(0), kbd(0), clipboard(0),
inputs(0), monitor(0), cleanDesktop(0), cursor(0),
statusLocation(0), ledState(0)
{
updateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
}
SDisplay::~SDisplay()
{
// XXX when the VNCServer has been deleted with clients active, stop()
// doesn't get called - this ought to be fixed in VNCServerST. In any event,
// we should never call any methods on VNCServer once we're being deleted.
// This is because it is supposed to be guaranteed that the SDesktop exists
// throughout the lifetime of the VNCServer. So if we're being deleted, then
// the VNCServer ought not to exist and therefore we shouldn't invoke any
// methods on it. Setting server to zero here ensures that stop() doesn't
// call setPixelBuffer(0) on the server.
server = 0;
if (core) stop();
}
// -=- SDesktop interface
void SDisplay::start(VNCServer* vs)
{
vlog.debug("starting");
// Try to make session zero the console session
if (!inConsoleSession())
setConsoleSession();
// Start the SDisplay core
server = vs;
startCore();
vlog.debug("started");
if (statusLocation) *statusLocation = true;
}
void SDisplay::stop()
{
vlog.debug("stopping");
// If we successfully start()ed then perform the DisconnectAction
if (core) {
CurrentUserToken cut;
CharArray action(disconnectAction.getData());
if (stricmp(action.buf, "Logoff") == 0) {
if (!cut.h)
vlog.info("ignoring DisconnectAction=Logoff - no current user");
else
ExitWindowsEx(EWX_LOGOFF, 0);
} else if (stricmp(action.buf, "Lock") == 0) {
if (!cut.h) {
vlog.info("ignoring DisconnectAction=Lock - no current user");
} else {
LockWorkStation();
}
}
}
// Stop the SDisplayCore
if (server)
server->setPixelBuffer(0);
stopCore();
server = 0;
vlog.debug("stopped");
if (statusLocation) *statusLocation = false;
}
void SDisplay::startCore() {
// Currently, we just check whether we're in the console session, and
// fail if not
if (!inConsoleSession())
throw rdr::Exception("Console is not session zero - oreconnect to restore Console sessin");
// Switch to the current input desktop
if (rfb::win32::desktopChangeRequired()) {
if (!rfb::win32::changeDesktop())
throw rdr::Exception("unable to switch into input desktop");
}
// Initialise the change tracker and clipper
updates.clear();
clipper.setUpdateTracker(server);
// Create the framebuffer object
recreatePixelBuffer(true);
// Create the SDisplayCore
updateMethod_ = updateMethod;
int tryMethod = updateMethod_;
while (!core) {
try {
if (tryMethod == 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("%s", 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 (removeWallpaper)
cleanDesktop->disableWallpaper();
if (disableEffects)
cleanDesktop->disableEffects();
isWallpaperRemoved = removeWallpaper;
areEffectsDisabled = disableEffects;
checkLedState();
if (server)
server->setLEDState(ledState);
}
void SDisplay::stopCore() {
if (core)
vlog.info("Stopping %s", core->methodName());
delete core; core = 0;
delete pb; pb = 0;
delete device; device = 0;
delete monitor; monitor = 0;
delete clipboard; clipboard = 0;
delete inputs; inputs = 0;
delete ptr; ptr = 0;
delete kbd; kbd = 0;
delete cleanDesktop; cleanDesktop = 0;
delete cursor; cursor = 0;
ResetEvent(updateEvent);
}
bool SDisplay::isRestartRequired() {
// - We must restart the SDesktop if:
// 1. We are no longer in the input desktop.
// 2. The any setting has changed.
// - Check that our session is the Console
if (!inConsoleSession())
return true;
// - Check that we are in the input desktop
if (rfb::win32::desktopChangeRequired())
return true;
// - Check that the update method setting hasn't changed
// NB: updateMethod reflects the *selected* update method, not
// necessarily the one in use, since we fall back to simpler
// methods if more advanced ones fail!
if (updateMethod_ != updateMethod)
return true;
// - Check that the desktop optimisation settings haven't changed
// This isn't very efficient, but it shouldn't change very often!
if ((isWallpaperRemoved != removeWallpaper) ||
(areEffectsDisabled != disableEffects))
return true;
return false;
}
void SDisplay::restartCore() {
vlog.info("restarting");
// Stop the existing Core related resources
stopCore();
try {
// Start a new Core if possible
startCore();
vlog.info("restarted");
} catch (rdr::Exception& e) {
// If startCore() fails then we MUST disconnect all clients,
// to cause the server to stop() the desktop.
// Otherwise, the SDesktop is in an inconsistent state
// and the server will crash.
server->closeClients(e.str());
}
}
void SDisplay::pointerEvent(const Point& pos, int buttonmask) {
if (pb->getRect().contains(pos)) {
Point screenPos = pos.translate(screenRect.tl);
// - Check that the SDesktop doesn't need restarting
if (isRestartRequired())
restartCore();
if (ptr)
ptr->pointerEvent(screenPos, buttonmask);
}
}
void SDisplay::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
// - Check that the SDesktop doesn't need restarting
if (isRestartRequired())
restartCore();
if (kbd)
kbd->keyEvent(keysym, keycode, down);
}
bool SDisplay::checkLedState() {
unsigned state = 0;
if (GetKeyState(VK_SCROLL) & 0x0001)
state |= ledScrollLock;
if (GetKeyState(VK_NUMLOCK) & 0x0001)
state |= ledNumLock;
if (GetKeyState(VK_CAPITAL) & 0x0001)
state |= ledCapsLock;
if (ledState != state) {
ledState = state;
return true;
}
return false;
}
void SDisplay::clientCutText(const char* text, int len) {
CharArray clip_sz(len+1);
memcpy(clip_sz.buf, text, len);
clip_sz.buf[len] = 0;
clipboard->setClipText(clip_sz.buf);
}
Point SDisplay::getFbSize() {
bool startAndStop = !core;
// If not started, do minimal initialisation to get desktop size.
if (startAndStop)
recreatePixelBuffer();
Point result = Point(pb->width(), pb->height());
// Destroy the initialised structures.
if (startAndStop)
stopCore();
return result;
}
void
SDisplay::notifyClipboardChanged(const char* text, int len) {
vlog.debug("clipboard text changed");
if (server)
server->serverCutText(text, len);
}
void
SDisplay::notifyDisplayEvent(WMMonitor::Notifier::DisplayEventType evt) {
switch (evt) {
case WMMonitor::Notifier::DisplaySizeChanged:
vlog.debug("desktop size changed");
recreatePixelBuffer();
break;
case WMMonitor::Notifier::DisplayPixelFormatChanged:
vlog.debug("desktop format changed");
recreatePixelBuffer();
break;
default:
vlog.error("unknown display event received");
}
}
void
SDisplay::processEvent(HANDLE event) {
if (event == updateEvent) {
vlog.write(120, "processEvent");
ResetEvent(updateEvent);
// - If the SDisplay isn't even started then quit now
if (!core) {
vlog.error("not start()ed");
return;
}
// - Ensure that the disableLocalInputs flag is respected
inputs->blockInputs(disableLocalInputs);
// - Only process updates if the server is ready
if (server) {
// - Check that the SDesktop doesn't need restarting
if (isRestartRequired()) {
restartCore();
return;
}
// - Flush any updates from the core
try {
core->flushUpdates();
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
restartCore();
return;
}
// Ensure the cursor is up to date
WMCursor::Info info = cursor->getCursorInfo();
if (old_cursor != info) {
// Update the cursor shape if the visibility has changed
bool set_cursor = info.visible != old_cursor.visible;
// OR if the cursor is visible and the shape has changed.
set_cursor |= info.visible && (old_cursor.cursor != info.cursor);
// Update the cursor shape
if (set_cursor)
pb->setCursor(info.visible ? info.cursor : 0, server);
// Update the cursor position
// NB: First translate from Screen coordinates to Desktop
Point desktopPos = info.position.translate(screenRect.tl.negate());
server->setCursorPos(desktopPos);
old_cursor = info;
}
// Flush any changes to the server
flushChangeTracker();
// Forward current LED state to the server
if (checkLedState())
server->setLEDState(ledState);
}
return;
}
throw rdr::Exception("No such event");
}
// -=- Protected methods
void
SDisplay::recreatePixelBuffer(bool force) {
// Open the specified display device
// If no device is specified, open entire screen using GetDC().
// Opening the whole display with CreateDC doesn't work on multi-monitor
// systems for some reason.
DeviceContext* new_device = 0;
TCharArray deviceName(displayDevice.getData());
if (deviceName.buf[0]) {
vlog.info("Attaching to device %s", (const char*)CStr(deviceName.buf));
new_device = new DeviceDC(deviceName.buf);
}
if (!new_device) {
vlog.info("Attaching to virtual desktop");
new_device = new WindowDC(0);
}
// Get the coordinates of the specified dispay device
Rect newScreenRect;
if (deviceName.buf[0]) {
MonitorInfo info(CStr(deviceName.buf));
newScreenRect = Rect(info.rcMonitor.left, info.rcMonitor.top,
info.rcMonitor.right, info.rcMonitor.bottom);
} else {
newScreenRect = new_device->getClipBox();
}
// If nothing has changed & a recreate has not been forced, delete
// the new device context and return
if (pb && !force &&
newScreenRect.equals(screenRect) &&
new_device->getPF().equal(pb->getPF())) {
delete new_device;
return;
}
// Flush any existing changes to the server
flushChangeTracker();
// Delete the old pixelbuffer and device context
vlog.debug("deleting old pixel buffer & device");
if (pb)
delete pb;
if (device)
delete device;
// Create a DeviceFrameBuffer attached to the new device
vlog.debug("creating pixel buffer");
DeviceFrameBuffer* new_buffer = new DeviceFrameBuffer(*new_device);
// Replace the old PixelBuffer
screenRect = newScreenRect;
pb = new_buffer;
device = new_device;
// Initialise the pixels
pb->grabRegion(pb->getRect());
// Prevent future grabRect operations from throwing exceptions
pb->setIgnoreGrabErrors(true);
// Update the clipping update tracker
clipper.setClipRect(pb->getRect());
// Inform the core of the changes
if (core)
core->setScreenRect(screenRect);
// Inform the server of the changes
if (server)
server->setPixelBuffer(pb);
}
bool SDisplay::flushChangeTracker() {
if (updates.is_empty())
return false;
vlog.write(120, "flushChangeTracker");
// Translate the update coordinates from Screen coords to Desktop
updates.translate(screenRect.tl.negate());
// Clip the updates & flush them to the server
updates.copyTo(&clipper);
updates.clear();
return true;
}

165
win/rfb_win32/SDisplay.h Normal file
View File

@@ -0,0 +1,165 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- SDisplay.h
//
// The SDisplay class encapsulates a system display.
#ifndef __RFB_SDISPLAY_H__
#define __RFB_SDISPLAY_H__
#include <rfb/SDesktop.h>
#include <rfb/UpdateTracker.h>
#include <rfb/Configuration.h>
#include <rfb_win32/Handle.h>
#include <rfb_win32/EventManager.h>
#include <rfb_win32/SInput.h>
#include <rfb_win32/Clipboard.h>
#include <rfb_win32/CleanDesktop.h>
#include <rfb_win32/WMCursor.h>
#include <rfb_win32/WMNotifier.h>
#include <rfb_win32/DeviceFrameBuffer.h>
#include <rfb_win32/DeviceContext.h>
namespace rfb {
namespace win32 {
//
// -=- SDisplay
//
class SDisplayCore {
public:
virtual ~SDisplayCore() {};
virtual void setScreenRect(const Rect& screenRect_) = 0;
virtual void flushUpdates() = 0;
virtual const char* methodName() const = 0;
};
class SDisplay : public SDesktop,
WMMonitor::Notifier,
Clipboard::Notifier,
public EventHandler
{
public:
SDisplay();
virtual ~SDisplay();
// -=- SDesktop interface
virtual void start(VNCServer* vs);
virtual void stop();
virtual void pointerEvent(const Point& pos, int buttonmask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void clientCutText(const char* str, int len);
// -=- Clipboard
virtual void notifyClipboardChanged(const char* text, int len);
// -=- Display events
virtual void notifyDisplayEvent(WMMonitor::Notifier::DisplayEventType evt);
// -=- EventHandler interface
HANDLE getUpdateEvent() {return updateEvent;}
virtual void processEvent(HANDLE event);
// -=- Notification of whether or not SDisplay is started
void setStatusLocation(bool* status) {statusLocation = status;}
// -=- Used (indirectly) by JavaViewer to get desktop size
Point getFbSize();
friend class SDisplayCore;
static IntParameter updateMethod;
static BoolParameter disableLocalInputs;
static StringParameter disconnectAction;
static BoolParameter removeWallpaper;
static BoolParameter disableEffects;
// -=- Use by VNC Config to determine whether hooks are available
static bool areHooksAvailable();
protected:
bool isRestartRequired();
void startCore();
void stopCore();
void restartCore();
void recreatePixelBuffer(bool force=false);
bool flushChangeTracker(); // true if flushed, false if empty
bool checkLedState();
VNCServer* server;
// -=- Display pixel buffer
DeviceFrameBuffer* pb;
DeviceContext* device;
// -=- The coordinates of Window's entire virtual Screen
Rect screenRect;
// -=- All changes are collected in UN-CLIPPED Display coords and merged
// When they are to be flushed to the VNCServer, they are changed
// to server coords and clipped appropriately.
SimpleUpdateTracker updates;
ClippingUpdateTracker clipper;
// -=- Internal SDisplay implementation
SDisplayCore* core;
int updateMethod_;
// Inputs
SPointer* ptr;
SKeyboard* kbd;
Clipboard* clipboard;
WMBlockInput* inputs;
// Desktop state
WMMonitor* monitor;
// Desktop optimisation
CleanDesktop* cleanDesktop;
bool isWallpaperRemoved;
bool areEffectsDisabled;
// Cursor
WMCursor* cursor;
WMCursor::Info old_cursor;
Region old_cursor_region;
Point cursor_renderpos;
// -=- Event signalled to trigger an update to be flushed
Handle updateEvent;
// -=- Where to write the active/inactive indicator to
bool* statusLocation;
unsigned ledState;
};
}
}
#endif // __RFB_SDISPLAY_H__

View File

@@ -0,0 +1,82 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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>
#include <rfb/util.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("SDisplayCorePolling");
const int POLLING_SEGMENTS = 16;
const unsigned int SDisplayCorePolling::pollTimerId = 1;
SDisplayCorePolling::SDisplayCorePolling(SDisplay* d, UpdateTracker* ut, int pollInterval_)
: MsgWindow(_T("rfb::win32::SDisplayCorePolling")),
pollTimer(getHandle(), pollTimerId), pollNextStrip(false), display(d), updateTracker(ut) {
pollInterval = __rfbmax(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 = __rfbmin(pollNextY, pollrect.br.y);
updateTracker->add_changed(pollrect);
}
}
}

View File

@@ -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 unsigned 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

View File

@@ -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 unsigned int SDisplayCoreWMHooks::cursorTimerId = 2;
const unsigned 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();
}

View File

@@ -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 unsigned int consolePollTimerId;
static const unsigned int cursorTimerId;
};
};
};
#endif

490
win/rfb_win32/SInput.cxx Normal file
View File

@@ -0,0 +1,490 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- SInput.cxx
//
// A number of routines that accept VNC input event data and perform
// the appropriate actions under Win32
#define XK_MISCELLANY
#define XK_LATIN1
#define XK_CURRENCY
#include <rfb/keysymdef.h>
#include <tchar.h>
#include <rfb_win32/SInput.h>
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/keymap.h>
#include <rdr/Exception.h>
#include <rfb/LogWriter.h>
using namespace rfb;
static LogWriter vlog("SInput");
//
// -=- Pointer implementation for Win32
//
static DWORD buttonDownMapping[8] = {
MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN,
MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, 0, 0, 0
};
static DWORD buttonUpMapping[8] = {
MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP,
MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, 0, 0, 0
};
static DWORD buttonDataMapping[8] = {
0, 0, 0, 120, (DWORD)-120, 0, 0, 0
};
win32::SPointer::SPointer()
: last_buttonmask(0)
{
}
void
win32::SPointer::pointerEvent(const Point& pos, int buttonmask)
{
// - We are specifying absolute coordinates
DWORD flags = MOUSEEVENTF_ABSOLUTE;
// - Has the pointer moved since the last event?
if (!last_position.equals(pos))
flags |= MOUSEEVENTF_MOVE;
// - If the system swaps left and right mouse buttons then we must
// swap them here to negate the effect, so that we do the actual
// action we mean to do
if (::GetSystemMetrics(SM_SWAPBUTTON)) {
bool leftDown = buttonmask & 1;
bool rightDown = buttonmask & 4;
buttonmask = (buttonmask & ~(1 | 4));
if (leftDown) buttonmask |= 4;
if (rightDown) buttonmask |= 1;
}
DWORD data = 0;
for (int i = 0; i < 8; i++) {
if ((buttonmask & (1<<i)) != (last_buttonmask & (1<<i))) {
if (buttonmask & (1<<i)) {
flags |= buttonDownMapping[i];
if (buttonDataMapping[i]) {
if (data) vlog.info("warning - two buttons set mouse_event data field");
data = buttonDataMapping[i];
}
} else {
flags |= buttonUpMapping[i];
}
}
}
last_position = pos;
last_buttonmask = buttonmask;
Rect primaryDisplay(0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
if (primaryDisplay.contains(pos)) {
// mouse_event wants coordinates specified as a proportion of the
// primary display's size, scaled to the range 0 to 65535
Point scaled;
scaled.x = (pos.x * 65535) / (primaryDisplay.width()-1);
scaled.y = (pos.y * 65535) / (primaryDisplay.height()-1);
::mouse_event(flags, scaled.x, scaled.y, data, 0);
} else {
// The event lies outside the primary monitor. Under Win2K, we can just use
// SendInput, which allows us to provide coordinates scaled to the virtual desktop.
// SendInput is available on all multi-monitor-aware platforms.
INPUT evt;
evt.type = INPUT_MOUSE;
Point vPos(pos.x-GetSystemMetrics(SM_XVIRTUALSCREEN),
pos.y-GetSystemMetrics(SM_YVIRTUALSCREEN));
evt.mi.dx = (vPos.x * 65535) / (GetSystemMetrics(SM_CXVIRTUALSCREEN)-1);
evt.mi.dy = (vPos.y * 65535) / (GetSystemMetrics(SM_CYVIRTUALSCREEN)-1);
evt.mi.dwFlags = flags | MOUSEEVENTF_VIRTUALDESK;
evt.mi.dwExtraInfo = 0;
evt.mi.mouseData = data;
evt.mi.time = 0;
if (SendInput(1, &evt, sizeof(evt)) != 1)
throw rdr::SystemException("SendInput", GetLastError());
}
}
//
// -=- Keyboard implementation
//
BoolParameter rfb::win32::SKeyboard::deadKeyAware("DeadKeyAware",
"Whether to assume the viewer has already interpreted dead key sequences "
"into latin-1 characters", true);
BoolParameter rfb::win32::SKeyboard::rawKeyboard("RawKeyboard",
"Send keyboard events straight through and avoid mapping them to the "
"current keyboard layout", false);
// The keysymToAscii table transforms a couple of awkward keysyms into their
// ASCII equivalents.
struct keysymToAscii_t {
rdr::U32 keysym;
rdr::U8 ascii;
};
keysymToAscii_t keysymToAscii[] = {
{ XK_KP_Space, ' ' },
{ XK_KP_Equal, '=' },
};
rdr::U8 latin1DeadChars[] = {
XK_grave, XK_acute, XK_asciicircum, XK_diaeresis, XK_degree, XK_cedilla,
XK_asciitilde
};
struct latin1ToDeadChars_t {
rdr::U8 latin1Char;
rdr::U8 deadChar;
rdr::U8 baseChar;
};
latin1ToDeadChars_t latin1ToDeadChars[] = {
{ XK_Agrave, XK_grave, XK_A },
{ XK_Egrave, XK_grave, XK_E },
{ XK_Igrave, XK_grave, XK_I },
{ XK_Ograve, XK_grave, XK_O },
{ XK_Ugrave, XK_grave, XK_U },
{ XK_agrave, XK_grave, XK_a },
{ XK_egrave, XK_grave, XK_e },
{ XK_igrave, XK_grave, XK_i },
{ XK_ograve, XK_grave, XK_o},
{ XK_ugrave, XK_grave, XK_u },
{ XK_Aacute, XK_acute, XK_A },
{ XK_Eacute, XK_acute, XK_E },
{ XK_Iacute, XK_acute, XK_I },
{ XK_Oacute, XK_acute, XK_O },
{ XK_Uacute, XK_acute, XK_U },
{ XK_Yacute, XK_acute, XK_Y },
{ XK_aacute, XK_acute, XK_a },
{ XK_eacute, XK_acute, XK_e },
{ XK_iacute, XK_acute, XK_i },
{ XK_oacute, XK_acute, XK_o},
{ XK_uacute, XK_acute, XK_u },
{ XK_yacute, XK_acute, XK_y },
{ XK_Acircumflex, XK_asciicircum, XK_A },
{ XK_Ecircumflex, XK_asciicircum, XK_E },
{ XK_Icircumflex, XK_asciicircum, XK_I },
{ XK_Ocircumflex, XK_asciicircum, XK_O },
{ XK_Ucircumflex, XK_asciicircum, XK_U },
{ XK_acircumflex, XK_asciicircum, XK_a },
{ XK_ecircumflex, XK_asciicircum, XK_e },
{ XK_icircumflex, XK_asciicircum, XK_i },
{ XK_ocircumflex, XK_asciicircum, XK_o},
{ XK_ucircumflex, XK_asciicircum, XK_u },
{ XK_Adiaeresis, XK_diaeresis, XK_A },
{ XK_Ediaeresis, XK_diaeresis, XK_E },
{ XK_Idiaeresis, XK_diaeresis, XK_I },
{ XK_Odiaeresis, XK_diaeresis, XK_O },
{ XK_Udiaeresis, XK_diaeresis, XK_U },
{ XK_adiaeresis, XK_diaeresis, XK_a },
{ XK_ediaeresis, XK_diaeresis, XK_e },
{ XK_idiaeresis, XK_diaeresis, XK_i },
{ XK_odiaeresis, XK_diaeresis, XK_o},
{ XK_udiaeresis, XK_diaeresis, XK_u },
{ XK_ydiaeresis, XK_diaeresis, XK_y },
{ XK_Aring, XK_degree, XK_A },
{ XK_aring, XK_degree, XK_a },
{ XK_Ccedilla, XK_cedilla, XK_C },
{ XK_ccedilla, XK_cedilla, XK_c },
{ XK_Atilde, XK_asciitilde, XK_A },
{ XK_Ntilde, XK_asciitilde, XK_N },
{ XK_Otilde, XK_asciitilde, XK_O },
{ XK_atilde, XK_asciitilde, XK_a },
{ XK_ntilde, XK_asciitilde, XK_n },
{ XK_otilde, XK_asciitilde, XK_o },
};
// doKeyboardEvent wraps the system keybd_event function and attempts to find
// the appropriate scancode corresponding to the supplied virtual keycode.
inline void doKeyboardEvent(BYTE vkCode, DWORD flags) {
vlog.debug("vkCode 0x%x flags 0x%lx", vkCode, flags);
keybd_event(vkCode, MapVirtualKey(vkCode, 0), flags, 0);
}
inline void doScanCodeEvent(BYTE scancode, bool down) {
INPUT evt;
evt.type = INPUT_KEYBOARD;
evt.ki.wVk = 0;
evt.ki.dwFlags = KEYEVENTF_SCANCODE;
if (!down)
evt.ki.dwFlags |= KEYEVENTF_KEYUP;
if (scancode & 0x80) {
evt.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
scancode &= ~0x80;
}
evt.ki.wScan = scancode;
evt.ki.dwExtraInfo = 0;
evt.ki.time = 0;
vlog.debug("SendInput ScanCode: 0x%x Flags: 0x%lx %s", scancode,
evt.ki.dwFlags, down ? "Down" : "Up");
// Windows has some bug where it doesn't look up scan code 0x45
// properly, so we need to help it out
if (evt.ki.wScan == 0x45) {
evt.ki.dwFlags &= ~KEYEVENTF_SCANCODE;
if (evt.ki.dwFlags & KEYEVENTF_EXTENDEDKEY)
evt.ki.wVk = VK_NUMLOCK;
else
evt.ki.wVk = VK_PAUSE;
}
if (SendInput(1, &evt, sizeof(evt)) != 1)
vlog.error("SendInput %lu", GetLastError());
}
// KeyStateModifier is a class which helps simplify generating a "fake" press
// or release of shift, ctrl, alt, etc. An instance of the class is created
// for every key which may need to be pressed or released. Then either press()
// or release() may be called to make sure that the corresponding key is in the
// right state. The destructor of the class automatically reverts to the
// previous state.
class KeyStateModifier {
public:
KeyStateModifier(int vkCode_, int flags_=0)
: vkCode(vkCode_), flags(flags_), pressed(false), released(false)
{}
void press() {
if (!(GetAsyncKeyState(vkCode) & 0x8000)) {
doKeyboardEvent(vkCode, flags);
pressed = true;
}
}
void release() {
if (GetAsyncKeyState(vkCode) & 0x8000) {
doKeyboardEvent(vkCode, flags | KEYEVENTF_KEYUP);
released = true;
}
}
~KeyStateModifier() {
if (pressed) {
doKeyboardEvent(vkCode, flags | KEYEVENTF_KEYUP);
} else if (released) {
doKeyboardEvent(vkCode, flags);
}
}
int vkCode;
int flags;
bool pressed;
bool released;
};
// doKeyEventWithModifiers() generates a key event having first "pressed" or
// "released" the shift, ctrl or alt modifiers if necessary.
void doKeyEventWithModifiers(BYTE vkCode, BYTE modifierState, bool down)
{
KeyStateModifier ctrl(VK_CONTROL);
KeyStateModifier alt(VK_MENU);
KeyStateModifier shift(VK_SHIFT);
if (down) {
if (modifierState & 2) ctrl.press();
if (modifierState & 4) alt.press();
if (modifierState & 1) {
shift.press();
} else {
shift.release();
}
}
doKeyboardEvent(vkCode, down ? 0 : KEYEVENTF_KEYUP);
}
win32::SKeyboard::SKeyboard()
{
for (unsigned int i = 0; i < sizeof(keymap) / sizeof(keymap_t); i++) {
vkMap[keymap[i].keysym] = keymap[i].vk;
extendedMap[keymap[i].keysym] = keymap[i].extended;
}
// Find dead characters for the current keyboard layout
// XXX how could we handle the keyboard layout changing?
BYTE keystate[256];
memset(keystate, 0, 256);
for (unsigned int j = 0; j < sizeof(latin1DeadChars); j++) {
SHORT s = VkKeyScan(latin1DeadChars[j]);
if (s != -1) {
BYTE vkCode = LOBYTE(s);
BYTE modifierState = HIBYTE(s);
keystate[VK_SHIFT] = (modifierState & 1) ? 0x80 : 0;
keystate[VK_CONTROL] = (modifierState & 2) ? 0x80 : 0;
keystate[VK_MENU] = (modifierState & 4) ? 0x80 : 0;
rdr::U8 chars[2];
int nchars = ToAscii(vkCode, 0, keystate, (WORD*)&chars, 0);
if (nchars < 0) {
vlog.debug("Found dead key 0x%x '%c'",
latin1DeadChars[j], latin1DeadChars[j]);
deadChars.push_back(latin1DeadChars[j]);
ToAscii(vkCode, 0, keystate, (WORD*)&chars, 0);
}
}
}
}
void win32::SKeyboard::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
{
// If scan code is available use that directly as windows uses
// compatible scancodes
if (keycode && rawKeyboard) {
// However NumLock incorrectly has the extended bit set
if (keycode == 0x45)
keycode = 0xc5;
// And Pause uses NumLock's proper code, except when Control is
// also pressed (i.e. when it is generating Break)
if ((keycode == 0xc6) && !(GetAsyncKeyState(VK_CONTROL) & 0x8000))
keycode = 0x45;
// And PrintScreen uses a different code than Alt+PrintScreen (SysRq)
if ((keycode == 0x54) && !(GetAsyncKeyState(VK_MENU) & 0x8000))
keycode = 0xb7;
if (down && (keycode == 0xd3) &&
((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) &&
((GetAsyncKeyState(VK_MENU) & 0x8000) != 0))
{
rfb::win32::emulateCtrlAltDel();
return;
}
doScanCodeEvent(keycode, down);
return;
}
for (unsigned int i = 0; i < sizeof(keysymToAscii) / sizeof(keysymToAscii_t); i++) {
if (keysymToAscii[i].keysym == keysym) {
keysym = keysymToAscii[i].ascii;
break;
}
}
if ((keysym >= 32 && keysym <= 126) ||
(keysym >= 160 && keysym <= 255))
{
// ordinary Latin-1 character
if (deadKeyAware) {
// Detect dead chars and generate the dead char followed by space so
// that we'll end up with the original char.
for (unsigned int i = 0; i < deadChars.size(); i++) {
if (keysym == deadChars[i]) {
SHORT dc = VkKeyScan(keysym);
if (dc != -1) {
if (down) {
vlog.info("latin-1 dead key: 0x%x vkCode 0x%x mod 0x%x "
"followed by space", keysym, LOBYTE(dc), HIBYTE(dc));
doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), true);
doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), false);
doKeyEventWithModifiers(VK_SPACE, 0, true);
doKeyEventWithModifiers(VK_SPACE, 0, false);
}
return;
}
}
}
}
SHORT s = VkKeyScan(keysym);
if (s == -1) {
if (down) {
// not a single keypress - try synthesizing dead chars.
for (unsigned int j = 0;
j < sizeof(latin1ToDeadChars) / sizeof(latin1ToDeadChars_t);
j++) {
if (keysym == latin1ToDeadChars[j].latin1Char) {
for (unsigned int i = 0; i < deadChars.size(); i++) {
if (deadChars[i] == latin1ToDeadChars[j].deadChar) {
SHORT dc = VkKeyScan(latin1ToDeadChars[j].deadChar);
SHORT bc = VkKeyScan(latin1ToDeadChars[j].baseChar);
if (dc != -1 && bc != -1) {
vlog.info("latin-1 key: 0x%x dead key vkCode 0x%x mod 0x%x "
"followed by vkCode 0x%x mod 0x%x",
keysym, LOBYTE(dc), HIBYTE(dc),
LOBYTE(bc), HIBYTE(bc));
doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), true);
doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), false);
doKeyEventWithModifiers(LOBYTE(bc), HIBYTE(bc), true);
doKeyEventWithModifiers(LOBYTE(bc), HIBYTE(bc), false);
return;
}
break;
}
}
break;
}
}
vlog.info("ignoring unrecognised Latin-1 keysym 0x%x",keysym);
}
return;
}
BYTE vkCode = LOBYTE(s);
BYTE modifierState = HIBYTE(s);
vlog.debug("latin-1 key: 0x%x vkCode 0x%x mod 0x%x down %d",
keysym, vkCode, modifierState, down);
doKeyEventWithModifiers(vkCode, modifierState, down);
} else {
// see if it's a recognised keyboard key, otherwise ignore it
if (vkMap.find(keysym) == vkMap.end()) {
vlog.info("ignoring unknown keysym 0x%x",keysym);
return;
}
BYTE vkCode = vkMap[keysym];
DWORD flags = 0;
if (extendedMap[keysym]) flags |= KEYEVENTF_EXTENDEDKEY;
if (!down) flags |= KEYEVENTF_KEYUP;
vlog.debug("keyboard key: keysym 0x%x vkCode 0x%x ext %d down %d",
keysym, vkCode, extendedMap[keysym], down);
if (down && (vkCode == VK_DELETE) &&
((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) &&
((GetAsyncKeyState(VK_MENU) & 0x8000) != 0))
{
rfb::win32::emulateCtrlAltDel();
return;
}
doKeyboardEvent(vkCode, flags);
}
}

69
win/rfb_win32/SInput.h Normal file
View File

@@ -0,0 +1,69 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Input.h
//
// A number of routines that accept VNC-style input event data and perform
// the appropriate actions under Win32
#ifndef __RFB_WIN32_INPUT_H__
#define __RFB_WIN32_INPUT_H__
#include <rfb/Rect.h>
#include <rfb/Configuration.h>
#include <rdr/types.h>
#include <map>
#include <vector>
namespace rfb {
namespace win32 {
// -=- Pointer event handling
class SPointer {
public:
SPointer();
// - Create a pointer event at a the given coordinates, with the
// specified button state. The event must be specified using
// Screen coordinates.
void pointerEvent(const Point& pos, int buttonmask);
protected:
Point last_position;
rdr::U8 last_buttonmask;
};
// -=- Keyboard event handling
class SKeyboard {
public:
SKeyboard();
void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
static BoolParameter deadKeyAware;
static BoolParameter rawKeyboard;
private:
std::map<rdr::U32,rdr::U8> vkMap;
std::map<rdr::U32,bool> extendedMap;
std::vector<rdr::U8> deadChars;
};
}; // win32
}; // rfb
#endif // __RFB_WIN32_INPUT_H__

182
win/rfb_win32/Security.cxx Normal file
View File

@@ -0,0 +1,182 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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/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=%lu, domainLen=%lu, 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) {
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, (PSECURITY_DESCRIPTOR)sd.ptr, &sdSize))
throw rdr::SystemException("MakeSelfRelativeSD", GetLastError());
return sd.takeSD();
}

123
win/rfb_win32/Security.h Normal file
View File

@@ -0,0 +1,123 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// Security.h
// Wrapper classes for a few Windows NT security structures/functions
// that are used by VNC
#ifndef __RFB_WIN32_SECURITY_H__
#define __RFB_WIN32_SECURITY_H__
#include <rdr/types.h>
#include <rfb_win32/LocalMem.h>
#include <rfb_win32/TCharArray.h>
#include <aclapi.h>
namespace rfb {
namespace win32 {
struct Trustee : public TRUSTEE {
Trustee(const TCHAR* name,
TRUSTEE_FORM form=TRUSTEE_IS_NAME,
TRUSTEE_TYPE type=TRUSTEE_IS_UNKNOWN);
};
struct ExplicitAccess : public EXPLICIT_ACCESS {
ExplicitAccess(const TCHAR* name,
TRUSTEE_FORM type,
DWORD perms,
ACCESS_MODE mode,
DWORD inherit=0);
};
// Helper class for building access control lists
struct AccessEntries {
AccessEntries();
~AccessEntries();
void allocMinEntries(int count);
void addEntry(const TCHAR* trusteeName,
DWORD permissions,
ACCESS_MODE mode);
void addEntry(const PSID sid,
DWORD permissions,
ACCESS_MODE mode);
EXPLICIT_ACCESS* entries;
int entry_count;
};
// Helper class for handling SIDs
struct Sid : rdr::U8Array {
Sid() {}
operator PSID() const {return (PSID)buf;}
PSID takePSID() {PSID r = (PSID)buf; buf = 0; return r;}
static PSID copySID(const PSID sid);
void setSID(const PSID sid);
void getUserNameAndDomain(TCHAR** name, TCHAR** domain);
struct Administrators;
struct SYSTEM;
struct FromToken;
private:
Sid(const Sid&);
Sid& operator=(const Sid&);
};
struct Sid::Administrators : public Sid {
Administrators();
};
struct Sid::SYSTEM : public Sid {
SYSTEM();
};
struct Sid::FromToken : public Sid {
FromToken(HANDLE h);
};
// Helper class for handling & freeing ACLs
struct AccessControlList : public LocalMem {
AccessControlList(int size) : LocalMem(size) {}
AccessControlList(PACL acl_=0) : LocalMem(acl_) {}
operator PACL() {return (PACL)ptr;}
};
// Create a new ACL based on supplied entries and, if supplied, existing ACL
PACL CreateACL(const AccessEntries& ae, PACL existing_acl=0);
// Helper class for memory-management of self-relative SecurityDescriptors
struct SecurityDescriptorPtr : LocalMem {
SecurityDescriptorPtr(int size) : LocalMem(size) {}
SecurityDescriptorPtr(PSECURITY_DESCRIPTOR sd_=0) : LocalMem(sd_) {}
PSECURITY_DESCRIPTOR takeSD() {return (PSECURITY_DESCRIPTOR)takePtr();}
};
// Create a new self-relative Security Descriptor, owned by SYSTEM/Administrators,
// with the supplied DACL and no SACL. The returned value can be assigned
// to a SecurityDescriptorPtr to be managed.
PSECURITY_DESCRIPTOR CreateSdWithDacl(const PACL dacl);
}
}
#endif

View File

@@ -0,0 +1,217 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <rdr/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/Security.h>
#include <rfb_win32/resource.h>
#include <rfb_win32/SecurityPage.h>
#include <list>
using namespace rdr;
using namespace rfb;
using namespace rfb::win32;
using namespace std;
static LogWriter vlog("AuthDialog");
/* XXX: This class contains bunch of similar code to unix/vncviewer/CConn.cxx */
SecurityPage::SecurityPage(Security *security_)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_SECURITY)),
security(security_) {
}
void
SecurityPage::initDialog()
{
list<U8> secTypes;
list<U8>::iterator i;
if (isItemChecked(IDC_ENC_X509))
enableX509Dialogs();
else
disableX509Dialogs();
secTypes = security->GetEnabledSecTypes();
/* Process non-VeNCrypt sectypes */
for (i = secTypes.begin(); i != secTypes.end(); i++) {
switch (*i) {
case secTypeNone:
enableAuthMethod(IDC_ENC_NONE, IDC_AUTH_NONE);
break;
case secTypeVncAuth:
enableAuthMethod(IDC_ENC_NONE, IDC_AUTH_VNC);
break;
}
}
list<U32> secTypesExt;
list<U32>::iterator iext;
secTypesExt = security->GetEnabledExtSecTypes();
/* Process VeNCrypt subtypes */
for (iext = secTypesExt.begin(); iext != secTypesExt.end(); iext++) {
switch (*iext) {
case secTypePlain:
enableAuthMethod(IDC_ENC_NONE, IDC_AUTH_PLAIN);
break;
case secTypeTLSNone:
enableAuthMethod(IDC_ENC_TLS, IDC_AUTH_NONE);
break;
case secTypeTLSVnc:
enableAuthMethod(IDC_ENC_TLS, IDC_AUTH_VNC);
break;
case secTypeTLSPlain:
enableAuthMethod(IDC_ENC_TLS, IDC_AUTH_PLAIN);
break;
case secTypeX509None:
enableAuthMethod(IDC_ENC_X509, IDC_AUTH_NONE);
enableX509Dialogs();
break;
case secTypeX509Vnc:
enableAuthMethod(IDC_ENC_X509, IDC_AUTH_VNC);
enableX509Dialogs();
break;
case secTypeX509Plain:
enableAuthMethod(IDC_ENC_X509, IDC_AUTH_PLAIN);
enableX509Dialogs();
break;
}
}
}
bool
SecurityPage::onCommand(int id, int cmd)
{
if (id == IDC_ENC_X509) {
if (isItemChecked(IDC_ENC_X509))
enableX509Dialogs();
else
disableX509Dialogs();
}
return true;
}
bool
SecurityPage::onOk() {
#ifdef HAVE_GNUTLS
bool x509_loaded = false;
#endif
bool vnc_loaded = false;
list<U32> secTypes;
/* Keep same priorities as in common/rfb/SecurityClient::secTypes */
secTypes.push_back(secTypeVeNCrypt);
#ifdef HAVE_GNUTLS
/* X509Plain */
if (authMethodEnabled(IDC_ENC_X509, IDC_AUTH_PLAIN)) {
loadX509Certs(x509_loaded);
secTypes.push_back(secTypeX509Plain);
}
/* TLSPlain */
if (authMethodEnabled(IDC_ENC_TLS, IDC_AUTH_PLAIN))
secTypes.push_back(secTypeTLSPlain);
/* X509Vnc */
if (authMethodEnabled(IDC_ENC_X509, IDC_AUTH_VNC)) {
loadX509Certs(x509_loaded);
loadVncPasswd(vnc_loaded);
secTypes.push_back(secTypeX509Vnc);
}
/* TLSVnc */
if (authMethodEnabled(IDC_ENC_TLS, IDC_AUTH_VNC)) {
loadVncPasswd(vnc_loaded);
secTypes.push_back(secTypeTLSVnc);
}
/* X509None */
if (authMethodEnabled(IDC_ENC_X509, IDC_AUTH_NONE)) {
loadX509Certs(x509_loaded);
secTypes.push_back(secTypeX509None);
}
/* TLSNone */
if (authMethodEnabled(IDC_ENC_TLS, IDC_AUTH_NONE))
secTypes.push_back(secTypeTLSNone);
#endif
/* VncAuth */
if (authMethodEnabled(IDC_ENC_NONE, IDC_AUTH_VNC)) {
loadVncPasswd(vnc_loaded);
secTypes.push_back(secTypeVncAuth);
}
/* None */
if (authMethodEnabled(IDC_ENC_NONE, IDC_AUTH_NONE))
secTypes.push_back(secTypeNone);
security->SetSecTypes(secTypes);
return true;
}
inline void
SecurityPage::disableFeature(int id)
{
enableItem(id, false);
setItemChecked(id, false);
}
inline void
SecurityPage::enableAuthMethod(int encid, int authid)
{
setItemChecked(encid, true);
setItemChecked(authid, true);
}
inline bool
SecurityPage::authMethodEnabled(int encid, int authid)
{
return isItemChecked(encid) && isItemChecked(authid);
}
inline void
SecurityPage::loadX509Certs(bool &loaded)
{
if (!loaded)
loadX509Certs();
loaded = true;
}
inline void
SecurityPage::loadVncPasswd(bool &loaded)
{
if (!loaded)
loadVncPasswd();
loaded = true;
}

View File

@@ -0,0 +1,62 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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_SECURITYPAGE_H__
#define __RFB_WIN32_SECURITYPAGE_H__
#include <rdr/types.h>
#include <rfb/Security.h>
#include <rfb_win32/Dialog.h>
#include <list>
namespace rfb {
namespace win32 {
class SecurityPage: public PropSheetPage
{
public:
SecurityPage(Security *security_);
virtual void loadX509Certs(void) = 0;
virtual void enableX509Dialogs(void) = 0;
virtual void disableX509Dialogs(void) = 0;
virtual void loadVncPasswd(void) = 0;
virtual void initDialog();
virtual bool onCommand(int id, int cmd);
virtual bool onOk();
protected:
Security *security;
private:
inline void enableVeNCryptFeatures(bool enable);
inline void disableFeature(int id);
inline void enableAuthMethod(int encid, int authid);
inline bool authMethodEnabled(int encid, int authid);
inline void loadX509Certs(bool &loaded);
inline void loadVncPasswd(bool &loaded);
};
};
};
#endif

476
win/rfb_win32/Service.cxx Normal file
View File

@@ -0,0 +1,476 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Service.cxx
#include <rfb_win32/Service.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Registry.h>
#include <rfb_win32/Handle.h>
#include <logmessages/messages.h>
#include <rdr/Exception.h>
#include <rfb/LogWriter.h>
using namespace rdr;
using namespace rfb;
using namespace win32;
static LogWriter vlog("Service");
// - Internal service implementation functions
Service* service = 0;
bool runAsService = false;
VOID WINAPI serviceHandler(DWORD control) {
switch (control) {
case SERVICE_CONTROL_INTERROGATE:
vlog.info("cmd: report status");
service->setStatus();
return;
case SERVICE_CONTROL_PARAMCHANGE:
vlog.info("cmd: param change");
service->readParams();
return;
case SERVICE_CONTROL_SHUTDOWN:
vlog.info("cmd: OS shutdown");
service->osShuttingDown();
return;
case SERVICE_CONTROL_STOP:
vlog.info("cmd: stop");
service->setStatus(SERVICE_STOP_PENDING);
service->stop();
return;
};
vlog.debug("cmd: unknown %lu", control);
}
// -=- Service main procedure
VOID WINAPI serviceProc(DWORD dwArgc, LPTSTR* lpszArgv) {
vlog.debug("entering %s serviceProc", service->getName());
vlog.info("registering handler...");
service->status_handle = RegisterServiceCtrlHandler(service->getName(), serviceHandler);
if (!service->status_handle) {
DWORD err = GetLastError();
vlog.error("failed to register handler: %lu", err);
ExitProcess(err);
}
vlog.debug("registered handler (%p)", service->status_handle);
service->setStatus(SERVICE_START_PENDING);
vlog.debug("entering %s serviceMain", service->getName());
service->status.dwWin32ExitCode = service->serviceMain(dwArgc, lpszArgv);
vlog.debug("leaving %s serviceMain", service->getName());
service->setStatus(SERVICE_STOPPED);
}
// -=- Service
Service::Service(const TCHAR* name_) : name(name_) {
vlog.debug("Service");
status_handle = 0;
status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
status.dwWin32ExitCode = NO_ERROR;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 30000;
status.dwCurrentState = SERVICE_STOPPED;
}
void
Service::start() {
SERVICE_TABLE_ENTRY entry[2];
entry[0].lpServiceName = (TCHAR*)name;
entry[0].lpServiceProc = serviceProc;
entry[1].lpServiceName = NULL;
entry[1].lpServiceProc = NULL;
vlog.debug("entering dispatcher");
if (!SetProcessShutdownParameters(0x100, 0))
vlog.error("unable to set shutdown parameters: %lu", GetLastError());
service = this;
if (!StartServiceCtrlDispatcher(entry))
throw SystemException("unable to start service", GetLastError());
}
void
Service::setStatus() {
setStatus(status.dwCurrentState);
}
void
Service::setStatus(DWORD state) {
if (status_handle == 0) {
vlog.debug("warning - cannot setStatus");
return;
}
status.dwCurrentState = state;
status.dwCheckPoint++;
if (!SetServiceStatus(status_handle, &status)) {
status.dwCurrentState = SERVICE_STOPPED;
status.dwWin32ExitCode = GetLastError();
vlog.error("unable to set service status:%lu", status.dwWin32ExitCode);
}
vlog.debug("set status to %lu(%lu)", state, status.dwCheckPoint);
}
Service::~Service() {
vlog.debug("~Service");
service = 0;
}
// Find out whether this process is running as the WinVNC service
bool thisIsService() {
return service && (service->status.dwCurrentState != SERVICE_STOPPED);
}
// -=- Desktop handling code
// Switch the current thread to the specified desktop
static bool
switchToDesktop(HDESK desktop) {
HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
if (!SetThreadDesktop(desktop)) {
vlog.debug("switchToDesktop failed:%lu", GetLastError());
return false;
}
if (!CloseDesktop(old_desktop))
vlog.debug("unable to close old desktop:%lu", GetLastError());
return true;
}
// Determine whether the thread's current desktop is the input one
static bool
inputDesktopSelected() {
HDESK current = GetThreadDesktop(GetCurrentThreadId());
HDESK input = OpenInputDesktop(0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
if (!input) {
vlog.debug("unable to OpenInputDesktop(1):%lu", GetLastError());
return false;
}
DWORD size;
char currentname[256];
char inputname[256];
if (!GetUserObjectInformation(current, UOI_NAME, currentname, 256, &size)) {
vlog.debug("unable to GetUserObjectInformation(1):%lu", GetLastError());
CloseDesktop(input);
return false;
}
if (!GetUserObjectInformation(input, UOI_NAME, inputname, 256, &size)) {
vlog.debug("unable to GetUserObjectInformation(2):%lu", GetLastError());
CloseDesktop(input);
return false;
}
if (!CloseDesktop(input))
vlog.debug("unable to close input desktop:%lu", GetLastError());
// *** vlog.debug("current=%s, input=%s", currentname, inputname);
bool result = strcmp(currentname, inputname) == 0;
return result;
}
// Switch the current thread into the input desktop
static bool
selectInputDesktop() {
// - Open the input desktop
HDESK desktop = OpenInputDesktop(0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
if (!desktop) {
vlog.debug("unable to OpenInputDesktop(2):%lu", GetLastError());
return false;
}
// - Switch into it
if (!switchToDesktop(desktop)) {
CloseDesktop(desktop);
return false;
}
// ***
DWORD size = 256;
char currentname[256];
if (GetUserObjectInformation(desktop, UOI_NAME, currentname, 256, &size)) {
vlog.debug("switched to %s", currentname);
}
// ***
vlog.debug("switched to input desktop");
return true;
}
// -=- Access points to desktop-switching routines
bool
rfb::win32::desktopChangeRequired() {
return !inputDesktopSelected();
}
bool
rfb::win32::changeDesktop() {
return selectInputDesktop();
}
// -=- Ctrl-Alt-Del emulation
bool
rfb::win32::emulateCtrlAltDel() {
rfb::win32::Handle sessionEventCad =
CreateEvent(0, FALSE, FALSE, "Global\\SessionEventKasmVNCCad");
SetEvent(sessionEventCad);
return true;
}
// -=- Application Event Log target Logger class
class Logger_EventLog : public Logger {
public:
Logger_EventLog(const TCHAR* srcname) : Logger("EventLog") {
eventlog = RegisterEventSource(NULL, srcname);
if (!eventlog)
printf("Unable to open event log:%ld\n", GetLastError());
}
~Logger_EventLog() {
if (eventlog)
DeregisterEventSource(eventlog);
}
virtual void write(int level, const char *logname, const char *message) {
if (!eventlog) return;
TStr log(logname), msg(message);
const TCHAR* strings[] = {log, msg};
WORD type = EVENTLOG_INFORMATION_TYPE;
if (level == 0) type = EVENTLOG_ERROR_TYPE;
if (!ReportEvent(eventlog, type, 0, VNC4LogMessage, NULL, 2, 0, strings, NULL)) {
// *** It's not at all clear what is the correct behaviour if this fails...
printf("ReportEvent failed:%ld\n", GetLastError());
}
}
protected:
HANDLE eventlog;
};
static Logger_EventLog* logger = 0;
bool rfb::win32::initEventLogLogger(const TCHAR* srcname) {
if (logger)
return false;
logger = new Logger_EventLog(srcname);
logger->registerLogger();
return true;
}
// -=- Registering and unregistering the service
bool rfb::win32::registerService(const TCHAR* name,
const TCHAR* display,
const TCHAR* desc,
int argc, char** argv) {
// - Initialise the default service parameters
const TCHAR* defaultcmdline;
defaultcmdline = _T("-service");
// - Get the full pathname of our executable
ModuleFileName buffer;
// - Calculate the command-line length
int cmdline_len = _tcslen(buffer.buf) + 4;
int i;
for (i=0; i<argc; i++) {
cmdline_len += strlen(argv[i]) + 3;
}
// - Add the supplied extra parameters to the command line
TCharArray cmdline(cmdline_len+_tcslen(defaultcmdline));
_stprintf(cmdline.buf, _T("\"%s\" %s"), buffer.buf, defaultcmdline);
for (i=0; i<argc; i++) {
_tcscat(cmdline.buf, _T(" \""));
_tcscat(cmdline.buf, TStr(argv[i]));
_tcscat(cmdline.buf, _T("\""));
}
// - Register the service
// - Open the SCM
ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!scm)
throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
// - Add the service
ServiceHandle service = CreateService(scm,
name, display, SC_MANAGER_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
cmdline.buf, NULL, NULL, NULL, NULL, NULL);
if (!service)
throw rdr::SystemException("unable to create service", GetLastError());
// - Set a description
SERVICE_DESCRIPTION sdesc = {(LPTSTR)desc};
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sdesc);
// - Register the event log source
RegKey hk, hk2;
hk2.createKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
hk.createKey(hk2, name);
for (i=_tcslen(buffer.buf); i>0; i--) {
if (buffer.buf[i] == _T('\\')) {
buffer.buf[i+1] = 0;
break;
}
}
const TCHAR* dllFilename = _T("logmessages.dll");
TCharArray dllPath(_tcslen(buffer.buf) + _tcslen(dllFilename) + 1);
_tcscpy(dllPath.buf, buffer.buf);
_tcscat(dllPath.buf, dllFilename);
hk.setExpandString(_T("EventMessageFile"), dllPath.buf);
hk.setInt(_T("TypesSupported"), EVENTLOG_ERROR_TYPE | EVENTLOG_INFORMATION_TYPE);
Sleep(500);
return true;
}
bool rfb::win32::unregisterService(const TCHAR* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!scm)
throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
// - Create the service
ServiceHandle service = OpenService(scm, name, SC_MANAGER_ALL_ACCESS);
if (!service)
throw rdr::SystemException("unable to locate the service", GetLastError());
if (!DeleteService(service))
throw rdr::SystemException("unable to remove the service", GetLastError());
// - Register the event log source
RegKey hk;
hk.openKey(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"));
hk.deleteKey(name);
Sleep(500);
return true;
}
// -=- Starting and stopping the service
bool rfb::win32::startService(const TCHAR* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!scm)
throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
// - Locate the service
ServiceHandle service = OpenService(scm, name, SERVICE_START);
if (!service)
throw rdr::SystemException("unable to open the service", GetLastError());
// - Start the service
if (!StartService(service, 0, NULL))
throw rdr::SystemException("unable to start the service", GetLastError());
Sleep(500);
return true;
}
bool rfb::win32::stopService(const TCHAR* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!scm)
throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
// - Locate the service
ServiceHandle service = OpenService(scm, name, SERVICE_STOP);
if (!service)
throw rdr::SystemException("unable to open the service", GetLastError());
// - Start the service
SERVICE_STATUS status;
if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
throw rdr::SystemException("unable to stop the service", GetLastError());
Sleep(500);
return true;
}
DWORD rfb::win32::getServiceState(const TCHAR* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!scm)
throw rdr::SystemException("unable to open Service Control Manager", GetLastError());
// - Locate the service
ServiceHandle service = OpenService(scm, name, SERVICE_INTERROGATE);
if (!service)
throw rdr::SystemException("unable to open the service", GetLastError());
// - Get the service status
SERVICE_STATUS status;
if (!ControlService(service, SERVICE_CONTROL_INTERROGATE, (SERVICE_STATUS*)&status))
throw rdr::SystemException("unable to query the service", GetLastError());
return status.dwCurrentState;
}
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 runAsService;
}

123
win/rfb_win32/Service.h Normal file
View File

@@ -0,0 +1,123 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Service.h
//
// Win32 service-mode code.
// Derive your service from this code and let it handle the annoying Win32
// service API.
#ifndef __RFB_WIN32_SERVICE_H__
#define __RFB_WIN32_SERVICE_H__
#include <windows.h>
namespace rfb {
namespace win32 {
//
// -=- Service
//
// Application base-class for services.
class Service {
public:
Service(const TCHAR* name_);
virtual ~Service();
const TCHAR* getName() {return name;}
SERVICE_STATUS& getStatus() {return status;}
void setStatus(DWORD status);
void setStatus();
// - Start the service, having initialised it
void start();
// - Service main procedure - override to implement a service
virtual DWORD serviceMain(int argc, TCHAR* argv[]) = 0;
// - Service control notifications
// To get notified when the OS is shutting down
virtual void osShuttingDown() {};
// To get notified when the service parameters change
virtual void readParams() {};
// To cause the serviceMain() routine to return
virtual void stop() {};
public:
SERVICE_STATUS_HANDLE status_handle;
SERVICE_STATUS status;
protected:
const TCHAR* name;
};
class ServiceHandle {
public:
ServiceHandle(SC_HANDLE h) : handle(h) {}
~ServiceHandle() {CloseServiceHandle(handle);}
operator SC_HANDLE() const {return handle;}
protected:
SC_HANDLE handle;
};
// -=- Routines used by desktop back-end code to manage desktops/window stations
bool desktopChangeRequired();
bool changeDesktop();
// -=- Routines used by the SInput Keyboard class to emulate Ctrl-Alt-Del
bool emulateCtrlAltDel();
// -=- Routines to initialise the Event Log target Logger
bool initEventLogLogger(const TCHAR* srcname);
// -=- Routines to register/unregister the service
// These routines also take care of registering the required
// event source information, etc.
// *** should really accept TCHAR argv
bool registerService(const TCHAR* name, const TCHAR* display,
const TCHAR* desc, int argc, char** argv);
bool unregisterService(const TCHAR* name);
bool startService(const TCHAR* name);
bool stopService(const TCHAR* name);
// -=- Get the state of the named service (one of the NT service state values)
DWORD getServiceState(const TCHAR* name);
// -=- Convert a supplied service state value to a printable string e.g. Running, Stopped...
// The caller must delete the returned string buffer
char* serviceStateName(DWORD state);
// -=- Routine to determine whether the host process is running a service
bool isServiceProcess();
};
};
#endif // __RFB_WIN32_SERVICE_NT_H__

View File

@@ -0,0 +1,211 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- SocketManager.cxx
#include <winsock2.h>
#include <list>
#include <rfb/LogWriter.h>
#include <rfb_win32/SocketManager.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("SocketManager");
// -=- SocketManager
SocketManager::SocketManager() {
}
SocketManager::~SocketManager() {
}
static void 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: 0x%08x", (unsigned)err);
}
}
void SocketManager::addListener(network::SocketListener* sock_,
network::SocketServer* srvr,
AddressChangeNotifier* acn) {
WSAEVENT event = WSACreateEvent();
long flags = FD_ACCEPT | FD_CLOSE;
if (acn)
flags |= FD_ADDRESS_LIST_CHANGE;
try {
if (event && (WSAEventSelect(sock_->getFd(), event, flags) == SOCKET_ERROR))
throw rdr::SystemException("Unable to select on listener", WSAGetLastError());
// requestAddressChangeEvents MUST happen after WSAEventSelect, so that the socket is non-blocking
if (acn)
requestAddressChangeEvents(sock_);
// addEvent is the last thing we do, so that the event is NOT registered if previous steps fail
if (!event || !addEvent(event, this))
throw rdr::Exception("Unable to add listener");
} catch (rdr::Exception& e) {
if (event)
WSACloseEvent(event);
delete sock_;
vlog.error("%s", e.str());
throw;
}
ListenInfo li;
li.sock = sock_;
li.server = srvr;
li.notifier = acn;
listeners[event] = li;
}
void SocketManager::remListener(network::SocketListener* sock) {
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++) {
if (i->second.sock == sock) {
removeEvent(i->first);
WSACloseEvent(i->first);
delete sock;
listeners.erase(i);
return;
}
}
throw rdr::Exception("Listener not registered");
}
void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
WSAEVENT event = WSACreateEvent();
if (!event || !addEvent(event, this) ||
(WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
if (event)
WSACloseEvent(event);
delete sock_;
vlog.error("Unable to add connection");
return;
}
ConnInfo ci;
ci.sock = sock_;
ci.server = srvr;
connections[event] = ci;
srvr->addSocket(sock_, outgoing);
}
void SocketManager::remSocket(network::Socket* sock_) {
std::map<HANDLE,ConnInfo>::iterator i;
for (i=connections.begin(); i!=connections.end(); i++) {
if (i->second.sock == sock_) {
i->second.server->removeSocket(sock_);
removeEvent(i->first);
WSACloseEvent(i->first);
delete sock_;
connections.erase(i);
return;
}
}
throw rdr::Exception("Socket not registered");
}
int SocketManager::checkTimeouts() {
int timeout = EventManager::checkTimeouts();
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++)
soonestTimeout(&timeout, i->second.server->checkTimeouts());
std::list<network::Socket*> shutdownSocks;
std::map<HANDLE,ConnInfo>::iterator j, j_next;
for (j=connections.begin(); j!=connections.end(); j=j_next) {
j_next = j; j_next++;
if (j->second.sock->isShutdown())
shutdownSocks.push_back(j->second.sock);
}
std::list<network::Socket*>::iterator k;
for (k=shutdownSocks.begin(); k!=shutdownSocks.end(); k++)
remSocket(*k);
return timeout;
}
void SocketManager::processEvent(HANDLE event) {
if (listeners.count(event)) {
ListenInfo li = listeners[event];
// Accept an incoming connection
vlog.debug("accepting incoming connection");
// What kind of event is this?
WSANETWORKEVENTS network_events;
WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
if (network_events.lNetworkEvents & FD_ACCEPT) {
network::Socket* new_sock = li.sock->accept();
if (new_sock && li.server->getDisable()) {
delete new_sock;
new_sock = 0;
}
if (new_sock)
addSocket(new_sock, li.server, false);
} else if (network_events.lNetworkEvents & FD_CLOSE) {
vlog.info("deleting listening socket");
remListener(li.sock);
} else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
li.notifier->processAddressChange();
requestAddressChangeEvents(li.sock);
} else {
vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
}
} else if (connections.count(event)) {
ConnInfo ci = connections[event];
try {
// Process data from an active connection
// Cancel event notification for this socket
if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
throw rdr::SystemException("unable to disable WSAEventSelect:%u", WSAGetLastError());
// Reset the event object
WSAResetEvent(event);
// Call the socket server to process the event
ci.server->processSocketReadEvent(ci.sock);
if (ci.sock->isShutdown()) {
remSocket(ci.sock);
return;
}
// Re-instate the required socket event
// If the read event is still valid, the event object gets set here
if (WSAEventSelect(ci.sock->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
throw rdr::SystemException("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
remSocket(ci.sock);
}
}
}

View File

@@ -0,0 +1,90 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- SocketManager.h
// Socket manager class for Win32.
// Passed a network::SocketListener and a network::SocketServer when
// constructed. Uses WSAAsyncSelect to get notifications of network
// connection attempts. When an incoming connection is received,
// the manager will call network::SocketServer::addClient(). If
// addClient returns true then the manager registers interest in
// network events on that socket, and calls
// network::SocketServer::processSocketEvent().
#ifndef __RFB_WIN32_SOCKET_MGR_H__
#define __RFB_WIN32_SOCKET_MGR_H__
#include <map>
#include <network/Socket.h>
#include <rfb_win32/EventManager.h>
namespace rfb {
namespace win32 {
class SocketManager : public EventManager, EventHandler {
public:
SocketManager();
virtual ~SocketManager();
// AddressChangeNotifier callback interface
// If an object implementing this is passed to addListener then it will be
// called whenever the SocketListener's address list changes
class AddressChangeNotifier {
public:
virtual ~AddressChangeNotifier() {}
virtual void processAddressChange() = 0;
};
// Add a listening socket. Incoming connections will be added to the supplied
// SocketServer.
void addListener(network::SocketListener* sock_,
network::SocketServer* srvr,
AddressChangeNotifier* acn = 0);
// Remove and delete a listening socket.
void remListener(network::SocketListener* sock);
// Add an already-connected socket. Socket events will cause the supplied
// SocketServer to be called. The socket must ALREADY BE REGISTERED with
// the SocketServer.
void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);
protected:
virtual int checkTimeouts();
virtual void processEvent(HANDLE event);
virtual void remSocket(network::Socket* sock);
struct ConnInfo {
network::Socket* sock;
network::SocketServer* server;
};
struct ListenInfo {
network::SocketListener* sock;
network::SocketServer* server;
AddressChangeNotifier* notifier;
};
std::map<HANDLE, ListenInfo> listeners;
std::map<HANDLE, ConnInfo> connections;
};
}
}
#endif

View File

@@ -0,0 +1,85 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rfb_win32/TCharArray.h>
namespace rfb {
WCHAR* wstrDup(const WCHAR* s) {
if (!s) return 0;
WCHAR* t = new WCHAR[wcslen(s)+1];
memcpy(t, s, sizeof(WCHAR)*(wcslen(s)+1));
return t;
}
void wstrFree(WCHAR* s) {delete [] s;}
char* strDup(const WCHAR* s) {
if (!s) return 0;
int len = wcslen(s);
char* t = new char[len+1];
t[WideCharToMultiByte(CP_ACP, 0, s, len, t, len, 0, 0)] = 0;
return t;
}
WCHAR* wstrDup(const char* s) {
if (!s) return 0;
int len = strlen(s);
WCHAR* t = new WCHAR[len+1];
t[MultiByteToWideChar(CP_ACP, 0, s, len, t, len)] = 0;
return t;
}
bool wstrSplit(const WCHAR* src, const WCHAR limiter, WCHAR** out1, WCHAR** out2, bool fromEnd) {
WCharArray out1old, out2old;
if (out1) out1old.buf = *out1;
if (out2) out2old.buf = *out2;
int len = wcslen(src);
int i=0, increment=1, limit=len;
if (fromEnd) {
i=len-1; increment = -1; limit = -1;
}
while (i!=limit) {
if (src[i] == limiter) {
if (out1) {
*out1 = new WCHAR[i+1];
if (i) memcpy(*out1, src, sizeof(WCHAR)*i);
(*out1)[i] = 0;
}
if (out2) {
*out2 = new WCHAR[len-i];
if (len-i-1) memcpy(*out2, &src[i+1], sizeof(WCHAR)*(len-i-1));
(*out2)[len-i-1] = 0;
}
return true;
}
i+=increment;
}
if (out1) *out1 = wstrDup(src);
if (out2) *out2 = 0;
return false;
}
bool wstrContains(const WCHAR* src, WCHAR c) {
int l=wcslen(src);
for (int i=0; i<l; i++)
if (src[i] == c) return true;
return false;
}
};

135
win/rfb_win32/TCharArray.h Normal file
View File

@@ -0,0 +1,135 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- TCharArray.h
// This library contains the wide-character equivalent of CharArray, named
// WCharArray. In addition to providing wide-character equivalents of
// the char* string manipulation functions (strDup, strFree, etc), special
// versions of those functions are provided which attempt to convert from
// one format to the other.
// e.g. char* t = "hello world"; WCHAR* w = wstrDup(t);
// Results in w containing the wide-character text "hello world".
// For convenience, the WStr and CStr classes are also provided. These
// accept an existing (const) WCHAR* or char* null-terminated string and
// create a read-only copy of that in the desired format. The new copy
// will actually be the original copy if the format has not changed, otherwise
// it will be a new buffer owned by the WStr/CStr.
// In addition to providing wide character functions, this header defines
// TCHAR* handling classes & functions. TCHAR is defined at compile time to
// either char or WCHAR. Programs can treat this as a third data type and
// call TStr() whenever a TCHAR* is required but a char* or WCHAR* is supplied,
// and TStr will do the right thing.
#ifndef __RFB_WIN32_TCHARARRAY_H__
#define __RFB_WIN32_TCHARARRAY_H__
#include <windows.h>
#include <tchar.h>
#include <rfb/util.h>
#include <rfb/Password.h>
namespace rfb {
// -=- String duplication and cleanup functions.
// These routines also handle conversion between WCHAR* and char*
char* strDup(const WCHAR* s);
WCHAR* wstrDup(const WCHAR* s);
WCHAR* wstrDup(const char* s);
void wstrFree(WCHAR* s);
bool wstrSplit(const WCHAR* src, const WCHAR limiter, WCHAR** out1, WCHAR** out2, bool fromEnd=false);
bool wstrContains(const WCHAR* src, WCHAR c);
// -=- Temporary format conversion classes
// CStr accepts WCHAR* or char* and behaves like a char*
// WStr accepts WCHAR* or char* and behaves like a WCHAR*
struct WStr {
WStr(const char* s) : buf(wstrDup(s)), free_(true) {}
WStr(const WCHAR* s) : buf(s), free_(false) {}
~WStr() {if (free_) wstrFree((WCHAR*)buf);}
operator const WCHAR*() {return buf;}
const WCHAR* buf;
bool free_;
};
struct CStr {
CStr(const char* s) : buf(s), free_(false) {}
CStr(const WCHAR* s) : buf(strDup(s)), free_(true) {}
~CStr() {if (free_) strFree((char*)buf);}
operator const char*() {return buf;}
const char* buf;
bool free_;
};
// -=- Class to handle cleanup of arrays of native Win32 characters
class WCharArray {
public:
WCharArray() : buf(0) {}
WCharArray(char* str) : buf(wstrDup(str)) {strFree(str);} // note: assumes ownership
WCharArray(WCHAR* str) : buf(str) {} // note: assumes ownership
WCharArray(int len) {
buf = new WCHAR[len];
}
~WCharArray() {
delete [] buf;
}
// Get the buffer pointer & clear it (i.e. caller takes ownership)
WCHAR* takeBuf() {WCHAR* tmp = buf; buf = 0; return tmp;}
void replaceBuf(WCHAR* str) {delete [] buf; buf = str;}
WCHAR* buf;
};
// -=- Wide-character-based password-buffer handler. Zeroes the password
// buffer when deleted or replaced.
class WPlainPasswd : public WCharArray {
public:
WPlainPasswd() {}
WPlainPasswd(WCHAR* str) : WCharArray(str) {}
~WPlainPasswd() {replaceBuf(0);}
void replaceBuf(WCHAR* str) {
if (buf)
memset(buf, 0, sizeof(WCHAR)*wcslen(buf));
WCharArray::replaceBuf(str);
}
};
#ifdef _UNICODE
#define tstrDup wstrDup
#define tstrFree wstrFree
#define tstrSplit wstrSplit
#define tstrContains wstrContains
typedef WCharArray TCharArray;
typedef WStr TStr;
typedef WPlainPasswd TPlainPasswd;
#else
#define tstrDup strDup
#define tstrFree strFree
#define tstrSplit strSplit
#define tstrContains strContains
typedef CharArray TCharArray;
typedef CStr TStr;
typedef PlainPasswd TPlainPasswd;
#endif
};
#endif

89
win/rfb_win32/TrayIcon.h Normal file
View File

@@ -0,0 +1,89 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- CView.h
// An instance of the CView class is created for each VNC Viewer connection.
#ifndef __RFB_WIN32_TRAY_ICON_H__
#define __RFB_WIN32_TRAY_ICON_H__
#include <windows.h>
#include <shellapi.h>
#include <rfb_win32/MsgWindow.h>
#include <rdr/Exception.h>
namespace rfb {
namespace win32 {
class TrayIcon : public MsgWindow {
public:
TrayIcon() : MsgWindow(_T("VNCTray")) {
#ifdef NOTIFYICONDATA_V1_SIZE
nid.cbSize = NOTIFYICONDATA_V1_SIZE;
#else
nid.cbSize = sizeof(NOTIFYICONDATA);
#endif
nid.hWnd = getHandle();
nid.uID = 0;
nid.hIcon = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE;
nid.uCallbackMessage = WM_USER;
}
virtual ~TrayIcon() {
remove();
}
bool setIcon(UINT icon) {
if (icon == 0) {
return remove();
} else {
nid.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(icon),
IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
return refresh();
}
}
bool setToolTip(const TCHAR* text) {
if (text == 0) {
nid.uFlags &= ~NIF_TIP;
} else {
const int tipLen = sizeof(nid.szTip)/sizeof(TCHAR);
_tcsncpy(nid.szTip, text, tipLen);
nid.szTip[tipLen-1] = 0;
nid.uFlags |= NIF_TIP;
}
return refresh();
}
bool remove() {
return Shell_NotifyIcon(NIM_DELETE, &nid) != 0;
}
bool refresh() {
return Shell_NotifyIcon(NIM_MODIFY, &nid) || Shell_NotifyIcon(NIM_ADD, &nid);
}
protected:
NOTIFYICONDATA nid;
};
};
};
#endif

View File

@@ -0,0 +1,64 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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/LogWriter.h>
#include <rdr/Exception.h>
#include <tchar.h>
#include <wtsapi32.h>
static rfb::LogWriter vlog("TsSessions");
namespace rfb {
namespace win32 {
ProcessSessionId::ProcessSessionId(DWORD processId) {
id = 0;
if (processId == (DWORD)-1)
processId = GetCurrentProcessId();
if (!ProcessIdToSessionId(GetCurrentProcessId(), &id))
throw rdr::SystemException("ProcessIdToSessionId", GetLastError());
}
ProcessSessionId mySessionId;
ConsoleSessionId::ConsoleSessionId() {
id = WTSGetActiveConsoleSessionId();
}
bool inConsoleSession() {
ConsoleSessionId console;
return console.id == mySessionId.id;
}
void setConsoleSession(DWORD sessionId) {
if (sessionId == (DWORD)-1)
sessionId = mySessionId.id;
// Try to reconnect our session to the console
ConsoleSessionId console;
vlog.info("Console session is %lu", console.id);
if (!WTSConnectSession(sessionId, console.id, (PTSTR)_T(""), 0))
throw rdr::SystemException("Unable to connect session to Console", GetLastError());
// Lock the newly connected session, for security
LockWorkStation();
}
};
};

View File

@@ -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

View File

@@ -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.
*/
// -=- WMCursor.cxx
#include <rfb_win32/WMCursor.h>
#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
using namespace rdr;
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("WMCursor");
WMCursor::WMCursor() : cursor(0) {
cursor = (HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
}
WMCursor::~WMCursor() {
}
WMCursor::Info
WMCursor::getCursorInfo() {
Info result;
CURSORINFO info;
info.cbSize = sizeof(CURSORINFO);
if (!GetCursorInfo(&info))
throw rdr::SystemException("GetCursorInfo failed", GetLastError());
result.cursor = info.hCursor;
result.position = Point(info.ptScreenPos.x, info.ptScreenPos.y);
result.visible = info.flags & CURSOR_SHOWING;
return result;
}

59
win/rfb_win32/WMCursor.h Normal file
View File

@@ -0,0 +1,59 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMCursor.h
// WMCursor provides a single API through which the cursor state can be obtained
// The underlying implementation will use either GetCursorInfo, or use the
// wm_hooks library if GetCursorInfo is not available.
#ifndef __RFB_WIN32_WM_CURSOR_H__
#define __RFB_WIN32_WM_CURSOR_H__
#include <windows.h>
#include <rfb_win32/WMHooks.h>
namespace rfb {
namespace win32 {
class WMCursor {
public:
WMCursor();
~WMCursor();
struct Info {
HCURSOR cursor;
Point position;
bool visible;
Info() : cursor(0), visible(false) {}
bool operator!=(const Info& info) {
return ((cursor != info.cursor) ||
(!position.equals(info.position)) ||
(visible != info.visible));
}
};
Info getCursorInfo();
protected:
HCURSOR cursor;
};
};
};
#endif // __RFB_WIN32_WM_CURSOR_H__

386
win/rfb_win32/WMHooks.cxx Normal file
View File

@@ -0,0 +1,386 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMHooks.cxx
#include <os/Mutex.h>
#include <os/Thread.h>
#include <rfb_win32/WMHooks.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/IntervalTimer.h>
#include <rfb/LogWriter.h>
#include <list>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("WMHooks");
static HMODULE hooksLibrary;
typedef UINT (*WM_Hooks_WMVAL_proto)();
static WM_Hooks_WMVAL_proto WM_Hooks_WindowChanged;
static WM_Hooks_WMVAL_proto WM_Hooks_WindowBorderChanged;
static WM_Hooks_WMVAL_proto WM_Hooks_WindowClientAreaChanged;
static WM_Hooks_WMVAL_proto WM_Hooks_RectangleChanged;
#ifdef _DEBUG
static WM_Hooks_WMVAL_proto WM_Hooks_Diagnostic;
#endif
typedef BOOL (*WM_Hooks_Install_proto)(DWORD owner, DWORD thread);
static WM_Hooks_Install_proto WM_Hooks_Install;
typedef BOOL (*WM_Hooks_Remove_proto)(DWORD owner);
static WM_Hooks_Remove_proto WM_Hooks_Remove;
#ifdef _DEBUG
typedef void (*WM_Hooks_SetDiagnosticRange_proto)(UINT min, UINT max);
static WM_Hooks_SetDiagnosticRange_proto WM_Hooks_SetDiagnosticRange;
#endif
typedef BOOL (*WM_Hooks_EnableRealInputs_proto)(BOOL pointer, BOOL keyboard);
static WM_Hooks_EnableRealInputs_proto WM_Hooks_EnableRealInputs;
static void LoadHooks()
{
if (hooksLibrary != NULL)
return;
hooksLibrary = LoadLibrary("wm_hooks.dll");
if (hooksLibrary == NULL)
return;
WM_Hooks_WindowChanged = (WM_Hooks_WMVAL_proto)GetProcAddress(hooksLibrary, "WM_Hooks_WindowChanged");
if (WM_Hooks_WindowChanged == NULL)
goto error;
WM_Hooks_WindowBorderChanged = (WM_Hooks_WMVAL_proto)GetProcAddress(hooksLibrary, "WM_Hooks_WindowBorderChanged");
if (WM_Hooks_WindowBorderChanged == NULL)
goto error;
WM_Hooks_WindowClientAreaChanged = (WM_Hooks_WMVAL_proto)GetProcAddress(hooksLibrary, "WM_Hooks_WindowClientAreaChanged");
if (WM_Hooks_WindowClientAreaChanged == NULL)
goto error;
WM_Hooks_RectangleChanged = (WM_Hooks_WMVAL_proto)GetProcAddress(hooksLibrary, "WM_Hooks_RectangleChanged");
if (WM_Hooks_RectangleChanged == NULL)
goto error;
#ifdef _DEBUG
WM_Hooks_Diagnostic = (WM_Hooks_WMVAL_proto)GetProcAddress(hooksLibrary, "WM_Hooks_Diagnostic");
if (WM_Hooks_Diagnostic == NULL)
goto error;
#endif
WM_Hooks_Install = (WM_Hooks_Install_proto)GetProcAddress(hooksLibrary, "WM_Hooks_Install");
if (WM_Hooks_Install == NULL)
goto error;
WM_Hooks_Remove = (WM_Hooks_Remove_proto)GetProcAddress(hooksLibrary, "WM_Hooks_Remove");
if (WM_Hooks_Remove == NULL)
goto error;
#ifdef _DEBUG
WM_Hooks_SetDiagnosticRange = (WM_Hooks_SetDiagnosticRange_proto)GetProcAddress(hooksLibrary, "WM_Hooks_SetDiagnosticRange");
if (WM_Hooks_SetDiagnosticRange == NULL)
goto error;
#endif
WM_Hooks_EnableRealInputs = (WM_Hooks_EnableRealInputs_proto)GetProcAddress(hooksLibrary, "WM_Hooks_EnableRealInputs");
if (WM_Hooks_EnableRealInputs == NULL)
goto error;
return;
error:
FreeLibrary(hooksLibrary);
hooksLibrary = NULL;
}
class WMHooksThread : public os::Thread {
public:
WMHooksThread() : active(true), thread_id(-1) { }
void stop();
DWORD getThreadId() { return thread_id; }
protected:
virtual void worker();
protected:
bool active;
DWORD thread_id;
};
static WMHooksThread* hook_mgr = 0;
static std::list<WMHooks*> hooks;
static os::Mutex hook_mgr_lock;
static bool StartHookThread() {
if (hook_mgr)
return true;
if (hooksLibrary == NULL)
return false;
vlog.debug("creating thread");
hook_mgr = new WMHooksThread();
hook_mgr->start();
while (hook_mgr->getThreadId() == (DWORD)-1)
Sleep(0);
vlog.debug("installing hooks");
if (!WM_Hooks_Install(hook_mgr->getThreadId(), 0)) {
vlog.error("failed to initialise hooks");
hook_mgr->stop();
delete hook_mgr;
hook_mgr = 0;
return false;
}
return true;
}
static void StopHookThread() {
if (!hook_mgr)
return;
if (!hooks.empty())
return;
vlog.debug("closing thread");
hook_mgr->stop();
delete hook_mgr;
hook_mgr = 0;
}
static bool AddHook(WMHooks* hook) {
vlog.debug("adding hook");
os::AutoMutex a(&hook_mgr_lock);
if (!StartHookThread())
return false;
hooks.push_back(hook);
return true;
}
static bool RemHook(WMHooks* hook) {
{
vlog.debug("removing hook");
os::AutoMutex a(&hook_mgr_lock);
hooks.remove(hook);
}
StopHookThread();
return true;
}
static void NotifyHooksRegion(const Region& r) {
os::AutoMutex a(&hook_mgr_lock);
std::list<WMHooks*>::iterator i;
for (i=hooks.begin(); i!=hooks.end(); i++)
(*i)->NotifyHooksRegion(r);
}
void
WMHooksThread::worker() {
// Obtain message ids for all supported hook messages
UINT windowMsg = WM_Hooks_WindowChanged();
UINT clientAreaMsg = WM_Hooks_WindowClientAreaChanged();
UINT borderMsg = WM_Hooks_WindowBorderChanged();
UINT rectangleMsg = WM_Hooks_RectangleChanged();
#ifdef _DEBUG
UINT diagnosticMsg = 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");
thread_id = GetCurrentThreadId();
while (active && GetMessage(&msg, NULL, 0, 0)) {
count++;
if (msg.message == WM_TIMER) {
// Actually notify callbacks of graphical updates
NotifyHooksRegion(updates[1-activeRgn]);
if (updates[activeRgn].is_empty())
updateDelayTimer.stop();
activeRgn = 1-activeRgn;
updates[activeRgn].clear();
} else if (msg.message == windowMsg) {
// An entire window has (potentially) changed
hwnd = (HWND) msg.lParam;
if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect)) {
updates[activeRgn].assign_union(Rect(wrect.left, wrect.top,
wrect.right, wrect.bottom));
updateDelayTimer.start(updateDelayMs);
}
} else if (msg.message == clientAreaMsg) {
// The client area of a window has (potentially) changed
hwnd = (HWND) msg.lParam;
if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
GetClientRect(hwnd, &wrect) && !IsRectEmpty(&wrect))
{
POINT pt = {0,0};
if (ClientToScreen(hwnd, &pt)) {
updates[activeRgn].assign_union(Rect(wrect.left+pt.x, wrect.top+pt.y,
wrect.right+pt.x, wrect.bottom+pt.y));
updateDelayTimer.start(updateDelayMs);
}
}
} else if (msg.message == borderMsg) {
hwnd = (HWND) msg.lParam;
if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect))
{
Region changed(Rect(wrect.left, wrect.top, wrect.right, wrect.bottom));
RECT crect;
POINT pt = {0,0};
if (GetClientRect(hwnd, &crect) && ClientToScreen(hwnd, &pt) &&
!IsRectEmpty(&crect))
{
changed.assign_subtract(Rect(crect.left+pt.x, crect.top+pt.y,
crect.right+pt.x, crect.bottom+pt.y));
}
if (!changed.is_empty()) {
updates[activeRgn].assign_union(changed);
updateDelayTimer.start(updateDelayMs);
}
}
} else if (msg.message == rectangleMsg) {
Rect r = Rect(LOWORD(msg.wParam), HIWORD(msg.wParam),
LOWORD(msg.lParam), HIWORD(msg.lParam));
if (!r.is_empty()) {
updates[activeRgn].assign_union(r);
updateDelayTimer.start(updateDelayMs);
}
#ifdef _DEBUG
} else if (msg.message == diagnosticMsg) {
vlog.info("DIAG msg=%x(%d) wnd=%lx",
(unsigned)msg.wParam, (int)msg.wParam,
(unsigned long)msg.lParam);
#endif
}
}
vlog.debug("stopping hook thread - processed %d events", count);
WM_Hooks_Remove(getThreadId());
}
void
WMHooksThread::stop() {
vlog.debug("stopping WMHooks thread");
active = false;
PostThreadMessage(thread_id, WM_QUIT, 0, 0);
vlog.debug("waiting for WMHooks thread");
wait();
}
// -=- WMHooks class
rfb::win32::WMHooks::WMHooks() : updateEvent(0) {
LoadHooks();
}
rfb::win32::WMHooks::~WMHooks() {
RemHook(this);
}
bool rfb::win32::WMHooks::setEvent(HANDLE ue) {
if (updateEvent)
RemHook(this);
updateEvent = ue;
return AddHook(this);
}
bool rfb::win32::WMHooks::getUpdates(UpdateTracker* ut) {
if (!updatesReady) return false;
os::AutoMutex a(&hook_mgr_lock);
updates.copyTo(ut);
updates.clear();
updatesReady = false;
return true;
}
#ifdef _DEBUG
void
rfb::win32::WMHooks::setDiagnosticRange(UINT min, UINT max) {
WM_Hooks_SetDiagnosticRange(min, max);
}
#endif
void rfb::win32::WMHooks::NotifyHooksRegion(const Region& r) {
// hook_mgr_lock is already held at this point
updates.add_changed(r);
updatesReady = true;
SetEvent(updateEvent);
}
// -=- WMBlockInput class
rfb::win32::WMBlockInput::WMBlockInput() : active(false) {
LoadHooks();
}
rfb::win32::WMBlockInput::~WMBlockInput() {
blockInputs(false);
}
static bool blocking = false;
static bool blockRealInputs(bool block_) {
// NB: Requires blockMutex to be held!
if (hooksLibrary == NULL)
return false;
if (block_) {
if (blocking)
return true;
// Enable blocking
if (!WM_Hooks_EnableRealInputs(false, false))
return false;
blocking = true;
}
if (blocking) {
WM_Hooks_EnableRealInputs(true, true);
blocking = false;
}
return block_ == blocking;
}
static os::Mutex blockMutex;
static int blockCount = 0;
bool rfb::win32::WMBlockInput::blockInputs(bool on) {
if (active == on) return true;
os::AutoMutex a(&blockMutex);
int newCount = on ? blockCount+1 : blockCount-1;
if (!blockRealInputs(newCount > 0))
return false;
blockCount = newCount;
active = on;
return true;
}

78
win/rfb_win32/WMHooks.h Normal file
View File

@@ -0,0 +1,78 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMHooks.h
#ifndef __RFB_WIN32_WM_HOOKS_H__
#define __RFB_WIN32_WM_HOOKS_H__
#include <windows.h>
#include <rfb/UpdateTracker.h>
#include <rdr/Exception.h>
#include <rfb_win32/Win32Util.h>
namespace rfb {
namespace win32 {
// -=- WMHooks
// Uses the wm_hooks DLL to intercept window messages, to get _hints_ as
// to what may have changed on-screen. Updates are notified via a Win32
// event, and retrieved using the getUpdates method, which is thread-safe.
class WMHooks {
public:
WMHooks();
~WMHooks();
// Specify the event object to notify. Starts the hook subsystem if it is
// not already active, and returns false if the hooks fail to start.
bool setEvent(HANDLE updateEvent);
// Copies any new updates to the UpdateTracker. Returns true if new updates
// were added, false otherwise.
bool getUpdates(UpdateTracker* ut);
#ifdef _DEBUG
// Get notifications of any messages in the given range, to any hooked window
void setDiagnosticRange(UINT min, UINT max);
#endif
// * INTERNAL NOTIFICATION FUNCTION *
void NotifyHooksRegion(const Region& r);
protected:
HANDLE updateEvent;
bool updatesReady;
SimpleUpdateTracker updates;
};
// -=- Support for filtering out local input events while remote connections are
// active. Implemented using SetWindowsHookEx for portability.
class WMBlockInput {
public:
WMBlockInput();
~WMBlockInput();
bool blockInputs(bool block);
protected:
bool active;
};
};
};
#endif // __RFB_WIN32_WM_HOOKS_H__

View File

@@ -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.
*/
// -=- WMNotifier.cxx
#include <rfb_win32/WMNotifier.h>
#include <rfb_win32/WMShatter.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("WMMonitor");
WMMonitor::WMMonitor() : MsgWindow(_T("WMMonitor")), notifier(0) {
}
WMMonitor::~WMMonitor() {
}
LRESULT
WMMonitor::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DISPLAYCHANGE:
if (notifier) {
notifier->notifyDisplayEvent(Notifier::DisplaySizeChanged);
notifier->notifyDisplayEvent(Notifier::DisplayPixelFormatChanged);
}
break;
};
return MsgWindow::processMessage(msg, wParam, lParam);
}

View File

@@ -0,0 +1,67 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMNotifier.h
//
// The WMNotifier is used to get callbacks indicating changes in the state
// of the system, for instance in the size/format/palette of the display.
// The WMNotifier contains a Win32 window, which receives notifications of
// system events and stores them. Whenever processEvent is called, any
// incoming events are processed and the appropriate notifier called.
#ifndef __RFB_WIN32_NOTIFIER_H__
#define __RFB_WIN32_NOTIFIER_H__
#include <rfb/SDesktop.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/DeviceFrameBuffer.h>
#include <rfb_win32/SInput.h>
namespace rfb {
namespace win32 {
// -=- Window Message Monitor implementation
class WMMonitor : MsgWindow {
public:
class Notifier {
public:
typedef enum {DisplaySizeChanged,
DisplayPixelFormatChanged} DisplayEventType;
virtual void notifyDisplayEvent(DisplayEventType evt) = 0;
};
WMMonitor();
virtual ~WMMonitor();
void setNotifier(Notifier* wmn) {notifier=wmn;}
protected:
// - Internal MsgWindow callback
virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
Notifier* notifier;
};
};
};
#endif // __RFB_WIN32_WMNOTIFIER_H__

View File

@@ -0,0 +1,85 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMPoller.cxx
#include <rfb_win32/WMPoller.h>
#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/Configuration.h>
#include <tchar.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("WMPoller");
BoolParameter rfb::win32::WMPoller::poll_console_windows("PollConsoleWindows",
"Server should poll console windows for updates", true);
// -=- WMPoller class
bool
rfb::win32::WMPoller::processEvent() {
PollInfo info;
if (poll_console_windows && ut) {
::EnumWindows(WMPoller::enumWindowProc, (LPARAM) &info);
ut->add_changed(info.poll_include);
}
return false;
}
bool
rfb::win32::WMPoller::setUpdateTracker(UpdateTracker* ut_) {
ut = ut_;
return true;
}
bool
rfb::win32::WMPoller::checkPollWindow(HWND w) {
TCHAR buffer[128];
if (!GetClassName(w, buffer, 128))
throw rdr::SystemException("unable to get window class:%u", GetLastError());
if ((_tcscmp(buffer, _T("tty")) != 0) &&
(_tcscmp(buffer, _T("ConsoleWindowClass")) != 0)) {
return false;
}
return true;
}
void
rfb::win32::WMPoller::pollWindow(HWND w, PollInfo* i) {
RECT r;
if (IsWindowVisible(w) && GetWindowRect(w, &r)) {
if (IsRectEmpty(&r)) return;
Region wrgn(Rect(r.left, r.top, r.right, r.bottom));
if (checkPollWindow(w)) {
wrgn.assign_subtract(i->poll_exclude);
i->poll_include.assign_union(wrgn);
} else {
i->poll_exclude.assign_union(wrgn);
}
}
}
BOOL CALLBACK
rfb::win32::WMPoller::enumWindowProc(HWND w, LPARAM lp) {
pollWindow(w, (PollInfo*)lp);
return TRUE;
}

62
win/rfb_win32/WMPoller.h Normal file
View File

@@ -0,0 +1,62 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMPoller.h
//
// Polls the foreground window. If the pollOnlyConsoles flag is set,
// then checks the window class of the foreground window first and
// only polls it if it's a console.
// If the pollAllWindows flag is set then iterates through visible
// windows, and polls the visible bits. If pollOnlyConsoles is also
// set then only visible parts of console windows will be polled.
#ifndef __RFB_WIN32_WM_POLLER_H__
#define __RFB_WIN32_WM_POLLER_H__
#include <windows.h>
#include <rfb/UpdateTracker.h>
#include <rfb/Configuration.h>
namespace rfb {
namespace win32 {
class WMPoller {
public:
WMPoller() : ut(0) {}
bool processEvent();
bool setUpdateTracker(UpdateTracker* ut);
static BoolParameter poll_console_windows;
protected:
struct PollInfo {
Region poll_include;
Region poll_exclude;
};
static bool checkPollWindow(HWND w);
static void pollWindow(HWND w, PollInfo* info);
static BOOL CALLBACK enumWindowProc(HWND w, LPARAM lp);
UpdateTracker* ut;
};
};
};
#endif // __RFB_WIN32_WM_POLLER_H__

View File

@@ -0,0 +1,58 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMShatter.cxx
#include <rfb_win32/WMShatter.h>
#include <rfb/LogWriter.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("WMShatter");
bool
rfb::win32::IsSafeWM(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
bool result = true;
switch (msg) {
// - UNSAFE MESSAGES
case WM_TIMER:
result = lParam == 0;
break;
};
if (!result) {
vlog.info("IsSafeWM: 0x%p received 0x%x(%I64u, %I64u) - not safe",
window, msg, (long long)wParam, (long long)lParam);
}
return result;
}
LRESULT
rfb::win32::SafeDefWindowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
if (IsSafeWM(window, msg, wParam, lParam))
return DefWindowProc(window, msg, wParam, lParam);
return 0;
}
LRESULT
rfb::win32::SafeDispatchMessage(const MSG* msg) {
if (IsSafeWM(msg->hwnd, msg->message, msg->wParam, msg->lParam))
return DispatchMessage(msg);
return 0;
}

50
win/rfb_win32/WMShatter.h Normal file
View File

@@ -0,0 +1,50 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMShatter.h
//
// WMShatter provides the IsSafeWM routine, which returns true iff the
// supplied window message is safe to pass to DispatchMessage, or to
// process in the window procedure.
//
// This is only required, of course, to avoid so-called "shatter" attacks
// to be made against the VNC server, which take advantage of the noddy
// design of the Win32 window messaging system.
//
// The API here is designed to hopefully be future proof, so that if they
// ever come up with a proper way to determine whether a message is safe
// or not then it can just be reimplemented here...
#ifndef __RFB_WIN32_SHATTER_H__
#define __RFB_WIN32_SHATTER_H__
#include <windows.h>
namespace rfb {
namespace win32 {
bool IsSafeWM(HWND window, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT SafeDefWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT SafeDispatchMessage(const MSG* msg);
};
};
#endif // __RFB_WIN32_SHATTER_H__

View File

@@ -0,0 +1,67 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMCopyRect.cxx
#include <rfb_win32/WMWindowCopyRect.h>
#include <rfb/LogWriter.h>
#include <windows.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("WMCopyRect");
// -=- WMHooks class
rfb::win32::WMCopyRect::WMCopyRect() : ut(0), fg_window(0) {
}
bool
rfb::win32::WMCopyRect::processEvent() {
// See if the foreground window has moved
HWND window = GetForegroundWindow();
if (window) {
RECT wrect;
if (IsWindow(window) && IsWindowVisible(window) && GetWindowRect(window, &wrect)) {
Rect winrect(wrect.left, wrect.top, wrect.right, wrect.bottom);
if (fg_window == window) {
if (!fg_window_rect.tl.equals(winrect.tl) && ut) {
// Window has moved - mark both the previous and new position as changed
// (we can't use add_copied() here because we aren't that properly synced
// with the actual state of the framebuffer)
ut->add_changed(Region(winrect));
ut->add_changed(Region(fg_window_rect));
}
}
fg_window = window;
fg_window_rect = winrect;
} else {
fg_window = 0;
}
} else {
fg_window = 0;
}
return false;
}
bool
rfb::win32::WMCopyRect::setUpdateTracker(UpdateTracker* ut_) {
ut = ut_;
return true;
}

View File

@@ -0,0 +1,53 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- WMWindowCopyRect.h
//
// Helper class which produces copyRect actions by monitoring the location
// of the current foreground window.
// Whenever processEvent is called, the foreground window's position is
// recalculated and a copy event flushed to the supplied UpdateTracker
// if appropriate.
#ifndef __RFB_WIN32_WM_WINDOW_COPYRECT_H__
#define __RFB_WIN32_WM_WINDOW_COPYRECT_H__
#include <rfb/UpdateTracker.h>
namespace rfb {
namespace win32 {
class WMCopyRect {
public:
WMCopyRect();
bool processEvent();
bool setUpdateTracker(UpdateTracker* ut);
protected:
UpdateTracker* ut;
void* fg_window;
Rect fg_window_rect;
};
};
};
#endif // __RFB_WIN32_WM_WINDOW_COPYRECT_H__

115
win/rfb_win32/Win32Util.cxx Normal file
View File

@@ -0,0 +1,115 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// Win32Util.cxx
#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Win32Util.h>
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Handle.h>
#include <rdr/HexOutStream.h>
#include <rdr/Exception.h>
#include <stdio.h>
namespace rfb {
namespace win32 {
FileVersionInfo::FileVersionInfo(const TCHAR* filename) {
// Get executable name
ModuleFileName exeName;
if (!filename)
filename = exeName.buf;
// Attempt to open the file, to cause Access Denied, etc, errors
// to be correctly reported, since the GetFileVersionInfoXXX calls lie...
{
Handle file(CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0));
if (file.h == INVALID_HANDLE_VALUE)
throw rdr::SystemException("Failed to open file", GetLastError());
}
// Get version info size
DWORD handle;
int size = GetFileVersionInfoSize((TCHAR*)filename, &handle);
if (!size)
throw rdr::SystemException("GetVersionInfoSize failed", GetLastError());
// Get version info
buf = new TCHAR[size];
if (!GetFileVersionInfo((TCHAR*)filename, handle, size, buf))
throw rdr::SystemException("GetVersionInfo failed", GetLastError());
}
const TCHAR* FileVersionInfo::getVerString(const TCHAR* name, DWORD langId) {
char langIdBuf[sizeof(langId)];
for (int i=sizeof(langIdBuf)-1; i>=0; i--) {
langIdBuf[i] = (char) (langId & 0xff);
langId = langId >> 8;
}
TCharArray langIdStr(rdr::HexOutStream::binToHexStr(langIdBuf, sizeof(langId)));
TCharArray infoName(_tcslen(_T("StringFileInfo")) + 4 + _tcslen(name) + _tcslen(langIdStr.buf));
_stprintf(infoName.buf, _T("\\StringFileInfo\\%s\\%s"), langIdStr.buf, name);
// Locate the required version string within the version info
TCHAR* buffer = 0;
UINT length = 0;
if (!VerQueryValue(buf, infoName.buf, (void**)&buffer, &length)) {
printf("unable to find %s version string", infoName.buf);
throw rdr::Exception("VerQueryValue failed");
}
return buffer;
}
bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file) {
return tstrSplit(path, '\\', dir, file, true);
}
void centerWindow(HWND handle, HWND parent) {
RECT r;
MonitorInfo mi(parent ? parent : handle);
if (!parent || !IsWindowVisible(parent) || !GetWindowRect(parent, &r))
r=mi.rcWork;
centerWindow(handle, r);
mi.clipTo(handle);
}
void centerWindow(HWND handle, const RECT& r) {
RECT wr;
if (!GetWindowRect(handle, &wr)) return;
int w = wr.right-wr.left;
int h = wr.bottom-wr.top;
int x = (r.left + r.right - w)/2;
int y = (r.top + r.bottom - h)/2;
UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE;
SetWindowPos(handle, 0, x, y, 0, 0, flags);
}
void resizeWindow(HWND handle, int width, int height) {
RECT r;
GetWindowRect(handle, &r);
SetWindowPos(handle, 0, 0, 0, width, height, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
centerWindow(handle, r);
}
};
};

55
win/rfb_win32/Win32Util.h Normal file
View File

@@ -0,0 +1,55 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Win32Util.h
// Miscellaneous but useful Win32 API utility functions & classes.
// In particular, a set of classes which wrap GDI objects,
// and some to handle palettes.
#ifndef __RFB_WIN32_GDIUTIL_H__
#define __RFB_WIN32_GDIUTIL_H__
#include <rfb_win32/TCharArray.h>
namespace rfb {
namespace win32 {
struct FileVersionInfo : public TCharArray {
FileVersionInfo(const TCHAR* filename=0);
const TCHAR* getVerString(const TCHAR* name, DWORD langId = 0x080904b0);
};
bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file);
// Center the window to a rectangle, or to a parent window.
// Optionally, resize the window to lay within the rect or parent window
// If the parent window is NULL then the working area if the window's
// current monitor is used instead.
void centerWindow(HWND handle, const RECT& r);
void centerWindow(HWND handle, HWND parent);
// resizeWindow resizes a window about its center
void resizeWindow(HWND handle, int width, int height);
};
};
#endif

149
win/rfb_win32/keymap.h Normal file
View File

@@ -0,0 +1,149 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// keymap.h - this file is shared between SInput.cxx and CKeyboard.cxx
//
// Mapping of X keysyms to and from Windows VK codes. Ordering here must be
// such that when we look up a Windows VK code we get the preferred X keysym.
// Going the other way there is no problem because an X keysym always maps to
// exactly one Windows VK code. This map only contain keys which are not the
// normal keys for printable ASCII characters. For example it does not contain
// VK_SPACE (note that things like VK_ADD are for the plus key on the keypad,
// not on the main keyboard).
struct keymap_t {
rdr::U32 keysym;
rdr::U8 vk;
bool extended;
};
static keymap_t keymap[] = {
{ XK_BackSpace, VK_BACK, 0 },
{ XK_Tab, VK_TAB, 0 },
{ XK_Clear, VK_CLEAR, 0 },
{ XK_Return, VK_RETURN, 0 },
{ XK_Pause, VK_PAUSE, 0 },
{ XK_Escape, VK_ESCAPE, 0 },
{ XK_Delete, VK_DELETE, 1 },
// Cursor control & motion
{ XK_Home, VK_HOME, 1 },
{ XK_Left, VK_LEFT, 1 },
{ XK_Up, VK_UP, 1 },
{ XK_Right, VK_RIGHT, 1 },
{ XK_Down, VK_DOWN, 1 },
{ XK_Page_Up, VK_PRIOR, 1 },
{ XK_Page_Down, VK_NEXT, 1 },
{ XK_End, VK_END, 1 },
// Misc functions
{ XK_Select, VK_SELECT, 0 },
{ XK_Print, VK_SNAPSHOT, 0 },
{ XK_Execute, VK_EXECUTE, 0 },
{ XK_Insert, VK_INSERT, 1 },
{ XK_Help, VK_HELP, 0 },
{ XK_Break, VK_CANCEL, 1 },
// Auxiliary Functions - must come before XK_KP_F1, etc
{ XK_F1, VK_F1, 0 },
{ XK_F2, VK_F2, 0 },
{ XK_F3, VK_F3, 0 },
{ XK_F4, VK_F4, 0 },
{ XK_F5, VK_F5, 0 },
{ XK_F6, VK_F6, 0 },
{ XK_F7, VK_F7, 0 },
{ XK_F8, VK_F8, 0 },
{ XK_F9, VK_F9, 0 },
{ XK_F10, VK_F10, 0 },
{ XK_F11, VK_F11, 0 },
{ XK_F12, VK_F12, 0 },
{ XK_F13, VK_F13, 0 },
{ XK_F14, VK_F14, 0 },
{ XK_F15, VK_F15, 0 },
{ XK_F16, VK_F16, 0 },
{ XK_F17, VK_F17, 0 },
{ XK_F18, VK_F18, 0 },
{ XK_F19, VK_F19, 0 },
{ XK_F20, VK_F20, 0 },
{ XK_F21, VK_F21, 0 },
{ XK_F22, VK_F22, 0 },
{ XK_F23, VK_F23, 0 },
{ XK_F24, VK_F24, 0 },
// Keypad Functions, keypad numbers
{ XK_KP_Tab, VK_TAB, 0 },
{ XK_KP_Enter, VK_RETURN, 1 },
{ XK_KP_F1, VK_F1, 0 },
{ XK_KP_F2, VK_F2, 0 },
{ XK_KP_F3, VK_F3, 0 },
{ XK_KP_F4, VK_F4, 0 },
{ XK_KP_Home, VK_HOME, 0 },
{ XK_KP_Left, VK_LEFT, 0 },
{ XK_KP_Up, VK_UP, 0 },
{ XK_KP_Right, VK_RIGHT, 0 },
{ XK_KP_Down, VK_DOWN, 0 },
{ XK_KP_End, VK_END, 0 },
{ XK_KP_Page_Up, VK_PRIOR, 0 },
{ XK_KP_Page_Down, VK_NEXT, 0 },
{ XK_KP_Begin, VK_CLEAR, 0 },
{ XK_KP_Insert, VK_INSERT, 0 },
{ XK_KP_Delete, VK_DELETE, 0 },
{ XK_KP_Multiply, VK_MULTIPLY, 0 },
{ XK_KP_Add, VK_ADD, 0 },
{ XK_KP_Separator, VK_SEPARATOR, 0 },
{ XK_KP_Subtract, VK_SUBTRACT, 0 },
{ XK_KP_Decimal, VK_DECIMAL, 0 },
{ XK_KP_Divide, VK_DIVIDE, 1 },
{ XK_KP_0, VK_NUMPAD0, 0 },
{ XK_KP_1, VK_NUMPAD1, 0 },
{ XK_KP_2, VK_NUMPAD2, 0 },
{ XK_KP_3, VK_NUMPAD3, 0 },
{ XK_KP_4, VK_NUMPAD4, 0 },
{ XK_KP_5, VK_NUMPAD5, 0 },
{ XK_KP_6, VK_NUMPAD6, 0 },
{ XK_KP_7, VK_NUMPAD7, 0 },
{ XK_KP_8, VK_NUMPAD8, 0 },
{ XK_KP_9, VK_NUMPAD9, 0 },
// Modifiers
{ XK_Shift_L, VK_SHIFT, 0 },
{ XK_Shift_R, VK_SHIFT, 0 },
{ XK_Control_L, VK_CONTROL, 0 },
{ XK_Control_R, VK_CONTROL, 1 },
{ XK_Alt_L, VK_MENU, 0 },
{ XK_Alt_R, VK_MENU, 1 },
// Left & Right Windows keys & Windows Menu Key
{ XK_Super_L, VK_LWIN, 0 },
{ XK_Super_R, VK_RWIN, 0 },
{ XK_Menu, VK_APPS, 0 },
// Japanese stuff - almost certainly wrong...
{ XK_Kanji, VK_KANJI, 0 },
{ XK_Kana_Shift, VK_KANA, 0 },
};

37
win/rfb_win32/resource.h Normal file
View File

@@ -0,0 +1,37 @@
/* Copyright (C) 2011 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
/*
* This file contains resource IDs shared between various Windows binaries.
* If you are adding new resource ID ensure it doesn't conflict with per-binary
* resource IDs.
*/
#ifndef __RFB_WIN32_RESOURCE_H__
#define __RFB_WIN32_RESOURCE_H__
#define IDD_SECURITY 117
#define IDC_ENC_NONE 1201
#define IDC_ENC_TLS 1202
#define IDC_ENC_X509 1203
#define IDC_AUTH_NONE 1206
#define IDC_AUTH_VNC 1207
#define IDC_AUTH_PLAIN 1208
#endif

View File

@@ -0,0 +1,189 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_AUTHENTICATION
#define WINVNCCONF_AUTHENTICATION
#include <windows.h>
#include <commctrl.h>
#include <vncconfig/PasswordDialog.h>
#include <rfb_win32/Registry.h>
#include <rfb_win32/SecurityPage.h>
#include <rfb_win32/MsgBox.h>
#include <rfb/ServerCore.h>
#include <rfb/Security.h>
#include <rfb/SecurityServer.h>
#include <rfb/SSecurityVncAuth.h>
#ifdef HAVE_GNUTLS
#include <rfb/SSecurityTLS.h>
#endif
#include <rfb/Password.h>
static rfb::BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
"Only prompt for a local user to accept incoming connections if there is a user logged on", false);
namespace rfb {
namespace win32 {
class SecPage : public SecurityPage {
public:
SecPage(const RegKey& rk)
: SecurityPage(NULL), regKey(rk) {
security = new SecurityServer();
}
void initDialog() {
SecurityPage::initDialog();
setItemChecked(IDC_QUERY_CONNECT, rfb::Server::queryConnect);
setItemChecked(IDC_QUERY_LOGGED_ON, queryOnlyIfLoggedOn);
onCommand(IDC_AUTH_NONE, 0);
}
bool onCommand(int id, int cmd) {
SecurityPage::onCommand(id, cmd);
setChanged(true);
if (id == IDC_AUTH_VNC_PASSWD) {
PasswordDialog passwdDlg(regKey, registryInsecure);
passwdDlg.showDialog(handle);
} else if (id == IDC_LOAD_CERT) {
const TCHAR* title = _T("X509Cert");
const TCHAR* filter =
_T("X.509 Certificates (*.crt;*.cer;*.pem)\0*.crt;*.cer;*.pem\0All\0*.*\0");
showFileChooser(regKey, title, filter, handle);
} else if (id == IDC_LOAD_CERTKEY) {
const TCHAR* title = _T("X509Key");
const TCHAR* filter = _T("X.509 Keys (*.key;*.pem)\0*.key;*.pem\0All\0*.*\0");
showFileChooser(regKey, title, filter, handle);
} else if (id == IDC_QUERY_LOGGED_ON) {
enableItem(IDC_QUERY_LOGGED_ON, enableQueryOnlyIfLoggedOn());
}
return true;
}
bool onOk() {
SecurityPage::onOk();
if (isItemChecked(IDC_AUTH_VNC))
verifyVncPassword(regKey);
else if (haveVncPassword() &&
MsgBox(0, _T("The VNC authentication method is disabled, but a password is still stored for it.\n")
_T("Do you want to remove the VNC authentication password from the registry?"),
MB_ICONWARNING | MB_YESNO) == IDYES) {
regKey.setBinary(_T("Password"), 0, 0);
}
#ifdef HAVE_GNUTLS
if (isItemChecked(IDC_ENC_X509)) {
SSecurityTLS::X509_CertFile.setParam(regKey.getString("X509Cert"));
SSecurityTLS::X509_CertFile.setParam(regKey.getString("X509Key"));
}
#endif
regKey.setString(_T("SecurityTypes"), security->ToString());
regKey.setBool(_T("QueryConnect"), isItemChecked(IDC_QUERY_CONNECT));
regKey.setBool(_T("QueryOnlyIfLoggedOn"), isItemChecked(IDC_QUERY_LOGGED_ON));
return true;
}
void setWarnPasswdInsecure(bool warn) {
registryInsecure = warn;
}
bool enableQueryOnlyIfLoggedOn() {
return isItemChecked(IDC_QUERY_CONNECT);
}
static bool haveVncPassword() {
PlainPasswd password, passwordReadOnly;
SSecurityVncAuth::vncAuthPasswd.getVncAuthPasswd(&password, &passwordReadOnly);
return password.buf && strlen(password.buf) != 0;
}
static void verifyVncPassword(const RegKey& regKey) {
if (!haveVncPassword()) {
MsgBox(0, _T("The VNC authentication method is enabled, but no password is specified.\n")
_T("The password dialog will now be shown."), MB_ICONINFORMATION | MB_OK);
PasswordDialog passwd(regKey, registryInsecure);
passwd.showDialog();
}
}
virtual void loadX509Certs(void) {}
virtual void enableX509Dialogs(void) {
enableItem(IDC_LOAD_CERT, true);
enableItem(IDC_LOAD_CERTKEY, true);
}
virtual void disableX509Dialogs(void) {
enableItem(IDC_LOAD_CERT, false);
enableItem(IDC_LOAD_CERTKEY, false);
}
virtual void loadVncPasswd() {
enableItem(IDC_AUTH_VNC_PASSWD, isItemChecked(IDC_AUTH_VNC));
}
protected:
RegKey regKey;
static bool registryInsecure;
private:
inline void modifyAuthMethod(int enc_idc, int auth_idc, bool enable)
{
setItemChecked(enc_idc, enable);
setItemChecked(auth_idc, enable);
}
inline bool showFileChooser(const RegKey& rk,
const char* title,
const char* filter,
HWND hwnd)
{
OPENFILENAME ofn;
char filename[MAX_PATH];
ZeroMemory(&ofn, sizeof(ofn));
ZeroMemory(&filename, sizeof(filename));
filename[0] = '\0';
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = filename;
ofn.nMaxFile = sizeof(filename);
ofn.lpstrFilter = (char*)filter;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrTitle = (char*)title;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn)==TRUE) {
regKey.setString(title, filename);
return true;
}
return false;
}
};
};
bool SecPage::registryInsecure = false;
};
#endif

View File

@@ -0,0 +1,13 @@
include_directories(${CMAKE_BINARY_DIR}/win)
add_executable(vncconfig WIN32
Legacy.cxx
PasswordDialog.cxx
vncconfig.cxx
vncconfig.rc)
target_link_libraries(vncconfig rfb_win32 rfb network rdr ws2_32.lib)
install(TARGETS vncconfig
RUNTIME DESTINATION ${BIN_DIR}
)

303
win/vncconfig/Connections.h Normal file
View File

@@ -0,0 +1,303 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_CONNECTIONS
#define WINVNCCONF_CONNECTIONS
#include <vector>
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/ModuleFileName.h>
#include <rfb/Configuration.h>
#include <rfb/Blacklist.h>
#include <network/TcpSocket.h>
static rfb::IntParameter http_port("HTTPPortNumber",
"TCP/IP port on which the server will serve the Java applet VNC Viewer ", 5800);
static rfb::IntParameter port_number("PortNumber",
"TCP/IP port on which the server will accept connections", 5900);
static rfb::StringParameter hosts("Hosts",
"Filter describing which hosts are allowed access to this server", "+");
static rfb::BoolParameter localHost("LocalHost",
"Only accept connections from via the local loop-back network interface", false);
namespace rfb {
namespace win32 {
class ConnHostDialog : public Dialog {
public:
ConnHostDialog() : Dialog(GetModuleHandle(0)) {}
bool showDialog(const TCHAR* pat) {
pattern.replaceBuf(tstrDup(pat));
return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONN_HOST));
}
void initDialog() {
if (_tcslen(pattern.buf) == 0)
pattern.replaceBuf(tstrDup("+"));
if (pattern.buf[0] == _T('+'))
setItemChecked(IDC_ALLOW, true);
else if (pattern.buf[0] == _T('?'))
setItemChecked(IDC_QUERY, true);
else
setItemChecked(IDC_DENY, true);
setItemString(IDC_HOST_PATTERN, &pattern.buf[1]);
pattern.replaceBuf(0);
}
bool onOk() {
TCharArray host(getItemString(IDC_HOST_PATTERN));
TCharArray newPat(_tcslen(host.buf)+2);
if (isItemChecked(IDC_ALLOW))
newPat.buf[0] = _T('+');
else if (isItemChecked(IDC_QUERY))
newPat.buf[0] = _T('?');
else
newPat.buf[0] = _T('-');
newPat.buf[1] = 0;
_tcscat(newPat.buf, host.buf);
try {
network::TcpFilter::Pattern pat(network::TcpFilter::parsePattern(CStr(newPat.buf)));
pattern.replaceBuf(TCharArray(network::TcpFilter::patternToStr(pat)).takeBuf());
} catch(rdr::Exception& e) {
MsgBox(NULL, TStr(e.str()), MB_ICONEXCLAMATION | MB_OK);
return false;
}
return true;
}
const TCHAR* getPattern() {return pattern.buf;}
protected:
TCharArray pattern;
};
class ConnectionsPage : public PropSheetPage {
public:
ConnectionsPage(const RegKey& rk)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_CONNECTIONS)), regKey(rk) {}
void initDialog() {
vlog.debug("set IDC_PORT %d", (int)port_number);
setItemInt(IDC_PORT, port_number ? port_number : 5900);
setItemChecked(IDC_RFB_ENABLE, port_number != 0);
setItemInt(IDC_IDLE_TIMEOUT, rfb::Server::idleTimeout);
vlog.debug("set IDC_HTTP_PORT %d", (int)http_port);
setItemInt(IDC_HTTP_PORT, http_port ? http_port : 5800);
setItemChecked(IDC_HTTP_ENABLE, http_port != 0);
enableItem(IDC_HTTP_PORT, http_port != 0);
setItemChecked(IDC_LOCALHOST, localHost);
HWND listBox = GetDlgItem(handle, IDC_HOSTS);
while (SendMessage(listBox, LB_GETCOUNT, 0, 0))
SendMessage(listBox, LB_DELETESTRING, 0, 0);
CharArray tmp;
tmp.buf = hosts.getData();
while (tmp.buf) {
CharArray first;
strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
if (strlen(first.buf))
SendMessage(listBox, LB_ADDSTRING, 0, (LPARAM)(const TCHAR*)TStr(first.buf));
}
onCommand(IDC_RFB_ENABLE, EN_CHANGE);
}
bool onCommand(int id, int cmd) {
switch (id) {
case IDC_HOSTS:
{
DWORD selected = SendMessage(GetDlgItem(handle, IDC_HOSTS), LB_GETCURSEL, 0, 0);
DWORD count = SendMessage(GetDlgItem(handle, IDC_HOSTS), LB_GETCOUNT, 0, 0);
bool enable = selected != (DWORD)LB_ERR;
enableItem(IDC_HOST_REMOVE, enable);
enableItem(IDC_HOST_UP, enable && (selected > 0));
enableItem(IDC_HOST_DOWN, enable && (selected+1 < count));
enableItem(IDC_HOST_EDIT, enable);
setChanged(isChanged());
}
return true;
case IDC_PORT:
if (cmd == EN_CHANGE) {
try {
setItemInt(IDC_HTTP_PORT, rfbPortToHTTP(getItemInt(IDC_PORT)));
} catch (...) {
}
}
case IDC_HTTP_PORT:
case IDC_IDLE_TIMEOUT:
if (cmd == EN_CHANGE)
setChanged(isChanged());
return false;
case IDC_HTTP_ENABLE:
case IDC_RFB_ENABLE:
case IDC_LOCALHOST:
{
// HTTP port
enableItem(IDC_HTTP_PORT, isItemChecked(IDC_HTTP_ENABLE) && isItemChecked(IDC_RFB_ENABLE));
enableItem(IDC_HTTP_ENABLE, isItemChecked(IDC_RFB_ENABLE));
// RFB port
enableItem(IDC_PORT, isItemChecked(IDC_RFB_ENABLE));
// Hosts
enableItem(IDC_LOCALHOST, isItemChecked(IDC_RFB_ENABLE));
bool enableHosts = !isItemChecked(IDC_LOCALHOST) && isItemChecked(IDC_RFB_ENABLE);
enableItem(IDC_HOSTS, enableHosts);
enableItem(IDC_HOST_ADD, enableHosts);
if (!enableHosts) {
enableItem(IDC_HOST_REMOVE, enableHosts);
enableItem(IDC_HOST_UP, enableHosts);
enableItem(IDC_HOST_DOWN, enableHosts);
enableItem(IDC_HOST_EDIT, enableHosts);
} else {
onCommand(IDC_HOSTS, EN_CHANGE);
}
setChanged(isChanged());
return false;
}
case IDC_HOST_ADD:
if (hostDialog.showDialog(_T("")))
{
const TCHAR* pattern = hostDialog.getPattern();
if (pattern)
SendMessage(GetDlgItem(handle, IDC_HOSTS), LB_ADDSTRING, 0, (LPARAM)pattern);
}
return true;
case IDC_HOST_EDIT:
{
HWND listBox = GetDlgItem(handle, IDC_HOSTS);
int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
TCharArray pattern(SendMessage(listBox, LB_GETTEXTLEN, item, 0)+1);
SendMessage(listBox, LB_GETTEXT, item, (LPARAM)pattern.buf);
if (hostDialog.showDialog(pattern.buf)) {
const TCHAR* newPat = hostDialog.getPattern();
if (newPat) {
item = SendMessage(listBox, LB_FINDSTRINGEXACT, item, (LPARAM)pattern.buf);
if (item != LB_ERR) {
SendMessage(listBox, LB_DELETESTRING, item, 0);
SendMessage(listBox, LB_INSERTSTRING, item, (LPARAM)newPat);
SendMessage(listBox, LB_SETCURSEL, item, 0);
onCommand(IDC_HOSTS, EN_CHANGE);
}
}
}
}
return true;
case IDC_HOST_UP:
{
HWND listBox = GetDlgItem(handle, IDC_HOSTS);
int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
TCharArray pattern(SendMessage(listBox, LB_GETTEXTLEN, item, 0)+1);
SendMessage(listBox, LB_GETTEXT, item, (LPARAM)pattern.buf);
SendMessage(listBox, LB_DELETESTRING, item, 0);
SendMessage(listBox, LB_INSERTSTRING, item-1, (LPARAM)pattern.buf);
SendMessage(listBox, LB_SETCURSEL, item-1, 0);
onCommand(IDC_HOSTS, EN_CHANGE);
}
return true;
case IDC_HOST_DOWN:
{
HWND listBox = GetDlgItem(handle, IDC_HOSTS);
int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
TCharArray pattern(SendMessage(listBox, LB_GETTEXTLEN, item, 0)+1);
SendMessage(listBox, LB_GETTEXT, item, (LPARAM)pattern.buf);
SendMessage(listBox, LB_DELETESTRING, item, 0);
SendMessage(listBox, LB_INSERTSTRING, item+1, (LPARAM)pattern.buf);
SendMessage(listBox, LB_SETCURSEL, item+1, 0);
onCommand(IDC_HOSTS, EN_CHANGE);
}
return true;
case IDC_HOST_REMOVE:
{
HWND listBox = GetDlgItem(handle, IDC_HOSTS);
int item = SendMessage(listBox, LB_GETCURSEL, 0, 0);
SendMessage(listBox, LB_DELETESTRING, item, 0);
onCommand(IDC_HOSTS, EN_CHANGE);
}
}
return false;
}
bool onOk() {
regKey.setInt(_T("PortNumber"), isItemChecked(IDC_RFB_ENABLE) ? getItemInt(IDC_PORT) : 0);
regKey.setInt(_T("IdleTimeout"), getItemInt(IDC_IDLE_TIMEOUT));
regKey.setInt(_T("HTTPPortNumber"), isItemChecked(IDC_HTTP_ENABLE) && isItemChecked(IDC_RFB_ENABLE)
? getItemInt(IDC_HTTP_PORT) : 0);
regKey.setInt(_T("LocalHost"), isItemChecked(IDC_LOCALHOST));
regKey.setString(_T("Hosts"), TCharArray(getHosts()).buf);
return true;
}
bool isChanged() {
try {
CharArray new_hosts(getHosts());
CharArray old_hosts(hosts.getData());
return (strcmp(new_hosts.buf, old_hosts.buf) != 0) ||
(localHost != isItemChecked(IDC_LOCALHOST)) ||
(port_number != getItemInt(IDC_PORT)) ||
(http_port != getItemInt(IDC_HTTP_PORT)) ||
((http_port!=0) != (isItemChecked(IDC_HTTP_ENABLE)!=0)) ||
(rfb::Server::idleTimeout != getItemInt(IDC_IDLE_TIMEOUT));
} catch (rdr::Exception&) {
return false;
}
}
char* getHosts() {
int bufLen = 1, i;
HWND listBox = GetDlgItem(handle, IDC_HOSTS);
for (i=0; i<SendMessage(listBox, LB_GETCOUNT, 0, 0); i++)
bufLen+=SendMessage(listBox, LB_GETTEXTLEN, i, 0)+1;
TCharArray hosts_str(bufLen);
hosts_str.buf[0] = 0;
TCHAR* outPos = hosts_str.buf;
for (i=0; i<SendMessage(listBox, LB_GETCOUNT, 0, 0); i++) {
outPos += SendMessage(listBox, LB_GETTEXT, i, (LPARAM)outPos);
outPos[0] = ',';
outPos[1] = 0;
outPos++;
}
return strDup(hosts_str.buf);
}
int rfbPortToHTTP(int rfbPort) {
int offset = -100;
if (http_port)
offset = http_port - port_number;
int httpPort = rfbPort + offset;
if (httpPort <= 0)
httpPort = rfbPort;
return httpPort;
}
protected:
RegKey regKey;
ConnHostDialog hostDialog;
};
};
};
#endif

80
win/vncconfig/Desktop.h Normal file
View File

@@ -0,0 +1,80 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_DESKTOP
#define WINVNCCONF_DESKTOP
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/SDisplay.h>
namespace rfb {
namespace win32 {
class DesktopPage : public PropSheetPage {
public:
DesktopPage(const RegKey& rk)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DESKTOP)), regKey(rk) {}
void initDialog() {
CharArray action(rfb::win32::SDisplay::disconnectAction.getData());
bool disconnectLock = stricmp(action.buf, "Lock") == 0;
bool disconnectLogoff = stricmp(action.buf, "Logoff") == 0;
setItemChecked(IDC_DISCONNECT_LOGOFF, disconnectLogoff);
setItemChecked(IDC_DISCONNECT_LOCK, disconnectLock);
setItemChecked(IDC_DISCONNECT_NONE, !disconnectLock && !disconnectLogoff);
setItemChecked(IDC_REMOVE_WALLPAPER, rfb::win32::SDisplay::removeWallpaper);
setItemChecked(IDC_DISABLE_EFFECTS, rfb::win32::SDisplay::disableEffects);
}
bool onCommand(int id, int cmd) {
switch (id) {
case IDC_DISCONNECT_LOGOFF:
case IDC_DISCONNECT_LOCK:
case IDC_DISCONNECT_NONE:
case IDC_REMOVE_WALLPAPER:
case IDC_DISABLE_EFFECTS:
CharArray action(rfb::win32::SDisplay::disconnectAction.getData());
bool disconnectLock = stricmp(action.buf, "Lock") == 0;
bool disconnectLogoff = stricmp(action.buf, "Logoff") == 0;
setChanged((disconnectLogoff != isItemChecked(IDC_DISCONNECT_LOGOFF)) ||
(disconnectLock != isItemChecked(IDC_DISCONNECT_LOCK)) ||
(isItemChecked(IDC_REMOVE_WALLPAPER) != rfb::win32::SDisplay::removeWallpaper) ||
(isItemChecked(IDC_DISABLE_EFFECTS) != rfb::win32::SDisplay::disableEffects));
break;
}
return false;
}
bool onOk() {
const TCHAR* action = _T("None");
if (isItemChecked(IDC_DISCONNECT_LOGOFF))
action = _T("Logoff");
else if (isItemChecked(IDC_DISCONNECT_LOCK))
action = _T("Lock");
regKey.setString(_T("DisconnectAction"), action);
regKey.setBool(_T("RemoveWallpaper"), isItemChecked(IDC_REMOVE_WALLPAPER));
regKey.setBool(_T("DisableEffects"), isItemChecked(IDC_DISABLE_EFFECTS));
return true;
}
protected:
RegKey regKey;
};
};
};
#endif

77
win/vncconfig/Hooking.h Normal file
View File

@@ -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.
*/
#ifndef WINVNCCONF_HOOKING
#define WINVNCCONF_HOOKING
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/SDisplay.h>
#include <rfb_win32/WMPoller.h>
#include <rfb/ServerCore.h>
namespace rfb {
namespace win32 {
class HookingPage : public PropSheetPage {
public:
HookingPage(const RegKey& rk)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_HOOKING)), regKey(rk) {}
void initDialog() {
setItemChecked(IDC_USEPOLLING, rfb::win32::SDisplay::updateMethod == 0);
setItemChecked(IDC_USEHOOKS, (rfb::win32::SDisplay::updateMethod == 1));
setItemChecked(IDC_POLLCONSOLES, rfb::win32::WMPoller::poll_console_windows);
setItemChecked(IDC_CAPTUREBLT, rfb::win32::DeviceFrameBuffer::useCaptureBlt);
onCommand(IDC_USEHOOKS, 0);
}
bool onCommand(int id, int cmd) {
switch (id) {
case IDC_USEPOLLING:
case IDC_USEHOOKS:
case IDC_POLLCONSOLES:
case IDC_CAPTUREBLT:
setChanged(((rfb::win32::SDisplay::updateMethod == 0) != isItemChecked(IDC_USEPOLLING)) ||
((rfb::win32::SDisplay::updateMethod == 1) != isItemChecked(IDC_USEHOOKS)) ||
(rfb::win32::WMPoller::poll_console_windows != isItemChecked(IDC_POLLCONSOLES)) ||
(rfb::win32::DeviceFrameBuffer::useCaptureBlt != isItemChecked(IDC_CAPTUREBLT)));
enableItem(IDC_POLLCONSOLES, isItemChecked(IDC_USEHOOKS));
break;
}
return false;
}
bool onOk() {
if (isItemChecked(IDC_USEPOLLING))
regKey.setInt(_T("UpdateMethod"), 0);
if (isItemChecked(IDC_USEHOOKS))
regKey.setInt(_T("UpdateMethod"), 1);
regKey.setBool(_T("PollConsoleWindows"), isItemChecked(IDC_POLLCONSOLES));
regKey.setBool(_T("UseCaptureBlt"), isItemChecked(IDC_CAPTUREBLT));
// *** LEGACY compatibility ***
regKey.setBool(_T("UseHooks"), isItemChecked(IDC_USEHOOKS));
return true;
}
protected:
RegKey regKey;
};
};
};
#endif

85
win/vncconfig/Inputs.h Normal file
View File

@@ -0,0 +1,85 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_INPUTS
#define WINVNCCONF_INPUTS
#ifndef SPI_GETBLOCKSENDINPUTRESETS
#define SPI_GETBLOCKSENDINPUTRESETS 0x1026
#define SPI_SETBLOCKSENDINPUTRESETS 0x1027
#endif
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb/ServerCore.h>
namespace rfb {
namespace win32 {
class InputsPage : public PropSheetPage {
public:
InputsPage(const RegKey& rk)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_INPUTS)),
regKey(rk), enableAffectSSaver(true) {}
void initDialog() {
setItemChecked(IDC_ACCEPT_KEYS, rfb::Server::acceptKeyEvents);
setItemChecked(IDC_RAW_KEYBOARD, SKeyboard::rawKeyboard);
setItemChecked(IDC_ACCEPT_PTR, rfb::Server::acceptPointerEvents);
setItemChecked(IDC_ACCEPT_CUTTEXT, rfb::Server::acceptCutText);
setItemChecked(IDC_SEND_CUTTEXT, rfb::Server::sendCutText);
setItemChecked(IDC_DISABLE_LOCAL_INPUTS, SDisplay::disableLocalInputs);
BOOL blocked = FALSE;
if (SystemParametersInfo(SPI_GETBLOCKSENDINPUTRESETS, 0, &blocked, 0))
setItemChecked(IDC_AFFECT_SCREENSAVER, !blocked);
else
enableAffectSSaver = false;
enableItem(IDC_AFFECT_SCREENSAVER, enableAffectSSaver);
}
bool onCommand(int id, int cmd) {
BOOL inputResetsBlocked;
SystemParametersInfo(SPI_GETBLOCKSENDINPUTRESETS, 0, &inputResetsBlocked, 0);
setChanged((rfb::Server::acceptKeyEvents != isItemChecked(IDC_ACCEPT_KEYS)) ||
(SKeyboard::rawKeyboard != isItemChecked(IDC_RAW_KEYBOARD)) ||
(rfb::Server::acceptPointerEvents != isItemChecked(IDC_ACCEPT_PTR)) ||
(rfb::Server::acceptCutText != isItemChecked(IDC_ACCEPT_CUTTEXT)) ||
(rfb::Server::sendCutText != isItemChecked(IDC_SEND_CUTTEXT)) ||
(SDisplay::disableLocalInputs != isItemChecked(IDC_DISABLE_LOCAL_INPUTS)) ||
(enableAffectSSaver && (!inputResetsBlocked != isItemChecked(IDC_AFFECT_SCREENSAVER))));
return false;
}
bool onOk() {
regKey.setBool(_T("AcceptKeyEvents"), isItemChecked(IDC_ACCEPT_KEYS));
regKey.setBool(_T("RawKeyboard"), isItemChecked(IDC_RAW_KEYBOARD));
regKey.setBool(_T("AcceptPointerEvents"), isItemChecked(IDC_ACCEPT_PTR));
regKey.setBool(_T("AcceptCutText"), isItemChecked(IDC_ACCEPT_CUTTEXT));
regKey.setBool(_T("SendCutText"), isItemChecked(IDC_SEND_CUTTEXT));
regKey.setBool(_T("DisableLocalInputs"), isItemChecked(IDC_DISABLE_LOCAL_INPUTS));
if (enableAffectSSaver) {
BOOL blocked = !isItemChecked(IDC_AFFECT_SCREENSAVER);
SystemParametersInfo(SPI_SETBLOCKSENDINPUTRESETS, blocked, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}
return true;
}
protected:
RegKey regKey;
bool enableAffectSSaver;
};
};
};
#endif

247
win/vncconfig/Legacy.cxx Normal file
View File

@@ -0,0 +1,247 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <vncconfig/Legacy.h>
#include <rfb/LogWriter.h>
#include <rfb/Password.h>
#include <rfb_win32/CurrentUser.h>
using namespace rfb;
using namespace win32;
static LogWriter vlog("Legacy");
void LegacyPage::LoadPrefs()
{
// VNC 3.3.3R3 Preferences Algorithm, as described by vncProperties.cpp
// - Load user-specific settings, based on logged-on user name,
// from HKLM/Software/ORL/WinVNC3/<user>. If they don't exist,
// try again with username "Default".
// - Load system-wide settings from HKLM/Software/ORL/WinVNC3.
// - If AllowProperties is non-zero then load the user's own
// settings from HKCU/Software/ORL/WinVNC3.
// Get the name of the current user
TCharArray username;
try {
UserName name;
username.buf = name.takeBuf();
} catch (rdr::SystemException& e) {
if (e.err != ERROR_NOT_LOGGED_ON)
throw;
}
// Open and read the WinVNC3 registry key
allowProperties = true;
RegKey winvnc3;
try {
winvnc3.openKey(HKEY_LOCAL_MACHINE, _T("Software\\ORL\\WinVNC3"));
int debugMode = winvnc3.getInt(_T("DebugMode"), 0);
const char* debugTarget = 0;
if (debugMode & 2) debugTarget = "file";
if (debugMode & 4) debugTarget = "stderr";
if (debugTarget) {
char logSetting[32];
sprintf(logSetting, "*:%s:%d", debugTarget, winvnc3.getInt(_T("DebugLevel"), 0));
regKey.setString(_T("Log"), TStr(logSetting));
}
TCharArray authHosts;
authHosts.buf = winvnc3.getString(_T("AuthHosts"), 0);
if (authHosts.buf) {
CharArray newHosts;
newHosts.buf = strDup("");
// Reformat AuthHosts to Hosts. Wish I'd left the format the same. :( :( :(
try {
CharArray tmp(authHosts.buf);
while (tmp.buf) {
// Split the AuthHosts string into patterns to match
CharArray first;
rfb::strSplit(tmp.buf, ':', &first.buf, &tmp.buf);
if (strlen(first.buf)) {
int bits = 0;
CharArray pattern(1+4*4+4);
pattern.buf[0] = first.buf[0];
pattern.buf[1] = 0;
// Split the pattern into IP address parts and process
rfb::CharArray address;
address.buf = rfb::strDup(&first.buf[1]);
while (address.buf) {
rfb::CharArray part;
rfb::strSplit(address.buf, '.', &part.buf, &address.buf);
if (bits)
strcat(pattern.buf, ".");
if (strlen(part.buf) > 3)
throw rdr::Exception("Invalid IP address part");
if (strlen(part.buf) > 0) {
strcat(pattern.buf, part.buf);
bits += 8;
}
}
// Pad out the address specification if required
int addrBits = bits;
while (addrBits < 32) {
if (addrBits) strcat(pattern.buf, ".");
strcat(pattern.buf, "0");
addrBits += 8;
}
// Append the number of bits to match
char buf[4];
sprintf(buf, "/%d", bits);
strcat(pattern.buf, buf);
// Append this pattern to the Hosts value
int length = strlen(newHosts.buf) + strlen(pattern.buf) + 2;
CharArray tmpHosts(length);
strcpy(tmpHosts.buf, pattern.buf);
if (strlen(newHosts.buf)) {
strcat(tmpHosts.buf, ",");
strcat(tmpHosts.buf, newHosts.buf);
}
delete [] newHosts.buf;
newHosts.buf = tmpHosts.takeBuf();
}
}
// Finally, save the Hosts value
regKey.setString(_T("Hosts"), TStr(newHosts.buf));
} catch (rdr::Exception&) {
MsgBox(0, _T("Unable to convert AuthHosts setting to Hosts format."),
MB_ICONWARNING | MB_OK);
}
} else {
regKey.setString(_T("Hosts"), _T("+"));
}
regKey.setBool(_T("LocalHost"), winvnc3.getBool(_T("LoopbackOnly"), false));
// *** check AllowLoopback?
if (winvnc3.getBool(_T("AuthRequired"), true))
regKey.setString(_T("SecurityTypes"), _T("VncAuth"));
else
regKey.setString(_T("SecurityTypes"), _T("None"));
int connectPriority = winvnc3.getInt(_T("ConnectPriority"), 0);
regKey.setBool(_T("DisconnectClients"), connectPriority == 0);
regKey.setBool(_T("AlwaysShared"), connectPriority == 1);
regKey.setBool(_T("NeverShared"), connectPriority == 2);
} catch(rdr::Exception&) {
}
// Open the local, default-user settings
allowProperties = true;
try {
RegKey userKey;
userKey.openKey(winvnc3, _T("Default"));
vlog.info("loading Default prefs");
LoadUserPrefs(userKey);
} catch(rdr::Exception& e) {
vlog.error("error reading Default settings:%s", e.str());
}
// Open the local, user-specific settings
if (userSettings && username.buf) {
try {
RegKey userKey;
userKey.openKey(winvnc3, username.buf);
vlog.info("loading local User prefs");
LoadUserPrefs(userKey);
} catch(rdr::Exception& e) {
vlog.error("error reading local User settings:%s", e.str());
}
// Open the user's own settings
if (allowProperties) {
try {
RegKey userKey;
userKey.openKey(HKEY_CURRENT_USER, _T("Software\\ORL\\WinVNC3"));
vlog.info("loading global User prefs");
LoadUserPrefs(userKey);
} catch(rdr::Exception& e) {
vlog.error("error reading global User settings:%s", e.str());
}
}
}
// Disable the Options menu item if appropriate
regKey.setBool(_T("DisableOptions"), !allowProperties);
}
void LegacyPage::LoadUserPrefs(const RegKey& key)
{
if (key.getBool(_T("HTTPConnect"), true))
regKey.setInt(_T("HTTPPortNumber"), key.getInt(_T("PortNumber"), 5900)-100);
else
regKey.setInt(_T("HTTPPortNumber"), 0);
regKey.setInt(_T("PortNumber"), key.getBool(_T("SocketConnect")) ? key.getInt(_T("PortNumber"), 5900) : 0);
if (key.getBool(_T("AutoPortSelect"), false)) {
MsgBox(0, _T("The AutoPortSelect setting is not supported by this release.")
_T("The port number will default to 5900."),
MB_ICONWARNING | MB_OK);
regKey.setInt(_T("PortNumber"), 5900);
}
regKey.setInt(_T("IdleTimeout"), key.getInt(_T("IdleTimeout"), 0));
regKey.setBool(_T("RemoveWallpaper"), key.getBool(_T("RemoveWallpaper")));
regKey.setBool(_T("DisableEffects"), key.getBool(_T("DisableEffects")));
if (key.getInt(_T("QuerySetting"), 2) != 2) {
regKey.setBool(_T("QueryConnect"), key.getInt(_T("QuerySetting")) > 2);
MsgBox(0, _T("The QuerySetting option has been replaced by QueryConnect.")
_T("Please see the documentation for details of the QueryConnect option."),
MB_ICONWARNING | MB_OK);
}
regKey.setInt(_T("QueryTimeout"), key.getInt(_T("QueryTimeout"), 10));
ObfuscatedPasswd passwd;
key.getBinary(_T("Password"), (void**)&passwd.buf, &passwd.length, 0, 0);
regKey.setBinary(_T("Password"), passwd.buf, passwd.length);
bool enableInputs = key.getBool(_T("InputsEnabled"), true);
regKey.setBool(_T("AcceptKeyEvents"), enableInputs);
regKey.setBool(_T("AcceptPointerEvents"), enableInputs);
regKey.setBool(_T("AcceptCutText"), enableInputs);
regKey.setBool(_T("SendCutText"), enableInputs);
switch (key.getInt(_T("LockSetting"), 0)) {
case 0: regKey.setString(_T("DisconnectAction"), _T("None")); break;
case 1: regKey.setString(_T("DisconnectAction"), _T("Lock")); break;
case 2: regKey.setString(_T("DisconnectAction"), _T("Logoff")); break;
};
regKey.setBool(_T("DisableLocalInputs"), key.getBool(_T("LocalInputsDisabled"), false));
// *** ignore polling preferences
// PollUnderCursor, PollForeground, OnlyPollConsole, OnlyPollOnEvent
regKey.setBool(_T("UseHooks"), !key.getBool(_T("PollFullScreen"), false));
if (key.isValue(_T("AllowShutdown")))
MsgBox(0, _T("The AllowShutdown option is not supported by this release."), MB_ICONWARNING | MB_OK);
if (key.isValue(_T("AllowEditClients")))
MsgBox(0, _T("The AllowEditClients option is not supported by this release."), MB_ICONWARNING | MB_OK);
allowProperties = key.getBool(_T("AllowProperties"), allowProperties);
}

85
win/vncconfig/Legacy.h Normal file
View File

@@ -0,0 +1,85 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_LEGACY
#define WINVNCCONF_LEGACY
#include <windows.h>
#include <lmcons.h>
#include <vncconfig/resource.h>
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/MsgBox.h>
#include <rfb/ServerCore.h>
#include <rfb/Security.h>
namespace rfb {
namespace win32 {
class LegacyPage : public PropSheetPage {
public:
LegacyPage(const RegKey& rk, bool userSettings_)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_LEGACY)), regKey(rk), userSettings(userSettings_) {}
void initDialog() {
setItemChecked(IDC_PROTOCOL_3_3, rfb::Server::protocol3_3);
}
bool onCommand(int id, int cmd) {
switch (id) {
case IDC_LEGACY_IMPORT:
{
DWORD result = MsgBox(0,
_T("Importing your legacy VNC 3.3 settings will overwrite your existing settings.\n")
_T("Are you sure you wish to continue?"),
MB_ICONWARNING | MB_YESNO);
if (result == IDYES) {
LoadPrefs();
MsgBox(0, _T("Imported VNC 3.3 settings successfully."),
MB_ICONINFORMATION | MB_OK);
// Sleep to allow RegConfig thread to reload settings
Sleep(1000);
propSheet->reInitPages();
}
}
return true;
case IDC_PROTOCOL_3_3:
setChanged(isItemChecked(IDC_PROTOCOL_3_3) != rfb::Server::protocol3_3);
return false;
};
return false;
}
bool onOk() {
regKey.setBool(_T("Protocol3.3"), isItemChecked(IDC_PROTOCOL_3_3));
return true;
}
void LoadPrefs();
void LoadUserPrefs(const RegKey& key);
protected:
bool allowProperties;
RegKey regKey;
bool userSettings;
};
};
};
#endif

View File

@@ -0,0 +1,52 @@
/* Copyright (C) 2004-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <vncconfig/resource.h>
#include <vncconfig/PasswordDialog.h>
#include <rfb_win32/MsgBox.h>
#include <rfb/Password.h>
using namespace rfb;
using namespace win32;
PasswordDialog::PasswordDialog(const RegKey& rk, bool registryInsecure_)
: Dialog(GetModuleHandle(0)), regKey(rk), registryInsecure(registryInsecure_) {
}
bool PasswordDialog::showDialog(HWND owner) {
return Dialog::showDialog(MAKEINTRESOURCE(IDD_AUTH_VNC_PASSWD), owner);
}
bool PasswordDialog::onOk() {
TPlainPasswd password1(getItemString(IDC_PASSWORD1));
TPlainPasswd password2(getItemString(IDC_PASSWORD2));
if (_tcscmp(password1.buf, password2.buf) != 0) {
MsgBox(0, _T("The supplied passwords do not match"),
MB_ICONEXCLAMATION | MB_OK);
return false;
}
if (registryInsecure &&
(MsgBox(0, _T("Please note that your password cannot be stored securely on this system. ")
_T("Are you sure you wish to continue?"),
MB_YESNO | MB_ICONWARNING) == IDNO))
return false;
PlainPasswd password(strDup(password1.buf));
ObfuscatedPasswd obfPwd(password);
regKey.setBinary(_T("Password"), obfPwd.buf, obfPwd.length);
return true;
}

View File

@@ -0,0 +1,40 @@
/* Copyright (C) 2004-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_PASSWORD_DIALOG
#define WINVNCCONF_PASSWORD_DIALOG
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
namespace rfb {
namespace win32 {
class PasswordDialog : public Dialog {
public:
PasswordDialog(const RegKey& rk, bool registryInsecure_);
bool showDialog(HWND owner=0);
bool onOk();
protected:
const RegKey& regKey;
bool registryInsecure;
};
};
};
#endif

59
win/vncconfig/Sharing.h Normal file
View File

@@ -0,0 +1,59 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef WINVNCCONF_SHARING
#define WINVNCCONF_SHARING
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb/ServerCore.h>
namespace rfb {
namespace win32 {
class SharingPage : public PropSheetPage {
public:
SharingPage(const RegKey& rk)
: PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_SHARING)), regKey(rk) {}
void initDialog() {
setItemChecked(IDC_DISCONNECT_CLIENTS, rfb::Server::disconnectClients);
setItemChecked(IDC_SHARE_NEVER, rfb::Server::neverShared);
setItemChecked(IDC_SHARE_ALWAYS, rfb::Server::alwaysShared);
setItemChecked(IDC_SHARE_CLIENT, !(rfb::Server::neverShared || rfb::Server::alwaysShared));
}
bool onCommand(int id, int cmd) {
setChanged((isItemChecked(IDC_DISCONNECT_CLIENTS) != rfb::Server::disconnectClients) ||
(isItemChecked(IDC_SHARE_NEVER) != rfb::Server::neverShared) ||
(isItemChecked(IDC_SHARE_ALWAYS) != rfb::Server::alwaysShared));
return true;
}
bool onOk() {
regKey.setBool(_T("DisconnectClients"), isItemChecked(IDC_DISCONNECT_CLIENTS));
regKey.setBool(_T("AlwaysShared"), isItemChecked(IDC_SHARE_ALWAYS));
regKey.setBool(_T("NeverShared"), isItemChecked(IDC_SHARE_NEVER));
return true;
}
protected:
RegKey regKey;
};
};
};
#endif

94
win/vncconfig/resource.h Normal file
View File

@@ -0,0 +1,94 @@
// Used by vncconfig.rc
#include <rfb_win32/resource.h>
#define IDR_MANIFEST 1
#define IDI_ICON 101
#define IDD_DIALOG1 102
#define IDD_DIALOG2 103
#define IDD_CONNECTIONS 105
#define IDD_HOOKING 106
#define IDD_VNC_PASSWD 107
#define IDD_AUTH_VNC_PASSWD 107
#define IDD_LEGACY 108
#define IDD_CONN_HOST 109
#define IDD_SHARING 110
#define IDD_INPUTS 111
#define IDR_TRAY 112
#define IDD_ABOUT 113
#define IDI_CONNECTED 115
#define IDD_DESKTOP 116
#define IDC_EDIT1 1000
#define IDC_PORT 1000
#define IDC_PASSWORD1 1000
#define IDC_HOST_PATTERN 1000
#define IDC_AUTH_VNC_PASSWD 1009
#define IDC_USEHOOKS 1011
#define IDC_POLLCONSOLES 1012
#define IDC_COMPAREFB 1013
#define IDC_IDLE_TIMEOUT 1015
#define IDC_HOSTS 1016
#define IDC_HOST_ADD 1017
#define IDC_HOST_REMOVE 1018
#define IDC_HOST_UP 1019
#define IDC_BUTTON4 1020
#define IDC_HOST_DOWN 1020
#define IDC_AUTH_INPUTONLY_PASSWD 1020
#define IDC_HOST_EDIT 1021
#define IDC_PASSWORD2 1022
#define IDC_LEGACY_IMPORT 1023
#define IDC_ALLOW 1024
#define IDC_DENY 1025
#define IDC_SHARE_ALWAYS 1030
#define IDC_SHARE_NEVER 1031
#define IDC_SHARE_CLIENT 1032
#define IDC_DISCONNECT_CLIENTS 1033
#define IDC_ACCEPT_KEYS 1034
#define IDC_ACCEPT_PTR 1035
#define IDC_ACCEPT_CUTTEXT 1036
#define IDC_SEND_CUTTEXT 1037
#define IDC_PROTOCOL_3_3 1038
#define IDC_DESCRIPTION 1039
#define IDC_BUILDTIME 1040
#define IDC_VERSION 1041
#define IDC_COPYRIGHT 1042
#define IDC_HTTP_ENABLE 1043
#define IDC_HTTP_PORT 1044
#define IDC_BL_THRESHOLD 1046
#define IDC_BL_TIMEOUT 1047
#define IDC_AFFECT_SCREENSAVER 1048
#define IDC_LOCALHOST 1049
#define IDC_DISABLE_LOCAL_INPUTS 1050
#define IDC_QUERY_CONNECT 1055
#define IDC_DISCONNECT_NONE 1056
#define IDC_DISCONNECT_LOCK 1057
#define IDC_DISCONNECT_LOGOFF 1058
#define IDC_REMOVE_WALLPAPER 1059
#define IDC_DISABLE_EFFECTS 1061
#define IDC_CAPTUREBLT 1062
#define IDC_QUERY 1064
#define IDC_USEPOLLING 1066
#define IDC_QUERY_LOGGED_ON 1069
#define IDC_AUTH_ADMIN_PASSWD 1076
#define IDC_AUTH_VIEWONLY_PASSWD 1077
#define IDC_AUTH_ADMIN_ENABLE 1078
#define IDC_AUTH_VIEWONLY_ENABLE 1079
#define IDC_AUTH_INPUTONLY_ENABLE 1080
#define IDC_RFB_ENABLE 1082
#define IDC_LOAD_CERT 1087
#define IDC_LOAD_CERTKEY 1088
#define IDC_RAW_KEYBOARD 1089
#define ID_OPTIONS 40001
#define ID_CLOSE 40002
#define ID_ABOUT 40003
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 117
#define _APS_NEXT_COMMAND_VALUE 40004
#define _APS_NEXT_CONTROL_VALUE 1083
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

189
win/vncconfig/vncconfig.cxx Normal file
View File

@@ -0,0 +1,189 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public 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 <winsock2.h>
#include <windows.h>
#include <commctrl.h>
#include <string.h>
#include "resource.h"
#include <rfb/Logger_stdio.h>
#include <rfb/LogWriter.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/RegConfig.h>
#include <rfb_win32/CurrentUser.h>
using namespace rfb;
using namespace rfb::win32;
static LogWriter vlog("main");
#include <vncconfig/Authentication.h>
#include <vncconfig/Connections.h>
#include <vncconfig/Sharing.h>
#include <vncconfig/Hooking.h>
#include <vncconfig/Inputs.h>
#include <vncconfig/Legacy.h>
#include <vncconfig/Desktop.h>
TStr rfb::win32::AppName("KasmVNC Configuration");
#ifdef _DEBUG
BoolParameter captureDialogs("CaptureDialogs", "", false);
#endif
HKEY configKey = HKEY_CURRENT_USER;
void
processParams(int argc, char* argv[]) {
for (int i=1; i<argc; i++) {
if (strcasecmp(argv[i], "-service") == 0) {
configKey = HKEY_LOCAL_MACHINE;
} else if (strcasecmp(argv[i], "-user") == 0) {
configKey = HKEY_CURRENT_USER;
} else {
// Try to process <option>=<value>, or -<bool>
if (Configuration::setParam(argv[i], true))
continue;
// Try to process -<option> <value>
if ((argv[i][0] == '-') && (i+1 < argc)) {
if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
i++;
continue;
}
}
}
}
}
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, char* cmdLine, int cmdShow) {
// Configure debugging output
#ifdef _DEBUG
AllocConsole();
freopen("CONIN$","rb",stdin);
freopen("CONOUT$","wb",stdout);
freopen("CONOUT$","wb",stderr);
setbuf(stderr, 0);
initStdIOLoggers();
LogWriter vlog("main");
logParams.setParam("*:stderr:100");
vlog.info("Starting vncconfig applet");
#endif
Configuration::enableServerParams();
try {
try {
// Process command-line args
int argc = __argc;
char** argv = __argv;
processParams(argc, argv);
/* *** Required if we wish to use IP address control
INITCOMMONCONTROLSEX icce;
icce.dwSize = sizeof(icce);
icce.dwICC = ICC_INTERNET_CLASSES;
InitCommonControlsEx(&icce);
*/
// Create the required configuration registry key
RegKey rootKey;
rootKey.createKey(configKey, _T("Software\\KasmVNC\\WinVNC4"));
// Override whatever security it already had (NT only)
bool warnOnChangePassword = false;
try {
AccessEntries access;
Sid::Administrators adminSID;
Sid::SYSTEM systemSID;
access.addEntry(adminSID, KEY_ALL_ACCESS, GRANT_ACCESS);
access.addEntry(systemSID, KEY_ALL_ACCESS, GRANT_ACCESS);
UserSID userSID;
if (configKey == HKEY_CURRENT_USER)
access.addEntry(userSID, KEY_ALL_ACCESS, GRANT_ACCESS);
AccessControlList acl(CreateACL(access));
// Set the DACL, and don't allow the key to inherit its parent's DACL
rootKey.setDACL(acl, false);
} catch (rdr::SystemException& e) {
// Something weird happens on NT 4.0 SP5 but I can't reproduce it on other
// NT 4.0 service pack revisions.
if (e.err == ERROR_INVALID_PARAMETER) {
MsgBox(0, _T("Windows reported an error trying to secure the VNC Server settings for this user. ")
_T("Your settings may not be secure!"), MB_ICONWARNING | MB_OK);
} else if (e.err != ERROR_CALL_NOT_IMPLEMENTED &&
e.err != ERROR_NOT_LOGGED_ON) {
// If the call is not implemented, ignore the error and continue
throw;
}
warnOnChangePassword = true;
}
// Start a RegConfig thread, to load in existing settings
RegConfigThread config;
config.start(configKey, _T("Software\\KasmVNC\\WinVNC4"));
// Build the dialog
std::list<PropSheetPage*> pages;
SecPage auth(rootKey); pages.push_back(&auth);
auth.setWarnPasswdInsecure(warnOnChangePassword);
ConnectionsPage conn(rootKey); pages.push_back(&conn);
InputsPage inputs(rootKey); pages.push_back(&inputs);
SharingPage sharing(rootKey); pages.push_back(&sharing);
DesktopPage desktop(rootKey); pages.push_back(&desktop);
HookingPage hooks(rootKey); pages.push_back(&hooks);
LegacyPage legacy(rootKey, configKey == HKEY_CURRENT_USER); pages.push_back(&legacy);
// Load the default icon to use
HICON icon = (HICON)LoadImage(inst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
// Create the PropertySheet handler
const TCHAR* propSheetTitle = _T("VNC Server Properties (Service-Mode)");
if (configKey == HKEY_CURRENT_USER)
propSheetTitle = _T("VNC Server Properties (User-Mode)");
PropSheet sheet(inst, propSheetTitle, pages, icon);
#ifdef _DEBUG
vlog.debug("capture dialogs=%s", captureDialogs ? "true" : "false");
sheet.showPropSheet(0, true, false, captureDialogs);
#else
sheet.showPropSheet(0, true, false);
#endif
} catch (rdr::SystemException& e) {
switch (e.err) {
case ERROR_ACCESS_DENIED:
MsgBox(0, _T("You do not have sufficient access rights to run the VNC Configuration applet"),
MB_ICONSTOP | MB_OK);
return 1;
};
throw;
}
} catch (rdr::Exception& e) {
MsgBox(NULL, TStr(e.str()), MB_ICONEXCLAMATION | MB_OK);
return 1;
}
return 0;
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="4.0.0.26"
processorArchitecture="X86"
name="KasmVNC.vncconfig.exe"
type="win32"
/>
<description>.NET control deployment tool</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="4.0.0.26"
processorArchitecture="AMD64"
name="KasmVNC.vncconfig.exe"
type="win32"
/>
<description>.NET control deployment tool</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="AMD64"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

BIN
win/vncconfig/vncconfig.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

516
win/vncconfig/vncconfig.rc Normal file
View File

@@ -0,0 +1,516 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#include "resdefs.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.K.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON ICON DISCARDABLE "vncconfig.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SECURITY DIALOG DISCARDABLE 0, 0, 180, 220
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Security"
FONT 8, "MS Sans Serif"
BEGIN
GROUPBOX "Session encryption", IDC_STATIC, 7,10,120,60
CONTROL "None", IDC_ENC_NONE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
10,20,50,15
CONTROL "Anonymous TLS", IDC_ENC_TLS, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP, 10,35,80,15
CONTROL "TLS with X.509 certificates", IDC_ENC_X509, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP, 10,50,110,15
GROUPBOX "X.509 certificates", IDC_STATIC, 7,75,185,30
PUSHBUTTON "Load X.509 Certificate", IDC_LOAD_CERT, 10,85,80,15
PUSHBUTTON "Load X.509 Certificate key", IDC_LOAD_CERTKEY, 90,85,100,15
GROUPBOX "Authentication", IDC_STATIC, 7,110,170,60
CONTROL "None", IDC_AUTH_NONE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
10,120,50,15
CONTROL "Standard VNC", IDC_AUTH_VNC, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP, 10,135,80,15
PUSHBUTTON "Configure", IDC_AUTH_VNC_PASSWD, 100,135,61,15
/*
CONTROL "Plaintext", IDC_AUTH_PLAIN, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP, 10,150,70,15
*/
CONTROL "Prompt local user to accept connections",
IDC_QUERY_CONNECT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
7,170,181,15
CONTROL "Only prompt when there is a user logged on",
IDC_QUERY_LOGGED_ON, "Button", BS_AUTOCHECKBOX |
WS_TABSTOP,20,185,166,15
END
IDD_CONNECTIONS DIALOG DISCARDABLE 0, 0, 218, 198
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Connections"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Accept connections on port:",IDC_RFB_ENABLE,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,10,138,15
EDITTEXT IDC_PORT,150,10,61,15,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Disconnect idle clients after (seconds):",IDC_STATIC,7,
25,138,15,SS_CENTERIMAGE
EDITTEXT IDC_IDLE_TIMEOUT,150,25,61,15,ES_AUTOHSCROLL | ES_NUMBER
CONTROL "Serve Java viewer via HTTP on port:",IDC_HTTP_ENABLE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,138,15
EDITTEXT IDC_HTTP_PORT,150,40,61,15,ES_AUTOHSCROLL | ES_NUMBER
GROUPBOX "Access Control",IDC_STATIC,7,55,204,135
CONTROL "Only accept connections from the local machine",
IDC_LOCALHOST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,
70,190,15
LISTBOX IDC_HOSTS,15,90,130,95,LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
WS_TABSTOP
PUSHBUTTON "&Add",IDC_HOST_ADD,150,90,55,15
PUSHBUTTON "&Remove",IDC_HOST_REMOVE,150,110,55,15
PUSHBUTTON "Move Up",IDC_HOST_UP,150,130,55,15
PUSHBUTTON "Move Down",IDC_HOST_DOWN,150,150,55,15
PUSHBUTTON "&Edit",IDC_HOST_EDIT,150,170,55,15
END
IDD_HOOKING DIALOG DISCARDABLE 0, 0, 197, 101
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Capture Method"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Poll for changes to the desktop",IDC_USEPOLLING,"Button",
BS_AUTORADIOBUTTON | WS_GROUP,7,10,183,15
CONTROL "Use VNC hooks to track changes",IDC_USEHOOKS,"Button",
BS_AUTORADIOBUTTON,7,25,183,15
CONTROL "Poll console windows for updates",IDC_POLLCONSOLES,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,40,165,15
CONTROL "Capture alpha-blended windows",IDC_CAPTUREBLT,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,55,183,15
END
IDD_AUTH_VNC_PASSWD DIALOG DISCARDABLE 0, 0, 212, 70
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "VNC Server Password"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "New Password:",IDC_STATIC,7,10,63,15
EDITTEXT IDC_PASSWORD1,75,10,130,15,ES_PASSWORD | ES_AUTOHSCROLL
LTEXT "Confirm Password:",IDC_STATIC,7,30,63,14
EDITTEXT IDC_PASSWORD2,75,30,130,14,ES_PASSWORD | ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,100,50,50,15
PUSHBUTTON "Cancel",IDCANCEL,155,50,50,15
END
IDD_LEGACY DIALOG DISCARDABLE 0, 0, 166, 92
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Legacy"
FONT 8, "MS Sans Serif"
BEGIN
PUSHBUTTON "&Import VNC 3.3 Settings",IDC_LEGACY_IMPORT,7,10,92,20
CONTROL "Only use protocol version 3.3",IDC_PROTOCOL_3_3,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,35,152,15
END
IDD_CONN_HOST DIALOG DISCARDABLE 0, 0, 225, 57
STYLE DS_SYSMODAL | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "Specify Host IP Address Pattern"
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_HOST_PATTERN,65,5,100,15,ES_AUTOHSCROLL
CONTROL "&Allow",IDC_ALLOW,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,7,5,53,15
CONTROL "&Deny",IDC_DENY,"Button",BS_AUTORADIOBUTTON,7,20,53,15
CONTROL "Query",IDC_QUERY,"Button",BS_AUTORADIOBUTTON,7,35,53,15
DEFPUSHBUTTON "OK",IDOK,115,35,50,15
PUSHBUTTON "Cancel",IDCANCEL,170,35,50,15
LTEXT "e.g. 192.168.0.0/16",IDC_STATIC,65,20,100,15
END
IDD_SHARING DIALOG DISCARDABLE 0, 0, 186, 95
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Sharing"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Always treat new connections as shared",
IDC_SHARE_ALWAYS,"Button",BS_AUTORADIOBUTTON | WS_GROUP,
7,10,172,15
CONTROL "Never treat new connections as shared",IDC_SHARE_NEVER,
"Button",BS_AUTORADIOBUTTON,7,25,172,15
CONTROL "Use client's preferred sharing setting",
IDC_SHARE_CLIENT,"Button",BS_AUTORADIOBUTTON,7,40,172,15
CONTROL "Non-shared connections replace existing ones",
IDC_DISCONNECT_CLIENTS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,7,55,172,15
END
IDD_INPUTS DIALOG DISCARDABLE 0, 0, 186, 119
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Inputs"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Accept pointer events from clients",IDC_ACCEPT_PTR,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,10,172,15
CONTROL "Accept keyboard events from clients",IDC_ACCEPT_KEYS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,25,172,15
CONTROL "Send raw keyboard events to applications",IDC_RAW_KEYBOARD,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,172,15
CONTROL "Accept clipboard updates from clients",
IDC_ACCEPT_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
7,55,172,15
CONTROL "Send clipboard updates to clients",IDC_SEND_CUTTEXT,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,70,172,15
CONTROL "Allow input events to affect the screen-saver",
IDC_AFFECT_SCREENSAVER,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,7,85,172,15
CONTROL "Disable local inputs while server is in use",
IDC_DISABLE_LOCAL_INPUTS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,7,110,172,15
END
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 300, 92
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "About KasmVNC Config for Windows"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,245,70,47,15
ICON IDI_ICON,IDC_STATIC,7,7,20,20
LTEXT ">appname<",IDC_DESCRIPTION,40,7,125,18
LTEXT ">version<",IDC_VERSION,165,7,77,18
LTEXT ">buildtime<",IDC_BUILDTIME,40,25,202,15
LTEXT ">copyright<",IDC_COPYRIGHT,40,40,256,15
LTEXT "See http://kasmweb.com for more information on KasmVNC.",
IDC_STATIC,40,55,202,15
END
IDD_DESKTOP DIALOG DISCARDABLE 0, 0, 185, 137
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CONTROL | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Desktop"
FONT 8, "MS Sans Serif"
BEGIN
GROUPBOX "While connected",IDC_STATIC,7,5,171,45
CONTROL "Remove wallpaper",IDC_REMOVE_WALLPAPER,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,15,155,15
CONTROL "Disable user interface effects",IDC_DISABLE_EFFECTS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,30,155,14
GROUPBOX "When last client disconnects",IDC_STATIC,7,55,171,60
CONTROL "Do nothing",IDC_DISCONNECT_NONE,"Button",
BS_AUTORADIOBUTTON,15,65,155,15
CONTROL "Lock workstation",IDC_DISCONNECT_LOCK,"Button",
BS_AUTORADIOBUTTON,15,80,155,15
CONTROL "Logoff user",IDC_DISCONNECT_LOGOFF,"Button",
BS_AUTORADIOBUTTON,15,95,155,15
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_AUTHENTICATION, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 186
VERTGUIDE, 20
VERTGUIDE, 49
VERTGUIDE, 120
VERTGUIDE, 125
TOPMARGIN, 7
BOTTOMMARGIN, 128
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 30
HORZGUIDE, 45
HORZGUIDE, 50
HORZGUIDE, 65
HORZGUIDE, 70
HORZGUIDE, 85
HORZGUIDE, 90
HORZGUIDE, 105
HORZGUIDE, 110
HORZGUIDE, 125
END
IDD_CONNECTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 211
VERTGUIDE, 15
VERTGUIDE, 145
VERTGUIDE, 150
VERTGUIDE, 205
TOPMARGIN, 7
BOTTOMMARGIN, 191
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 40
HORZGUIDE, 55
HORZGUIDE, 70
HORZGUIDE, 85
HORZGUIDE, 90
HORZGUIDE, 105
HORZGUIDE, 110
HORZGUIDE, 125
HORZGUIDE, 130
HORZGUIDE, 145
HORZGUIDE, 150
HORZGUIDE, 165
HORZGUIDE, 170
HORZGUIDE, 185
HORZGUIDE, 190
END
IDD_HOOKING, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 190
VERTGUIDE, 25
TOPMARGIN, 7
BOTTOMMARGIN, 94
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 40
HORZGUIDE, 55
HORZGUIDE, 70
HORZGUIDE, 85
END
IDD_AUTH_VNC_PASSWD, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 205
VERTGUIDE, 70
VERTGUIDE, 75
VERTGUIDE, 90
VERTGUIDE, 100
VERTGUIDE, 150
VERTGUIDE, 155
VERTGUIDE, 205
TOPMARGIN, 7
BOTTOMMARGIN, 65
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 30
HORZGUIDE, 44
HORZGUIDE, 50
HORZGUIDE, 65
END
IDD_LEGACY, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 159
TOPMARGIN, 7
BOTTOMMARGIN, 85
HORZGUIDE, 10
HORZGUIDE, 30
HORZGUIDE, 35
HORZGUIDE, 50
END
IDD_CONN_HOST, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 220
VERTGUIDE, 60
VERTGUIDE, 65
VERTGUIDE, 115
VERTGUIDE, 165
VERTGUIDE, 170
TOPMARGIN, 5
BOTTOMMARGIN, 50
HORZGUIDE, 20
HORZGUIDE, 35
END
IDD_SHARING, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 88
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 40
HORZGUIDE, 55
HORZGUIDE, 70
END
IDD_INPUTS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 112
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 40
HORZGUIDE, 55
HORZGUIDE, 70
HORZGUIDE, 85
HORZGUIDE, 95
HORZGUIDE, 110
END
IDD_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 242
VERTGUIDE, 40
VERTGUIDE, 165
VERTGUIDE, 195
TOPMARGIN, 7
BOTTOMMARGIN, 85
HORZGUIDE, 7
HORZGUIDE, 25
HORZGUIDE, 40
HORZGUIDE, 55
HORZGUIDE, 70
END
IDD_DESKTOP, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 182
TOPMARGIN, 7
BOTTOMMARGIN, 32
END
END
#endif // APSTUDIO_INVOKED
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION __RCVERSION
PRODUCTVERSION __RCVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080904b0"
BEGIN
VALUE "Comments", "\0"
VALUE "CompanyName", "KasmVNC Project\0"
#ifdef WIN64
VALUE "FileDescription", "KasmVNC Server Configuration Applet for Win64\0"
VALUE "ProductName", "KasmVNC Server Configuration Applet for Win64\0"
#else
VALUE "FileDescription", "KasmVNC Server Configuration Applet for Win32\0"
VALUE "ProductName", "KasmVNC Server Configuration Applet for Win32\0"
#endif
VALUE "FileVersion", __RCVERSIONSTR
VALUE "InternalName", "vncconfig\0"
VALUE "LegalCopyright", "Copyright (C) 2020 KasmVNC Team and many others (see README.md)\0"
VALUE "LegalTrademarks", "KasmVNC\0"
VALUE "OriginalFilename", "vncconfig.exe\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductVersion", __VERSIONSTR
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x809, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// 24
//
#ifdef WIN64
IDR_MANIFEST 24 DISCARDABLE "vncconfig.exe.manifest64"
#else
IDR_MANIFEST 24 DISCARDABLE "vncconfig.exe.manifest"
#endif
#endif // English (U.K.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,56 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- AddnewClientDialog.h
#ifndef __WINVNC_ADD_NEW_CLIENT_DIALOG_H__
#define __WINVNC_ADD_NEW_CLIENT_DIALOG_H__
#include <winvnc/resource.h>
#include <rfb_win32/Dialog.h>
//#include <rfb_win32/TCharArray.h>
namespace winvnc {
class AddNewClientDialog : public rfb::win32::Dialog {
public:
AddNewClientDialog() : Dialog(GetModuleHandle(0)) {}
// - Show the dialog and return true if OK was clicked,
// false in case of error or Cancel
virtual bool showDialog() {
return Dialog::showDialog(MAKEINTRESOURCE(IDD_ADD_NEW_CLIENT));
}
const char* getHostName() const {return hostName.buf;}
protected:
// Dialog methods (protected)
virtual void initDialog() {
if (hostName.buf)
setItemString(IDC_HOST, rfb::TStr(hostName.buf));
}
virtual bool onOk() {
hostName.replaceBuf(rfb::strDup(rfb::CStr(getItemString(IDC_HOST))));
return true;
}
rfb::CharArray hostName;
};
};
#endif

Some files were not shown because too many files have changed in this diff Show More