Initial commit
This commit is contained in:
15
win/CMakeLists.txt
Normal file
15
win/CMakeLists.txt
Normal 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()
|
||||
47
win/logmessages/messages.h
Normal file
47
win/logmessages/messages.h
Normal 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
|
||||
|
||||
7
win/logmessages/messages.mc
Normal file
7
win/logmessages/messages.mc
Normal file
@@ -0,0 +1,7 @@
|
||||
MessageId=0x1
|
||||
Severity=Success
|
||||
SymbolicName=VNC4LogMessage
|
||||
Language=English
|
||||
%1: %2
|
||||
|
||||
|
||||
2
win/logmessages/messages.rc
Normal file
2
win/logmessages/messages.rc
Normal file
@@ -0,0 +1,2 @@
|
||||
LANGUAGE 0x9,0x1
|
||||
1 11 MSG00001.bin
|
||||
3
win/resdefs.h.in
Normal file
3
win/resdefs.h.in
Normal file
@@ -0,0 +1,3 @@
|
||||
#define __VERSIONSTR "@VERSION@\0"
|
||||
#define __RCVERSION @RCVERSION@
|
||||
#define __RCVERSIONSTR "@RCVERSION@\0"
|
||||
49
win/rfb_win32/AboutDialog.cxx
Normal file
49
win/rfb_win32/AboutDialog.cxx
Normal 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")));
|
||||
}
|
||||
55
win/rfb_win32/AboutDialog.h
Normal file
55
win/rfb_win32/AboutDialog.h
Normal 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
|
||||
48
win/rfb_win32/BitmapInfo.h
Normal file
48
win/rfb_win32/BitmapInfo.h
Normal 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
|
||||
40
win/rfb_win32/CMakeLists.txt
Normal file
40
win/rfb_win32/CMakeLists.txt
Normal 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)
|
||||
271
win/rfb_win32/CleanDesktop.cxx
Normal file
271
win/rfb_win32/CleanDesktop.cxx
Normal 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());
|
||||
}
|
||||
}
|
||||
57
win/rfb_win32/CleanDesktop.h
Normal file
57
win/rfb_win32/CleanDesktop.h
Normal 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
201
win/rfb_win32/Clipboard.cxx
Normal 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
66
win/rfb_win32/Clipboard.h
Normal 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__
|
||||
46
win/rfb_win32/CompatibleBitmap.h
Normal file
46
win/rfb_win32/CompatibleBitmap.h
Normal 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
|
||||
40
win/rfb_win32/ComputerName.h
Normal file
40
win/rfb_win32/ComputerName.h
Normal 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
|
||||
121
win/rfb_win32/CurrentUser.cxx
Normal file
121
win/rfb_win32/CurrentUser.cxx
Normal 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));
|
||||
}
|
||||
84
win/rfb_win32/CurrentUser.h
Normal file
84
win/rfb_win32/CurrentUser.h
Normal 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
|
||||
180
win/rfb_win32/DIBSectionBuffer.cxx
Normal file
180
win/rfb_win32/DIBSectionBuffer.cxx
Normal 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);
|
||||
}
|
||||
}
|
||||
63
win/rfb_win32/DIBSectionBuffer.h
Normal file
63
win/rfb_win32/DIBSectionBuffer.h
Normal 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__
|
||||
200
win/rfb_win32/DeviceContext.cxx
Normal file
200
win/rfb_win32/DeviceContext.cxx
Normal 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);
|
||||
}
|
||||
86
win/rfb_win32/DeviceContext.h
Normal file
86
win/rfb_win32/DeviceContext.h
Normal 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
|
||||
323
win/rfb_win32/DeviceFrameBuffer.cxx
Normal file
323
win/rfb_win32/DeviceFrameBuffer.cxx
Normal 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());
|
||||
}
|
||||
}
|
||||
103
win/rfb_win32/DeviceFrameBuffer.h
Normal file
103
win/rfb_win32/DeviceFrameBuffer.h
Normal 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 ®ion);
|
||||
|
||||
// - 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
385
win/rfb_win32/Dialog.cxx
Normal 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
159
win/rfb_win32/Dialog.h
Normal 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__
|
||||
103
win/rfb_win32/EventManager.cxx
Normal file
103
win/rfb_win32/EventManager.cxx
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
win/rfb_win32/EventManager.h
Normal file
77
win/rfb_win32/EventManager.h
Normal 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
43
win/rfb_win32/Handle.h
Normal 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
44
win/rfb_win32/IconInfo.h
Normal 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
|
||||
70
win/rfb_win32/IntervalTimer.h
Normal file
70
win/rfb_win32/IntervalTimer.h
Normal 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__
|
||||
113
win/rfb_win32/LaunchProcess.cxx
Normal file
113
win/rfb_win32/LaunchProcess.cxx
Normal 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;
|
||||
}
|
||||
71
win/rfb_win32/LaunchProcess.h
Normal file
71
win/rfb_win32/LaunchProcess.h
Normal 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
|
||||
103
win/rfb_win32/ListViewControl.cxx
Normal file
103
win/rfb_win32/ListViewControl.cxx
Normal 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()
|
||||
{
|
||||
}
|
||||
35
win/rfb_win32/ListViewControl.h
Normal file
35
win/rfb_win32/ListViewControl.h
Normal 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
45
win/rfb_win32/LocalMem.h
Normal 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
|
||||
40
win/rfb_win32/ModuleFileName.h
Normal file
40
win/rfb_win32/ModuleFileName.h
Normal 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
|
||||
138
win/rfb_win32/MonitorInfo.cxx
Normal file
138
win/rfb_win32/MonitorInfo.cxx
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
55
win/rfb_win32/MonitorInfo.h
Normal file
55
win/rfb_win32/MonitorInfo.h
Normal 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
63
win/rfb_win32/MsgBox.h
Normal 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
118
win/rfb_win32/MsgWindow.cxx
Normal 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
53
win/rfb_win32/MsgWindow.h
Normal 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
113
win/rfb_win32/RegConfig.cxx
Normal 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
85
win/rfb_win32/RegConfig.h
Normal 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
311
win/rfb_win32/Registry.cxx
Normal 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
112
win/rfb_win32/Registry.h
Normal 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
509
win/rfb_win32/SDisplay.cxx
Normal 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
165
win/rfb_win32/SDisplay.h
Normal 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__
|
||||
82
win/rfb_win32/SDisplayCorePolling.cxx
Normal file
82
win/rfb_win32/SDisplayCorePolling.cxx
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
75
win/rfb_win32/SDisplayCorePolling.h
Normal file
75
win/rfb_win32/SDisplayCorePolling.h
Normal 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
|
||||
74
win/rfb_win32/SDisplayCoreWMHooks.cxx
Normal file
74
win/rfb_win32/SDisplayCoreWMHooks.cxx
Normal 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();
|
||||
}
|
||||
68
win/rfb_win32/SDisplayCoreWMHooks.h
Normal file
68
win/rfb_win32/SDisplayCoreWMHooks.h
Normal 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
490
win/rfb_win32/SInput.cxx
Normal 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
69
win/rfb_win32/SInput.h
Normal 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
182
win/rfb_win32/Security.cxx
Normal 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
123
win/rfb_win32/Security.h
Normal 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
|
||||
217
win/rfb_win32/SecurityPage.cxx
Normal file
217
win/rfb_win32/SecurityPage.cxx
Normal 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;
|
||||
}
|
||||
|
||||
62
win/rfb_win32/SecurityPage.h
Normal file
62
win/rfb_win32/SecurityPage.h
Normal 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
476
win/rfb_win32/Service.cxx
Normal 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
123
win/rfb_win32/Service.h
Normal 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__
|
||||
211
win/rfb_win32/SocketManager.cxx
Normal file
211
win/rfb_win32/SocketManager.cxx
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
win/rfb_win32/SocketManager.h
Normal file
90
win/rfb_win32/SocketManager.h
Normal 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
|
||||
85
win/rfb_win32/TCharArray.cxx
Normal file
85
win/rfb_win32/TCharArray.cxx
Normal 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
135
win/rfb_win32/TCharArray.h
Normal 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
89
win/rfb_win32/TrayIcon.h
Normal 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
|
||||
|
||||
|
||||
64
win/rfb_win32/TsSessions.cxx
Normal file
64
win/rfb_win32/TsSessions.cxx
Normal 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();
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
61
win/rfb_win32/TsSessions.h
Normal file
61
win/rfb_win32/TsSessions.h
Normal 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
|
||||
49
win/rfb_win32/WMCursor.cxx
Normal file
49
win/rfb_win32/WMCursor.cxx
Normal 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
59
win/rfb_win32/WMCursor.h
Normal 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
386
win/rfb_win32/WMHooks.cxx
Normal 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
78
win/rfb_win32/WMHooks.h
Normal 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__
|
||||
51
win/rfb_win32/WMNotifier.cxx
Normal file
51
win/rfb_win32/WMNotifier.cxx
Normal 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);
|
||||
}
|
||||
67
win/rfb_win32/WMNotifier.h
Normal file
67
win/rfb_win32/WMNotifier.h
Normal 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__
|
||||
85
win/rfb_win32/WMPoller.cxx
Normal file
85
win/rfb_win32/WMPoller.cxx
Normal 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
62
win/rfb_win32/WMPoller.h
Normal 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__
|
||||
58
win/rfb_win32/WMShatter.cxx
Normal file
58
win/rfb_win32/WMShatter.cxx
Normal 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
50
win/rfb_win32/WMShatter.h
Normal 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__
|
||||
67
win/rfb_win32/WMWindowCopyRect.cxx
Normal file
67
win/rfb_win32/WMWindowCopyRect.cxx
Normal 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;
|
||||
}
|
||||
53
win/rfb_win32/WMWindowCopyRect.h
Normal file
53
win/rfb_win32/WMWindowCopyRect.h
Normal 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
115
win/rfb_win32/Win32Util.cxx
Normal 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
55
win/rfb_win32/Win32Util.h
Normal 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
149
win/rfb_win32/keymap.h
Normal 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
37
win/rfb_win32/resource.h
Normal 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
|
||||
189
win/vncconfig/Authentication.h
Normal file
189
win/vncconfig/Authentication.h
Normal 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
|
||||
13
win/vncconfig/CMakeLists.txt
Normal file
13
win/vncconfig/CMakeLists.txt
Normal 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
303
win/vncconfig/Connections.h
Normal 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
80
win/vncconfig/Desktop.h
Normal 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
77
win/vncconfig/Hooking.h
Normal 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
85
win/vncconfig/Inputs.h
Normal 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
247
win/vncconfig/Legacy.cxx
Normal 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
85
win/vncconfig/Legacy.h
Normal 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
|
||||
52
win/vncconfig/PasswordDialog.cxx
Normal file
52
win/vncconfig/PasswordDialog.cxx
Normal 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;
|
||||
}
|
||||
40
win/vncconfig/PasswordDialog.h
Normal file
40
win/vncconfig/PasswordDialog.h
Normal 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
59
win/vncconfig/Sharing.h
Normal 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
94
win/vncconfig/resource.h
Normal 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
189
win/vncconfig/vncconfig.cxx
Normal 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;
|
||||
}
|
||||
22
win/vncconfig/vncconfig.exe.manifest
Normal file
22
win/vncconfig/vncconfig.exe.manifest
Normal 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>
|
||||
22
win/vncconfig/vncconfig.exe.manifest64
Normal file
22
win/vncconfig/vncconfig.exe.manifest64
Normal 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
BIN
win/vncconfig/vncconfig.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
516
win/vncconfig/vncconfig.rc
Normal file
516
win/vncconfig/vncconfig.rc
Normal 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
|
||||
|
||||
56
win/winvnc/AddNewClientDialog.h
Normal file
56
win/winvnc/AddNewClientDialog.h
Normal 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
Reference in New Issue
Block a user