cloudstack/thirdparty/vnc/viewer/AxVncViewer/ClientConnection.cpp

6412 lines
185 KiB
C++
Raw Blame History

// Copyright (C) 2002 Ultr@VNC Team Members. All Rights Reserved.
//
// Copyright (C) 2000-2002 Const Kaplinsky. All Rights Reserved.
//
// Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
//
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of the VNC system.
//
// The VNC system is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// If the source code for the VNC system is not available from the place
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
// the authors on vnc@uk.research.att.com for information on obtaining it.
// Many thanks to Randy Brown <rgb@inven.com> for providing the 3-button
// emulation code.
// This is the main source for a ClientConnection object.
// It handles almost everything to do with a connection to a server.
// The decoding of specific rectangle encodings is done in separate files.
#define _WIN32_WINDOWS 0x0410
#define WINVER 0x0400
#include "stdhdrs.h"
#include "vncviewer.h"
#ifdef UNDER_CE
#include "omnithreadce.h"
#define SD_BOTH 0x02
#else
#include "omnithread.h"
#endif
#include "ClientConnection.h"
#include "SessionDialog.h"
#include "AuthDialog.h"
#include "AboutBox.h"
#include "LowLevelHook.h"
#include "Exception.h"
extern "C" {
#include "vncauth.h"
}
#include "rdr/FdInStream.h"
#include "rdr/ZlibInStream.h"
#include "rdr/Exception.h"
#include "rfb/dh.h"
#include "DSMPlugin/DSMPlugin.h" // sf@200
#include "Log.h"
extern Log vnclog;
#define INITIALNETBUFSIZE 4096
#define MAX_ENCODINGS (LASTENCODING+10)
#define VWR_WND_CLASS_NAME _T("VNCviewer")
#define VWR_WND_CLASS_NAME_VIEWER _T("VNCviewerwindow")
#define SESSION_MRU_KEY_NAME _T("Software\\ORL\\VNCviewer\\MRU")
const UINT FileTransferSendPacketMessage = RegisterWindowMessage("UltraVNC.Viewer.FileTransferSendPacketMessage");
extern bool g_passwordfailed;
#ifdef _ULTRAVNCAX_
static HWND GetTopMostWnd( HWND h )
{
if ( h == NULL )
return NULL;
while( 1 )
{
HWND prev = h;
h = GetParent( h );
if ( h == NULL )
return prev;
}
}
#endif
/*
* Macro to compare pixel formats.
*/
#define PF_EQ(x,y) \
((x.bitsPerPixel == y.bitsPerPixel) && \
(x.depth == y.depth) && \
((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
(x.trueColour == y.trueColour) && \
(!x.trueColour || ((x.redMax == y.redMax) && \
(x.greenMax == y.greenMax) && \
(x.blueMax == y.blueMax) && \
(x.redShift == y.redShift) && \
(x.greenShift == y.greenShift) && \
(x.blueShift == y.blueShift))))
const rfbPixelFormat vnc8bitFormat = {8,8,0,1,7,7,3,0,3,6, 0, 0}; // 256 colors
const rfbPixelFormat vnc8bitFormat_64 = {8,6,0,1,3,3,3,4,2,0, 0, 0} ; // 64 colors
const rfbPixelFormat vnc8bitFormat_8 = {8,3,0,1,1,1,1,2,1,0, 0, 0} ; // 8 colors
const rfbPixelFormat vnc8bitFormat_8Grey = {8,8,0,1,7,7,3,0,3,6, 1, 0} ; // 8 colors-Dark Scale
const rfbPixelFormat vnc8bitFormat_4Grey = {8,6,0,1,3,3,3,4,2,0, 1, 0} ; // 4 colors-Grey Scale
const rfbPixelFormat vnc8bitFormat_2Grey = {8,3,0,1,1,1,1,2,1,0, 1, 0} ; // 2 colors-Grey Scale
const rfbPixelFormat vnc16bitFormat = {16,16,0,1,63,31,31,0,6,11, 0, 0};
//static LRESULT CALLBACK ClientConnection::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
extern HWND currentHWND;
extern char sz_L1[64];
extern char sz_L2[64];
extern char sz_L3[64];
extern char sz_L4[64];
extern char sz_L5[64];
extern char sz_L6[64];
extern char sz_L7[64];
extern char sz_L8[64];
extern char sz_L9[64];
extern char sz_L10[64];
extern char sz_L11[64];
extern char sz_L12[64];
extern char sz_L13[64];
extern char sz_L14[64];
extern char sz_L15[64];
extern char sz_L16[64];
extern char sz_L17[64];
extern char sz_L18[64];
extern char sz_L19[64];
extern char sz_L20[64];
extern char sz_L21[64];
extern char sz_L22[64];
extern char sz_L23[64];
extern char sz_L24[64];
extern char sz_L25[64];
extern char sz_L26[64];
extern char sz_L27[64];
extern char sz_L28[64];
extern char sz_L29[64];
extern char sz_L30[64];
extern char sz_L31[64];
extern char sz_L32[64];
extern char sz_L33[64];
extern char sz_L34[64];
extern char sz_L35[64];
extern char sz_L36[64];
extern char sz_L37[64];
extern char sz_L38[64];
extern char sz_L39[64];
extern char sz_L40[64];
extern char sz_L41[64];
extern char sz_L42[64];
extern char sz_L43[64];
extern char sz_L44[64];
extern char sz_L45[64];
extern char sz_L46[64];
extern char sz_L47[64];
extern char sz_L48[64];
extern char sz_L49[64];
extern char sz_L50[64];
extern char sz_L51[64];
extern char sz_L52[64];
extern char sz_L53[64];
extern char sz_L54[64];
extern char sz_L55[64];
extern char sz_L56[64];
extern char sz_L57[64];
extern char sz_L58[64];
extern char sz_L59[64];
extern char sz_L60[64];
extern char sz_L61[64];
extern char sz_L62[64];
extern char sz_L63[64];
extern char sz_L64[64];
extern char sz_L65[64];
extern char sz_L66[64];
extern char sz_L67[64];
extern char sz_L68[64];
extern char sz_L69[64];
extern char sz_L70[64];
extern char sz_L71[64];
extern char sz_L72[64];
extern char sz_L73[64];
extern char sz_L74[64];
extern char sz_L75[64];
extern char sz_L76[64];
extern char sz_L77[64];
extern char sz_L78[64];
extern char sz_L79[64];
extern char sz_L80[64];
extern char sz_L81[64];
extern char sz_L82[64];
extern char sz_L83[64];
extern char sz_L84[64];
extern char sz_L85[64];
extern char sz_L86[64];
extern char sz_L87[64];
extern char sz_L88[64];
extern char sz_L89[64];
extern char sz_L90[64];
extern char sz_L91[64];
extern char sz_L92[64];
extern char sz_F1[64];
extern char sz_F5[128];
extern char sz_F6[64];
extern bool command_line;
// *************************************************************************
// A Client connection involves two threads - the main one which sets up
// connections and processes window messages and inputs, and a
// client-specific one which receives, decodes and draws output data
// from the remote server.
// This first section contains bits which are generally called by the main
// program thread.
// *************************************************************************
ClientConnection::ClientConnection(VNCviewerApp *pApp)
: fis(0), zis(0)
{
Init(pApp);
memset(m_strUserName, 0, sizeof(m_strUserName));
memset(m_strPassword, 0, sizeof(m_strPassword));
}
ClientConnection::ClientConnection(VNCviewerApp *pApp, SOCKET sock)
: fis(0), zis(0)
{
Init(pApp);
memset(m_strUserName, 0, sizeof(m_strUserName));
memset(m_strPassword, 0, sizeof(m_strPassword));
if (m_opts.autoDetect)
{
m_opts.m_Use8Bit = rfbPF256Colors; //true;
m_opts.m_fEnableCache = true; // sf@2002
}
m_sock = sock;
m_serverInitiated = true;
struct sockaddr_in svraddr;
int sasize = sizeof(svraddr);
if (getpeername(sock, (struct sockaddr *) &svraddr,
&sasize) != SOCKET_ERROR) {
_stprintf(m_host, _T("%d.%d.%d.%d"),
svraddr.sin_addr.S_un.S_un_b.s_b1,
svraddr.sin_addr.S_un.S_un_b.s_b2,
svraddr.sin_addr.S_un.S_un_b.s_b3,
svraddr.sin_addr.S_un.S_un_b.s_b4);
m_port = svraddr.sin_port;
} else {
_tcscpy(m_host,sz_L1);
m_port = 0;
};
}
ClientConnection::ClientConnection(VNCviewerApp *pApp, LPTSTR host, int port, LPTSTR pszUser, LPTSTR pszPassword, LPTSTR pszProxy,
HWND rootHwnd, HWND* pHwndAppFrame)
: fis(0), zis(0)
{
Init(pApp);
memset(m_strUserName, 0, sizeof(m_strUserName));
memset(m_strPassword, 0, sizeof(m_strPassword));
#ifdef _ULTRAVNCAX_
m_hwndAx = rootHwnd;
m_pHwndAppFrame = pHwndAppFrame;
#endif
if (m_opts.autoDetect)
{
m_opts.m_Use8Bit = rfbPF256Colors; //true;
m_opts.m_fEnableCache = true; // sf@2002
}
_tcsncpy(m_host, host, MAX_HOST_NAME_LEN);
m_port = port;
if (pszProxy && strlen(pszProxy) > 0) {
::ParseDisplay((CHAR*)pszProxy, m_proxyhost, MAX_HOST_NAME_LEN-1, &m_proxyport);
m_fUseProxy = true;
} else {
m_fUseProxy = false;
}
if(pszUser != NULL)
strncpy(m_strUserName, pszUser, sizeof(m_strUserName) - 1);;
if(pszPassword != NULL)
strncpy(m_strPassword, pszPassword, sizeof(m_strPassword));
}
void ClientConnection::Init(VNCviewerApp *pApp)
{
Pressed_Cancel=false;
saved_set=false;
m_hwnd = 0;
m_desktopName = NULL;
m_port = -1;
m_proxyport = -1;
// m_proxy = 0;
m_serverInitiated = false;
m_netbuf = NULL;
m_netbufsize = 0;
m_zlibbuf = NULL;
m_zlibbufsize = 0;
m_decompStreamInited = false;
m_hwndNextViewer = NULL;
m_pApp = pApp;
m_dormant = false;
m_hBitmapDC = NULL;
m_hBitmap = NULL;
m_hCacheBitmapDC = NULL;
m_hCacheBitmap = NULL;
m_hPalette = NULL;
m_encPasswd[0] = '\0';
m_clearPasswd[0] = '\0'; // Modif sf@2002
// static window
m_BytesSend=0;
m_BytesRead=0;
// We take the initial conn options from the application defaults
m_opts = m_pApp->m_options;
m_sock = INVALID_SOCKET;
m_bKillThread = false;
#ifdef _ULTRAVNCAX_
m_threadStarted = false; // BUG ?
#else
m_threadStarted = true;
#endif
m_running = false;
m_pendingFormatChange = false;
// sf@2002 - v1.1.2 - Data Stream Modification Plugin handling
m_nTO = 1;
m_pDSMPlugin = new CDSMPlugin();
m_fUsePlugin = false;
m_fUseProxy = false;
m_pNetRectBuf = NULL;
m_fReadFromNetRectBuf = false; //
m_nNetRectBufOffset = 0;
m_nReadSize = 0;
m_nNetRectBufSize = 0;
m_pZRLENetRectBuf = NULL;
m_fReadFromZRLENetRectBuf = false; //
m_nZRLENetRectBufOffset = 0;
m_nZRLEReadSize = 0;
m_nZRLENetRectBufSize = 0;
// ZlibHex
m_decompStreamInited = false;
m_decompStreamRaw.total_in = ZLIBHEX_DECOMP_UNINITED;
m_decompStreamEncoded.total_in = ZLIBHEX_DECOMP_UNINITED;
// Initialise a few fields that will be properly set when the
// connection has been negotiated
m_fullwinwidth = m_fullwinheight = 0;
m_si.framebufferWidth = m_si.framebufferHeight = 0;
m_hScrollPos = 0; m_vScrollPos = 0;
m_waitingOnEmulateTimer = false;
m_emulatingMiddleButton = false;
oldPointerX = oldPointerY = oldButtonMask = 0;
// Create a buffer for various network operations
CheckBufferSize(INITIALNETBUFSIZE);
m_pApp->RegisterConnection(this);
kbitsPerSecond = 0;
m_lLastChangeTime = 0; // 0 because we want the first encoding switching to occur quickly
// (in Auto mode, ZRLE is used: pointless over a LAN)
m_fScalingDone = false;
zis = new rdr::ZlibInStream;
// tight cusorhandling
prevCursorSet = false;
rcCursorX = 0;
rcCursorY = 0;
// Modif sf@2002 - FileTransfer
m_pFileTransfer = new FileTransfer(m_pApp, this);
m_filezipbuf = NULL;
m_filezipbufsize = 0;
m_filechunkbuf = NULL;
m_filechunkbufsize = 0;
// Modif sf@2002 - Text Chat
m_pTextChat = new TextChat(m_pApp, this);
// Modif sf@2002 - Scaling
m_pendingScaleChange = false;
m_pendingCacheInit = false;
m_nServerScale = 1;
//ms logon
m_ms_logon=false;
// sf@2002 - FileTransfer on server
m_fServerKnowsFileTransfer = false;
// Auto Mode
m_nConfig = 0;
// sf@2002 - Options window flag
m_fOptionsOpen = false;
// Tight encoding
for (int i = 0; i < 4; i++)
m_tightZlibStreamActive[i] = false;
m_hwnd=NULL;
m_hbands=NULL;
m_hwndTB=NULL;
m_hwndTBwin=NULL;
m_hwndMain=NULL;
m_hwndStatus=NULL;
m_TrafficMonitor=NULL;
m_logo_wnd=NULL;
m_button_wnd=NULL;
// m_ToolbarEnable=true;
m_remote_mouse_disable=false;
m_SWselect=false;
EncodingStatusWindow = -1;
OldEncodingStatusWindow = -2;
m_nStatusTimer = 0;
// m_FTtimer = 0;
skipprompt2=true;
// flash=NULL;
// UltraFast
m_hmemdc=NULL;
m_DIBbits=NULL;
m_membitmap=NULL;
m_BigToolbar=false;
strcpy(m_proxyhost,"");
KillEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
newtick=0;
oldtick=0;
m_zipbuf=NULL;
m_filezipbuf=NULL;
m_filechunkbuf=NULL;
m_zlibbuf=NULL;
rcSource=NULL;
rcMask=NULL;
}
//
// Run() creates the connection if necessary, does the initial negotiations
// and then starts the thread running which does the output (update) processing.
// If Run throws an Exception, the caller must delete the ClientConnection object.
//
void ClientConnection::Run()
{
// Get the host name and port if we haven't got it
if (m_port == -1)
{
GetConnectDetails();
// sf@2002 - DSM Plugin loading if required
LoadDSMPlugin();
}
else
{
LoadDSMPlugin();
// sf@2003 - Take command line quickoption into account
HandleQuickOption();
}
// Modif sf@2003 - In case Auto Mode is On with DSMPlugin, we disable ZRLE right now !
/*
if (m_opts.autoDetect)
{
if (m_pDSMPlugin->IsEnabled())
{
m_opts.m_PreferredEncoding = rfbEncodingTight;
m_opts.m_fEnableCache = false; // Cache does not work perfectly with Tight
m_opts.m_Use8Bit = true; // full colors as Tight is going to last at least 30s...
m_lLastChangeTime = timeGetTime(); // defer the first possible Auto encoding switching in 30s
}
}
*/
// Modif sf@2002 - bit of a hack...and unsafe
if (strlen( m_pApp->m_options.m_clearPassword) > 0)
strcpy(m_clearPasswd, m_pApp->m_options.m_clearPassword);
if (saved_set)
{
saved_set=FALSE;
Save_Latest_Connection();
}
// Connect if we're not already connected
if (m_sock == INVALID_SOCKET)
if (strcmp(m_proxyhost,"")!=NULL && m_fUseProxy)ConnectProxy();
else Connect();
SetSocketOptions();
SetDSMPluginStuff(); // The Plugin is now activated BEFORE the protocol negociation
// so ALL the communication data travel through the DSMPlugin
if (strcmp(m_proxyhost,"")!=NULL && m_fUseProxy)
NegotiateProxy();
NegotiateProtocolVersion();
Authenticate();
GTGBS_CreateDisplay();
GTGBS_CreateToolbar();
// Set up windows etc
CreateDisplay();
// if (flash) {flash->Killflash();}
SendClientInit();
ReadServerInit();
CreateLocalFramebuffer();
SetupPixelFormat();
Createdib();
SetFormatAndEncodings();
SizeWindow();
// This starts the worker thread.
// The rest of the processing continues in run_undetached.
#ifndef _ULTRAVNCAX_
LowLevelHook::Initialize(m_hwndMain);
#endif
start_undetached();
EndDialog(m_hwndStatus,0);
}
HWND ClientConnection::GTGBS_ShowConnectWindow()
{
DWORD threadID;
m_statusThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE )ClientConnection::GTGBS_ShowStatusWindow,(LPVOID)this,0,&threadID);
ResumeThread(m_statusThread);
return (HWND)0;
}
////////////////////////////////////////////////////////
#include <commctrl.h>
#include <shellapi.h>
#include <lmaccess.h>
#include <lmat.h>
#include <lmalert.h>
void ClientConnection::CreateButtons(BOOL mini,BOOL ultra)
{
if (ultra)
{
int nr_buttons = 14;
TBADDBITMAP tbab;
TBBUTTON tbButtons []=
{
{0,ID_BUTTON_CAD,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,0},
{1,ID_BUTTON_FULLSCREEN,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,1},
{2,ID_BUTTON_PROPERTIES,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,2},
{3,ID_BUTTON_REFRESH,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,3},
{4,ID_BUTTON_STRG_ESC,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,4},
{5,ID_BUTTON_SEP,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,5},
{6,ID_BUTTON_INFO,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,6},
{7,ID_BUTTON_END,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,7},
{8,ID_BUTTON_DBUTTON,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,8},
{9,ID_BUTTON_DINPUT,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,9},
{10,ID_BUTTON_FTRANS,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,10},
{11,ID_BUTTON_SW,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,11},
{12,ID_BUTTON_DESKTOP,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,12},
{13,ID_BUTTON_TEXTCHAT,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,13},
};
static char *szTips[14] =
{
sz_L2,
sz_L3,
sz_L4,
sz_L5,
sz_L6,
sz_L7,
sz_L8,
sz_L9,
sz_L10,
sz_L11,
sz_L12,
sz_L13,
sz_L14,
sz_L15,
};
int stdidx;
HWND m_hwndTT;
UINT buttonmap,minibuttonmap;
int row,col;
TOOLINFO ti;
int id=0;
RECT clr;
InitCommonControls();
GetClientRect(m_hwndMain,&clr);
m_TBr.left=0;
m_TBr.right=clr.right;
m_TBr.top=0;
m_TBr.bottom=28;
buttonmap=IDB_BITMAP1;
minibuttonmap=IDB_BITMAP7;
if (m_remote_mouse_disable)
{
buttonmap=IDB_BITMAP8;
minibuttonmap=IDB_BITMAP9;
}
if (mini)
{
m_hwndTB = CreateToolbarEx(
m_hwndTBwin
//,WS_CHILD|WS_BORDER|WS_VISIBLE|TBSTYLE_TOOLTIPS|TBSTYLE_WRAPABLE|TB_AUTOSIZE
,WS_CHILD | TBSTYLE_WRAPABLE | WS_VISIBLE |TBSTYLE_TOOLTIPS |CCS_NORESIZE| TBSTYLE_FLAT | TBSTYLE_TRANSPARENT
,IDR_TOOLBAR
,nr_buttons
,(HINSTANCE)m_pApp->m_instance
,minibuttonmap
,(LPCTBBUTTON)&tbButtons
,nr_buttons
,10
,10
,10
,10
,sizeof(TBBUTTON));
}
else
{
m_hwndTB = CreateToolbarEx(
m_hwndTBwin
//,WS_CHILD|WS_BORDER|WS_VISIBLE|TBSTYLE_TOOLTIPS|TBSTYLE_WRAPABLE|TB_AUTOSIZE
,WS_CHILD | TBSTYLE_WRAPABLE | WS_VISIBLE |TBSTYLE_TOOLTIPS |CCS_NORESIZE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT
,IDR_TOOLBAR
,nr_buttons
,(HINSTANCE)m_pApp->m_instance
,buttonmap
,(LPCTBBUTTON)&tbButtons
,nr_buttons
,20
,20
,20
,20
,sizeof(TBBUTTON));
}
tbab.hInst = m_pApp->m_instance;
tbab.nID = IDB_BITMAP1;
stdidx = SendMessage(m_hwndTB,TB_ADDBITMAP,6,(LPARAM)&tbab);
RECT tbrect;
RECT wrect;
RECT trect;
SendMessage(m_hwndTB,TB_SETROWS,(WPARAM) MAKEWPARAM (2, true),(LPARAM) (LPRECT) (&trect));
GetClientRect(m_hwndTB,&tbrect);
GetClientRect(m_hwndTBwin,&wrect);
m_hwndTT = CreateWindow(
TOOLTIPS_CLASS,
(LPSTR)NULL,
TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
(HMENU)NULL,
(HINSTANCE)m_pApp->m_instance,
NULL);
DWORD buttonWidth = LOWORD(SendMessage(m_hwndTB,TB_GETBUTTONSIZE,(WPARAM)0,(LPARAM)0));
DWORD buttonHeight = HIWORD(SendMessage(m_hwndTB,TB_GETBUTTONSIZE,(WPARAM)0,(LPARAM)0));
for (row = 0; row < 1 ; row++ )
for (col = 0; col < nr_buttons; col++) {
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = 0 ;
ti.hwnd = m_hwndTB;
ti.hinst = m_pApp->m_instance;
ti.uId = (UINT) id;
ti.lpszText = (LPSTR) szTips[id++];
ti.rect.left = col * buttonWidth;
ti.rect.top = row * buttonHeight;
ti.rect.right = ti.rect.left + buttonWidth;
ti.rect.bottom = ti.rect.top + buttonHeight;
SendMessage(m_hwndTT, TTM_ADDTOOL, 0,
(LPARAM) (LPTOOLINFO) &ti);
}
SendMessage(m_hwndTB,TB_SETTOOLTIPS,(WPARAM)(HWND)m_hwndTT,(LPARAM)0);
SendMessage(m_hwndTT,TTM_SETTIPBKCOLOR,(WPARAM)(COLORREF)0x00404040,(LPARAM)0);
SendMessage(m_hwndTT,TTM_SETTIPTEXTCOLOR,(WPARAM)(COLORREF)0x00F5B28D,(LPARAM)0);
SendMessage(m_hwndTT,TTM_SETDELAYTIME,(WPARAM)(DWORD)TTDT_INITIAL,(LPARAM)(INT) MAKELONG(200,0));
SetWindowLong(m_hwndTBwin, GWL_USERDATA, (LONG) this);
ShowWindow(m_hwndTB, SW_SHOW);
ShowWindow(m_hwndTBwin, SW_SHOW);
}
else
{
int nr_buttons=9;
TBADDBITMAP tbab;
TBBUTTON tbButtons []=
{
{0,ID_BUTTON_CAD,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,0},
{1,ID_BUTTON_FULLSCREEN,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,1},
{2,ID_BUTTON_PROPERTIES,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,2},
{3,ID_BUTTON_REFRESH,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,3},
{4,ID_BUTTON_STRG_ESC,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,4},
{5,ID_BUTTON_SEP,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,5},
{6,ID_BUTTON_INFO,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,6},
{7,ID_BUTTON_END,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,7},
{8,ID_BUTTON_DBUTTON,TBSTATE_ENABLED,TBSTYLE_BUTTON,0L,8},
};
static char *szTips[9] =
{
sz_L2,
sz_L3,
sz_L4,
sz_L5,
sz_L6,
sz_L7,
sz_L8,
sz_L9,
sz_L10,
};
int stdidx;
HWND m_hwndTT;
int row,col;
TOOLINFO ti;
int id=0;
RECT clr;
InitCommonControls();
GetClientRect(m_hwndMain,&clr);
m_TBr.left=0;
m_TBr.right=clr.right;
m_TBr.top=0;
m_TBr.bottom=28;
if (mini)
{
m_hwndTB = CreateToolbarEx(
m_hwndTBwin
//,WS_CHILD|WS_BORDER|WS_VISIBLE|TBSTYLE_TOOLTIPS|TBSTYLE_WRAPABLE|TB_AUTOSIZE
,WS_CHILD | TBSTYLE_WRAPABLE | WS_VISIBLE |TBSTYLE_TOOLTIPS |CCS_NORESIZE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT
,IDR_TOOLBAR
,nr_buttons
,(HINSTANCE)m_pApp->m_instance
,IDB_BITMAP7
,(LPCTBBUTTON)&tbButtons
,nr_buttons
,12
,8
,12
,8
,sizeof(TBBUTTON));
}
else
{
m_hwndTB = CreateToolbarEx(
m_hwndTBwin
//,WS_CHILD|WS_BORDER|WS_VISIBLE|TBSTYLE_TOOLTIPS|TBSTYLE_WRAPABLE|TB_AUTOSIZE
,WS_CHILD | TBSTYLE_WRAPABLE | WS_VISIBLE |TBSTYLE_TOOLTIPS |CCS_NORESIZE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT
,IDR_TOOLBAR
,nr_buttons
,(HINSTANCE)m_pApp->m_instance
,IDB_BITMAP1
,(LPCTBBUTTON)&tbButtons
,nr_buttons
,20
,20
,20
,20
,sizeof(TBBUTTON));
}
tbab.hInst = m_pApp->m_instance;
tbab.nID = IDB_BITMAP1;
stdidx = SendMessage(m_hwndTB,TB_ADDBITMAP,6,(LPARAM)&tbab);
RECT tbrect;
RECT wrect;
RECT trect;
SendMessage(m_hwndTB,TB_SETROWS,(WPARAM) MAKEWPARAM (2, true),(LPARAM) (LPRECT) (&trect));
GetClientRect(m_hwndTB,&tbrect);
GetClientRect(m_hwndTBwin,&wrect);
m_hwndTT = CreateWindow(
TOOLTIPS_CLASS,
(LPSTR)NULL,
TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
(HMENU)NULL,
(HINSTANCE)m_pApp->m_instance,
NULL);
DWORD buttonWidth = LOWORD(SendMessage(m_hwndTB,TB_GETBUTTONSIZE,(WPARAM)0,(LPARAM)0));
DWORD buttonHeight = HIWORD(SendMessage(m_hwndTB,TB_GETBUTTONSIZE,(WPARAM)0,(LPARAM)0));
for (row = 0; row < 1 ; row++ )
for (col = 0; col < nr_buttons; col++) {
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = 0 ;
ti.hwnd = m_hwndTB;
ti.hinst = m_pApp->m_instance;
ti.uId = (UINT) id;
ti.lpszText = (LPSTR) szTips[id++];
ti.rect.left = col * buttonWidth;
ti.rect.top = row * buttonHeight;
ti.rect.right = ti.rect.left + buttonWidth;
ti.rect.bottom = ti.rect.top + buttonHeight;
SendMessage(m_hwndTT, TTM_ADDTOOL, 0,
(LPARAM) (LPTOOLINFO) &ti);
}
SendMessage(m_hwndTB,TB_SETTOOLTIPS,(WPARAM)(HWND)m_hwndTT,(LPARAM)0);
SendMessage(m_hwndTT,TTM_SETTIPBKCOLOR,(WPARAM)(COLORREF)0x0000ff00,(LPARAM)0);
SendMessage(m_hwndTT,TTM_SETTIPTEXTCOLOR,(WPARAM)(COLORREF)0x00000000,(LPARAM)0);
SendMessage(m_hwndTT,TTM_SETDELAYTIME,(WPARAM)(DWORD)TTDT_INITIAL,(LPARAM)(INT) MAKELONG(200,0));
SetWindowLong(m_hwndTBwin, GWL_USERDATA, (LONG) this);
ShowWindow(m_hwndTB, SW_SHOW);
ShowWindow(m_hwndTBwin, SW_SHOW);
}
}
void ClientConnection::GTGBS_CreateToolbar()
{
RECT clr;
WNDCLASS wndclass;
wndclass.style = 0;
wndclass.lpfnWndProc = ClientConnection::WndProcTBwin;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_pApp->m_instance;
wndclass.hIcon = LoadIcon(m_pApp->m_instance, MAKEINTRESOURCE(IDI_MAINICON));
switch (m_opts.m_localCursor) {
case NOCURSOR:
wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_NOCURSOR));
break;
case NORMALCURSOR:
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
break;
case DOTCURSOR:
default:
wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_DOTCURSOR));
}
//wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wndclass.lpszMenuName = (const TCHAR *) NULL;
wndclass.lpszClassName = VWR_WND_CLASS_NAME;
RegisterClass(&wndclass);
const DWORD winstyle = WS_CHILD ;
GetClientRect(m_hwndMain,&clr);
m_hwndTBwin = CreateWindowEx(
//WS_EX_TOPMOST ,
0,
VWR_WND_CLASS_NAME,
_T("VNC ToolBar"),
winstyle,
0,
0,
clr.right - clr.left,
28,
//m_hwnd, // Parent handle
m_hwndMain,
NULL, // Menu handle
m_pApp->m_instance,
NULL);
ShowWindow(m_hwndTBwin, SW_HIDE);
//////////////////////////////////////////////////
if ((clr.right-clr.left)>140+85+14*24)
CreateButtons(false,m_fServerKnowsFileTransfer);
else
CreateButtons(true,m_fServerKnowsFileTransfer);
//////////////////////////////////////////////////
RECT r;
GetClientRect(m_hwndTBwin,&r);
m_TrafficMonitor = CreateWindowEx(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
"Static",
NULL,
WS_CHILD | WS_VISIBLE ,
clr.right - clr.left-45,
((r.bottom-r.top) / 2) - 8,
35,
22,
m_hwndTBwin,
NULL,
m_pApp->m_instance,
NULL);
m_bitmapNONE = LoadImage(m_pApp->m_instance,MAKEINTRESOURCE(IDB_STAT_NONE),IMAGE_BITMAP,22,20,LR_SHARED);
m_bitmapFRONT = LoadImage(m_pApp->m_instance,MAKEINTRESOURCE(IDB_STAT_FRONT),IMAGE_BITMAP,22,20,LR_SHARED);
m_bitmapBACK= LoadImage(m_pApp->m_instance,MAKEINTRESOURCE(IDB_STAT_BACK),IMAGE_BITMAP,22,20,LR_SHARED);
HDC hdc = GetDC(m_TrafficMonitor);
HDC hdcBits;
hdcBits = CreateCompatibleDC(hdc);
SelectObject(hdcBits,m_bitmapNONE);
BitBlt(hdc,0,0,22,22,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdc);
///////////////////////////////////////////////////
m_logo_wnd = CreateWindow(
"combobox",
"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP|CBS_SIMPLE | CBS_AUTOHSCROLL | WS_VSCROLL,
clr.right - clr.left-45-70,
4,
70,
28,
m_hwndTBwin,
(HMENU)9999,
m_pApp->m_instance,
NULL);
m_button_wnd = CreateWindow(
"button",
"",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
clr.right - clr.left-45-70-200,
4,
20,
20,
m_hwndTBwin,
(HMENU)9998,
m_pApp->m_instance,
NULL);
TCHAR valname[256];
MRU *m_pMRU;
m_pMRU = new MRU(SESSION_MRU_KEY_NAME,26);
for (int i = 0; i < m_pMRU->NumItems(); i++) {
m_pMRU->GetItem(i, valname, 255);
int pos = SendMessage(m_logo_wnd, CB_ADDSTRING, 0, (LPARAM) valname);
}
SendMessage(m_logo_wnd, CB_SETCURSEL, 0, 0);
if (m_pMRU) delete m_pMRU;
}
//////////////////////////////////////////////////////////
void ClientConnection::CreateDisplay()
{
#ifdef _WIN32_WCE
//const DWORD winstyle = WS_VSCROLL | WS_HSCROLL | WS_CAPTION | WS_SYSMENU;
const DWORD winstyle = WS_CHILD;
#else
//const DWORD winstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_VSCROLL | WS_HSCROLL;
const DWORD winstyle = WS_CHILD;
#endif
RECT Rmain;
RECT Rtb;
GetClientRect(m_hwndMain,&Rmain);
GetClientRect(m_hwndTBwin,&Rtb);
WNDCLASS wndclass;
wndclass.style = 0;
wndclass.lpfnWndProc = ClientConnection::WndProchwnd;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_pApp->m_instance;
wndclass.hIcon = LoadIcon(m_pApp->m_instance, MAKEINTRESOURCE(IDI_MAINICON));
switch (m_opts.m_localCursor) {
case NOCURSOR:
wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_NOCURSOR));
break;
case NORMALCURSOR:
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
break;
case DOTCURSOR:
default:
wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_DOTCURSOR));
}
//wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndclass.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
wndclass.lpszMenuName = (const TCHAR *) NULL;
wndclass.lpszClassName = VWR_WND_CLASS_NAME_VIEWER;
RegisterClass(&wndclass);
m_hwnd = CreateWindow(VWR_WND_CLASS_NAME_VIEWER,
//m_hwnd = CreateWindow(_T("VNCMDI_Window"),
_T("VNCviewer"),
winstyle ,
0,
Rtb.top + Rtb.bottom,
CW_USEDEFAULT, // x-size
CW_USEDEFAULT, // y-size
//NULL, // Parent handle
m_hwndMain,
NULL, // Menu handle
m_pApp->m_instance,
NULL);
//ShowWindow(m_hwnd, SW_HIDE);
ShowWindow(m_hwnd, SW_SHOW);
// record which client created this window
SetWindowLong(m_hwnd, GWL_USERDATA, (LONG) this);
// SendMessage(m_hwnd,WM_CREATE,0,0);
// Create a memory DC which we'll use for drawing to
// the local framebuffer
m_hBitmapDC = CreateCompatibleDC(NULL);
m_hCacheBitmapDC = CreateCompatibleDC(NULL);
// Set a suitable palette up
if (GetDeviceCaps(m_hBitmapDC, RASTERCAPS) & RC_PALETTE) {
vnclog.Print(3, _T("Palette-based display - %d entries, %d reserved\n"),
GetDeviceCaps(m_hBitmapDC, SIZEPALETTE), GetDeviceCaps(m_hBitmapDC, NUMRESERVED));
BYTE buf[sizeof(LOGPALETTE)+216*sizeof(PALETTEENTRY)];
LOGPALETTE *plp = (LOGPALETTE *) buf;
int pepos = 0;
for (int r = 5; r >= 0; r--) {
for (int g = 5; g >= 0; g--) {
for (int b = 5; b >= 0; b--) {
plp->palPalEntry[pepos].peRed = r * 255 / 5;
plp->palPalEntry[pepos].peGreen = g * 255 / 5;
plp->palPalEntry[pepos].peBlue = b * 255 / 5;
plp->palPalEntry[pepos].peFlags = NULL;
pepos++;
}
}
}
plp->palVersion = 0x300;
plp->palNumEntries = 216;
m_hPalette = CreatePalette(plp);
}
// Add stuff to System menu
HMENU hsysmenu = GetSystemMenu(m_hwndMain, FALSE);
if (!m_opts.m_restricted) {
// Modif sf@2002
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_FILETRANSFER, sz_L16);
AppendMenu(hsysmenu, MF_STRING, ID_TEXTCHAT, sz_L17);
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_DBUTTON, sz_L18);
// AppendMenu(hsysmenu, MF_STRING, ID_BUTTON, _T("Show Toolbar Buttons"));
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_DINPUT, sz_L19);
AppendMenu(hsysmenu, MF_STRING, ID_INPUT, sz_L20);
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, IDC_OPTIONBUTTON, sz_L21);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_ABOUT, sz_L22);
AppendMenu(hsysmenu, MF_STRING, ID_REQUEST_REFRESH, sz_L23);
AppendMenu(hsysmenu, MF_STRING, ID_VIEWONLYTOGGLE, "View Only"); // Todo: translate
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_FULLSCREEN, sz_L24);
AppendMenu(hsysmenu, MF_STRING, ID_AUTOSCALING, sz_L25);
// Modif sf@2002
AppendMenu(hsysmenu, MF_STRING, ID_HALFSCREEN, sz_L26);
AppendMenu(hsysmenu, MF_STRING, ID_FUZZYSCREEN, sz_L27);
AppendMenu(hsysmenu, MF_STRING, ID_NORMALSCREEN, sz_L28);
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_MAXCOLORS, sz_L29);
AppendMenu(hsysmenu, MF_STRING, ID_256COLORS, sz_L30);
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLALTDEL, sz_L31);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLESC, sz_L32);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLDOWN, sz_L33);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLUP, sz_L34);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_ALTDOWN, sz_L35);
AppendMenu(hsysmenu, MF_STRING, ID_CONN_ALTUP, sz_L36);
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_NEWCONN, sz_L37);
AppendMenu(hsysmenu, MF_STRING | (m_serverInitiated ? MF_GRAYED : 0),
ID_CONN_SAVE_AS, sz_L38);
}
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, IDD_APP_ABOUT, sz_L39);
if (m_opts.m_listening) {
AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hsysmenu, MF_STRING, ID_CLOSEDAEMON, sz_L40);
}
DrawMenuBar(m_hwndMain);
TheAccelKeys.SetWindowHandle(m_opts.m_NoHotKeys ? 0 : m_hwndMain);
CheckMenuItem(GetSystemMenu(m_hwndMain, FALSE),
ID_DBUTTON,
MF_BYCOMMAND | (m_opts.m_ShowToolbar ? MF_CHECKED :MF_UNCHECKED));
CheckMenuItem(GetSystemMenu(m_hwndMain, FALSE),
ID_AUTOSCALING,
MF_BYCOMMAND | (m_opts.m_fAutoScaling ? MF_CHECKED :MF_UNCHECKED));
// Set up clipboard watching
#ifndef _WIN32_WCE
// We want to know when the clipboard changes, so
// insert ourselves in the viewer chain. But doing
// this will cause us to be notified immediately of
// the current state.
// We don't want to send that.
m_initialClipboardSeen = false;
m_hwndNextViewer = SetClipboardViewer(m_hwnd);
#endif
#ifndef _ULTRAVNCAX_
//Added by: Lars Werner (http://lars.werner.no)
if(TitleBar.GetSafeHwnd()==NULL)
TitleBar.Create(m_pApp->m_instance, m_hwndMain);
#endif
}
//
// sf@2002 - DSMPlugin loading and initialization if required
//
void ClientConnection::LoadDSMPlugin()
{
if (m_opts.m_fUseDSMPlugin)
{
if (!m_pDSMPlugin->IsLoaded())
{
m_pDSMPlugin->LoadPlugin(m_opts.m_szDSMPluginFilename, m_opts.m_listening);
if (m_pDSMPlugin->IsLoaded())
{
if (m_pDSMPlugin->InitPlugin())
{
m_pDSMPlugin->SetEnabled(true);
m_pDSMPlugin->DescribePlugin();
/*
MessageBox(NULL,
_T(_this->m_pDSMPlugin->DescribePlugin()),
_T("Plugin Description"), MB_OK | MB_ICONEXCLAMATION );
*/
}
else
{
m_pDSMPlugin->SetEnabled(false);
MessageBox(NULL,
sz_F1,
sz_F6, MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_TOPMOST);
return;
}
}
else
{
m_pDSMPlugin->SetEnabled(false);
MessageBox(NULL,
sz_F5,
sz_F6, MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_TOPMOST);
return;
}
}
}
return;
}
//
// Get & Set the VNC password for the DSMPlugin if necessary
//
void ClientConnection::SetDSMPluginStuff()
{
if (m_pDSMPlugin->IsEnabled())
{
char szParams[256+16];
// Does the plugin need the VNC password to do its job ?
if (!stricmp(m_pDSMPlugin->GetPluginParams(), "VNCPasswordNeeded"))
{
// Yes. The user must enter the VNC password
// He won't be prompted again for password if ms_logon is not used.
if (strlen(m_clearPasswd) == 0) // Possibly set using -password command line
{
AuthDialog ad;
#ifdef _ULTRAVNCAX_
ad.parent = GetTopMostWnd( m_hwndMain ? m_hwndMain : m_hwndAx );
#endif
if (ad.DoDialog(false))
{
strncpy(m_clearPasswd, ad.m_passwd,254);
}
}
strcpy(szParams, m_clearPasswd);
}
else
strcpy(szParams, "NoPassword");
// The second parameter tells the plugin the kind of program is using it
// (in vncviewer : "viewer")
strcat(szParams, ",");
strcat(szParams, "viewer");
// Initialize the DSM Plugin with params
if (!m_pDSMPlugin->SetPluginParams(NULL, szParams))
{
m_pDSMPlugin->SetEnabled(false);
m_fUsePlugin = false;
vnclog.Print(0, _T("DSMPlugin cannot be configured\n"));
throw WarningException(sz_L41);
}
// If all went well
m_fUsePlugin = true;
}
}
//
//
//
void ClientConnection::HandleQuickOption()
{
switch (m_opts.m_quickoption)
{
case 1:
m_opts.m_PreferredEncoding = rfbEncodingZRLE;
m_opts.m_Use8Bit = rfbPFFullColors; //false;
m_opts.m_fEnableCache = true;
m_opts.autoDetect = true;
break;
case 2:
m_opts.m_PreferredEncoding = rfbEncodingHextile;
m_opts.m_Use8Bit = rfbPFFullColors; // false; // Max colors
m_opts.autoDetect = false;
m_opts.m_fEnableCache = false;
// m_opts.m_localCursor = NOCURSOR;
// m_opts.m_requestShapeUpdates = true;
// m_opts.m_ignoreShapeUpdates = false;
break;
case 3:
m_opts.m_PreferredEncoding = rfbEncodingZRLE; // rfbEncodingZlibHex;
m_opts.m_Use8Bit = rfbPF256Colors; //false;
m_opts.autoDetect = false;
m_opts.m_fEnableCache = false;
// m_opts.m_localCursor = NOCURSOR;
break;
case 4:
m_opts.m_PreferredEncoding = rfbEncodingZRLE;
m_opts.m_Use8Bit = rfbPF64Colors; //true;
m_opts.autoDetect = false;
m_opts.m_fEnableCache = true;
break;
case 5:
m_opts.m_PreferredEncoding = rfbEncodingZRLE;
m_opts.m_Use8Bit = rfbPF8Colors; //true;
// m_opts.m_scaling = true;
// m_opts.m_scale_num = 200;
// m_opts.m_scale_den = 100;
// m_opts.m_nServerScale = 2;
m_opts.m_enableJpegCompression = false;
m_opts.autoDetect = false;
m_opts.m_fEnableCache = true;
break;
case 7:
m_opts.m_PreferredEncoding = rfbEncodingUltra;
m_opts.m_Use8Bit = rfbPFFullColors; //false; // Max colors
m_opts.autoDetect = false;
m_opts.m_fEnableCache = false;
m_opts.m_requestShapeUpdates = false;
m_opts.m_ignoreShapeUpdates = true;
// m_opts.m_localCursor = NOCURSOR;
break;
default: // 0 can be set by noauto command line option. Do not chnage any setting in this case
/* sf@2005
m_opts.m_PreferredEncoding = rfbEncodingZRLE;
m_opts.m_Use8Bit = rfbPF256Colors; //false;
m_opts.m_fEnableCache = true;
m_opts.autoDetect = false;
*/
break;
}
}
void ClientConnection::GetConnectDetails()
{
if (m_opts.m_configSpecified) {
LoadConnection(m_opts.m_configFilename, false);
}
else
{
char optionfile[MAX_PATH];
char *tempvar=NULL;
tempvar = getenv( "TEMP" );
if (tempvar) strcpy(optionfile,tempvar);
else strcpy(optionfile,"");
strcat(optionfile,"\\options.vnc");
if (!command_line)
{
if (LoadConnection(optionfile, false)==-1)
{
SessionDialog sessdlg(&m_opts, this, m_pDSMPlugin); //sf@2002
if (!sessdlg.DoDialog())
{
throw QuietException(sz_L42);
}
_tcsncpy(m_host, sessdlg.m_host_dialog, MAX_HOST_NAME_LEN);
m_port = sessdlg.m_port;
_tcsncpy(m_proxyhost, sessdlg.m_proxyhost, MAX_HOST_NAME_LEN);
// _tcsncpy(m_remotehost, sessdlg.m_remotehost, MAX_HOST_NAME_LEN);
m_proxyport = sessdlg.m_proxyport;
m_fUseProxy = sessdlg.m_fUseProxy;
if (m_opts.autoDetect)
{
m_opts.m_Use8Bit = rfbPF256Colors;
m_opts.m_fEnableCache = true; // sf@2002
}
}
}
else
{
SessionDialog sessdlg(&m_opts, this, m_pDSMPlugin); //sf@2002
if (!sessdlg.DoDialog())
{
throw QuietException(sz_L42);
}
_tcsncpy(m_host, sessdlg.m_host_dialog, MAX_HOST_NAME_LEN);
m_port = sessdlg.m_port;
_tcsncpy(m_proxyhost, sessdlg.m_proxyhost, MAX_HOST_NAME_LEN);
// _tcsncpy(m_remotehost, sessdlg.m_remotehost, MAX_HOST_NAME_LEN);
m_proxyport = sessdlg.m_proxyport;
m_fUseProxy = sessdlg.m_fUseProxy;
if (m_opts.autoDetect)
{
m_opts.m_Use8Bit = rfbPF256Colors;
m_opts.m_fEnableCache = true; // sf@2002
}
}
}
// This is a bit of a hack:
// The config file may set various things in the app-level defaults which
// we don't want to be used except for the first connection. So we clear them
// in the app defaults here.
m_pApp->m_options.m_host_options[0] = '\0';
m_pApp->m_options.m_port = -1;
m_pApp->m_options.m_proxyhost[0] = '\0';
m_pApp->m_options.m_proxyport = -1;
m_pApp->m_options.m_connectionSpecified = false;
m_pApp->m_options.m_configSpecified = false;
}
void ClientConnection::Connect()
{
struct sockaddr_in thataddr;
int res;
if (!m_opts.m_NoStatus) GTGBS_ShowConnectWindow();
m_sock = socket(PF_INET, SOCK_STREAM, 0);
if (m_hwndStatus) SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L43);
if (m_sock == INVALID_SOCKET) {if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L44);throw WarningException(sz_L44);}
int one = 1;
if (m_hwndStatus) SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L45);
if (m_hwndStatus) UpdateWindow(m_hwndStatus);
// The host may be specified as a dotted address "a.b.c.d"
// Try that first
thataddr.sin_addr.s_addr = inet_addr(m_host);
// If it wasn't one of those, do gethostbyname
if (thataddr.sin_addr.s_addr == INADDR_NONE) {
LPHOSTENT lphost;
lphost = gethostbyname(m_host);
if (lphost == NULL) {
//if(myDialog!=0)DestroyWindow(myDialog);
if (m_hwndStatus) SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L46);
throw WarningException(sz_L46);
};
thataddr.sin_addr.s_addr = ((LPIN_ADDR) lphost->h_addr)->s_addr;
};
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L47);
if (m_hwndStatus)ShowWindow(m_hwndStatus,SW_SHOW);
if (m_hwndStatus)UpdateWindow(m_hwndStatus);
if (m_hwndStatus)SetDlgItemInt(m_hwndStatus,IDC_PORT,m_port,FALSE);
thataddr.sin_family = AF_INET;
thataddr.sin_port = htons(m_port);
res = connect(m_sock, (LPSOCKADDR) &thataddr, sizeof(thataddr));
if (res == SOCKET_ERROR)
{
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L48);
if (!Pressed_Cancel) throw WarningException(sz_L48);
else throw QuietException(sz_L48);
}
vnclog.Print(0, _T("Connected to %s port %d\n"), m_host, m_port);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L49);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_VNCSERVER,m_host);
if (m_hwndStatus)ShowWindow(m_hwndStatus,SW_SHOW);
if (m_hwndStatus)UpdateWindow(m_hwndStatus);
}
void ClientConnection::ConnectProxy()
{
struct sockaddr_in thataddr;
int res;
if (!m_opts.m_NoStatus) GTGBS_ShowConnectWindow();
m_sock = socket(PF_INET, SOCK_STREAM, 0);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L43);
if (m_sock == INVALID_SOCKET) {if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L44);throw WarningException(sz_L44);}
int one = 1;
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L45);
if (m_hwndStatus)UpdateWindow(m_hwndStatus);
// The host may be specified as a dotted address "a.b.c.d"
// Try that first
thataddr.sin_addr.s_addr = inet_addr(m_proxyhost);
// If it wasn't one of those, do gethostbyname
if (thataddr.sin_addr.s_addr == INADDR_NONE) {
LPHOSTENT lphost;
lphost = gethostbyname(m_proxyhost);
if (lphost == NULL) {
//if(myDialog!=0)DestroyWindow(myDialog);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L46);
throw WarningException(sz_L46);
};
thataddr.sin_addr.s_addr = ((LPIN_ADDR) lphost->h_addr)->s_addr;
};
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L47);
if (m_hwndStatus)ShowWindow(m_hwndStatus,SW_SHOW);
if (m_hwndStatus)UpdateWindow(m_hwndStatus);
if (m_hwndStatus)SetDlgItemInt(m_hwndStatus,IDC_PORT,m_proxyport,FALSE);
thataddr.sin_family = AF_INET;
thataddr.sin_port = htons(m_proxyport);
res = connect(m_sock, (LPSOCKADDR) &thataddr, sizeof(thataddr));
if (res == SOCKET_ERROR) {if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L48);throw WarningException(sz_L48);}
vnclog.Print(0, _T("Connected to %s port %d\n"), m_proxyhost, m_proxyport);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L49);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_VNCSERVER,m_proxyhost);
if (m_hwndStatus)ShowWindow(m_hwndStatus,SW_SHOW);
if (m_hwndStatus)UpdateWindow(m_hwndStatus);
}
void ClientConnection::SetSocketOptions()
{
// Disable Nagle's algorithm
BOOL nodelayval = TRUE;
if (setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, (const char *) &nodelayval, sizeof(BOOL)))
throw WarningException(sz_L50);
fis = new rdr::FdInStream(m_sock);
fis->SetDSMMode(m_pDSMPlugin->IsEnabled()); // sf@2003 - Special DSM mode for ZRLE encoding
}
void ClientConnection::NegotiateProtocolVersion()
{
rfbProtocolVersionMsg pv;
/* if the connection is immediately closed, don't report anything, so
that pmw's monitor can make test connections */
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L89);
try
{
ReadExact(pv, sz_rfbProtocolVersionMsg);
}
catch (Exception &c)
{
vnclog.Print(0, _T("Error reading protocol version: %s\n"),
c.m_info);
if (m_fUsePlugin)
throw WarningException("Connection failed - Error reading Protocol Version\r\n\n\r"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- The selected DSMPlugin is not compatible with the one running on the Server\r\n"
"- The selected DSMPlugin is not correctly configured (also possibly on the Server)\r\n"
"- The password you've possibly entered is incorrect\r\n"
);
else
throw WarningException("Connection failed - Error reading Protocol Version\r\n\n\r"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- Viewer and Server are not compatible (they use different RFB protocoles)\r\n"
"- Bad connection\r\n"
);
throw QuietException(c.m_info);
}
pv[sz_rfbProtocolVersionMsg] = 0;
/*
// sf@2005 - Cleanup scrambled chars before parsing -> Restore original RFB protocol header first chars
if (m_fUsePlugin)
{
pv[0] = rfbProtocolVersionFormat[0];
pv[1] = rfbProtocolVersionFormat[1];
pv[2] = rfbProtocolVersionFormat[2];
pv[3] = rfbProtocolVersionFormat[3];
}
*/
// XXX This is a hack. Under CE we just return to the server the
// version number it gives us without parsing it.
// Too much hassle replacing sscanf for now. Fix this!
#ifdef UNDER_CE
m_majorVersion = rfbProtocolMajorVersion;
m_minorVersion = rfbProtocolMinorVersion;
#else
if (sscanf(pv,rfbProtocolVersionFormat,&m_majorVersion,&m_minorVersion) != 2)
{
if (m_fUsePlugin)
throw WarningException("Connection failed - Invalid protocol !\r\n\r\n"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- The selected DSMPlugin is not compatible with the one running on the Server\r\n"
"- The selected DSMPlugin is not correctly configured (also possibly on the Server)\r\n"
"- The password you've possibly entered is incorrect\r\n"
);
else
throw WarningException("Connection failed - Invalid protocol !\r\n\r\n"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- Viewer and Server are not compatible (they use different RFB protocoles)\r\n"
);
}
vnclog.Print(0, _T("RFB server supports protocol version %d.%d\n"),
m_majorVersion,m_minorVersion);
// UltraVNC specific functionnalities
// - ms logon
// - FileTransfer (TODO: change Minor version in next eSVNC release so it's compatible with Ultra)
// Minor = 4 means that server supports FileTransfer and requires ms logon
// Minor = 6 means that server support FileTransfer and requires normal VNC logon
if (m_minorVersion == 4)
{
m_ms_logon = true;
m_fServerKnowsFileTransfer = true;
}
if (m_minorVersion == 6) // 6 because 5 already used in TightVNC viewer for some reason
{
m_ms_logon = false;
m_fServerKnowsFileTransfer = true;
}
// Added for SC so we can do something before actual data transfer start
if (m_minorVersion == 14 || m_minorVersion == 16)
{
m_fServerKnowsFileTransfer = true;
}
else if ((m_majorVersion == 3) && (m_minorVersion < 3)) {
/* if server is 3.2 we can't use the new authentication */
vnclog.Print(0, _T("Can't use IDEA authentication\n"));
/* This will be reported later if authentication is requested*/
} else {
/* any other server version, just tell the server what we want */
m_majorVersion = rfbProtocolMajorVersion;
m_minorVersion = rfbProtocolMinorVersion; // always 4 for Ultra Viewer
}
sprintf(pv,rfbProtocolVersionFormat, m_majorVersion, m_minorVersion);
#endif
WriteExact(pv, sz_rfbProtocolVersionMsg);
if (m_minorVersion == 14 || m_minorVersion == 16)
{
int size;
ReadExact((char *)&size,sizeof(int));
char mytext[1024]; //10k
ReadExact(mytext,size);
mytext[size]=0;
int returnvalue=MessageBox(NULL, mytext,"Accept Incoming SC connection", MB_YESNO | MB_TOPMOST);
if (returnvalue==IDNO)
{
int nummer=0;
WriteExact((char *)&nummer,sizeof(int));
throw WarningException("You refused connection.....");
}
else
{
int nummer=1;
WriteExact((char *)&nummer,sizeof(int));
}
}
vnclog.Print(0, _T("Connected to RFB server, using protocol version %d.%d\n"),
rfbProtocolMajorVersion, rfbProtocolMinorVersion);
}
void ClientConnection::NegotiateProxy()
{
rfbProtocolVersionMsg pv;
/* if the connection is immediately closed, don't report anything, so
that pmw's monitor can make test connections */
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L89);
try
{
ReadExactProxy(pv, sz_rfbProtocolVersionMsg);
}
catch (Exception &c)
{
vnclog.Print(0, _T("Error reading protocol version: %s\n"),
c.m_info);
if (m_fUsePlugin)
throw WarningException("Proxy Connection failed - Error reading Protocol Version\r\n\n\r"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- The selected DSMPlugin is not compatible with the one running on the Server\r\n"
"- The selected DSMPlugin is not correctly configured (also possibly on the Server)\r\n"
"- The password you've possibly entered is incorrect\r\n"
);
else
throw WarningException("Proxy Connection failed - Error reading Protocol Version\r\n\n\r"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- Viewer and Server are not compatible (they use different RFB protocoles)\r\n"
"- Bad connection\r\n"
);
throw QuietException(c.m_info);
}
pv[sz_rfbProtocolVersionMsg] = 0;
/*
// sf@2005 - Cleanup scrambled chars before parsing -> Restore original RFB protocol header first chars
if (m_fUsePlugin)
{
pv[0] = rfbProtocolVersionFormat[0];
pv[1] = rfbProtocolVersionFormat[1];
pv[2] = rfbProtocolVersionFormat[2];
pv[3] = rfbProtocolVersionFormat[3];
}
*/
if (sscanf(pv,rfbProtocolVersionFormat,&m_majorVersion,&m_minorVersion) != 2)
{
if (m_fUsePlugin)
throw WarningException("Proxy Connection failed - Invalid protocol !\r\n\r\n"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- The selected DSMPlugin is not compatible with the one running on the Server\r\n"
"- The selected DSMPlugin is not correctly configured (also possibly on the Server)\r\n"
"- The password you've possibly entered is incorrect\r\n"
);
else
throw WarningException("Proxy Connection failed - Invalid protocol !\r\n\r\n"
"Possible causes:\r\r"
"- You've forgotten to select a DSMPlugin and the Server uses a DSMPlugin\r\n"
"- Viewer and Server are not compatible (they use different RFB protocoles)\r\n"
);
}
vnclog.Print(0, _T("Connected to proxy \n"),
m_majorVersion,m_minorVersion);
if (m_majorVersion==0 && m_minorVersion==0)
{
TCHAR tmphost[MAX_HOST_NAME_LEN];
TCHAR tmphost2[256];
_tcscpy(tmphost,m_host);
if (strcmp(tmphost,"")!=NULL)
{
_tcscat(tmphost,":");
_tcscat(tmphost,itoa(m_port,tmphost2,10));
}
WriteExactProxy(tmphost,MAX_HOST_NAME_LEN);
vnclog.Print(0, _T("Connected to RFB server, using protocol version %d.%d\n"),
rfbProtocolMajorVersion, rfbProtocolMinorVersion);
}
}
void ClientConnection::Authenticate()
{
CARD32 authScheme, reasonLen, authResult;
CARD8 challenge[CHALLENGESIZE];
CARD8 challengems[CHALLENGESIZEMS];
ReadExact((char *)&authScheme, 4);
authScheme = Swap32IfLE(authScheme);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L90);
switch (authScheme) {
case rfbConnFailed:
ReadExact((char *)&reasonLen, 4);
reasonLen = Swap32IfLE(reasonLen);
CheckBufferSize(reasonLen+1);
ReadString(m_netbuf, reasonLen);
vnclog.Print(0, _T("RFB connection failed, reason: %s\n"), m_netbuf);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L91);
throw WarningException(m_netbuf);
break;
case rfbNoAuth:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L92);
vnclog.Print(0, _T("No authentication needed\n"));
break;
case rfbVncAuth:
{
if ((m_majorVersion == 3) && (m_minorVersion < 3))
{
/* if server is 3.2 we can't use the new authentication */
vnclog.Print(0, _T("Can't use IDEA authentication\n"));
MessageBox(NULL,
sz_L51,
sz_L52,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
throw WarningException("Can't use IDEA authentication any more!");
}
// rdv@2002 - v1.1.x
char passwd[256];
char domain[256];
char user[256];
memset(passwd, 0, sizeof(char)*256);
memset(domain, 0, sizeof(char)*256);
memset(user, 0, sizeof(char)*256);
// We ignore the clear password in case of ms_logon !
// Todo: Add ms_user & ms_password command line params
if (m_ms_logon) memset(m_clearPasswd, 0, sizeof(m_clearPasswd));
if(strlen(m_strPassword) > 0)
{
strncpy(m_clearPasswd, m_strPassword, sizeof(m_clearPasswd) - 1);
}
// Was the password already specified in a config file or entered for DSMPlugin ?
// Modif sf@2002 - A clear password can be transmitted via the vncviewer command line
if (strlen(m_clearPasswd)>0)
{
strcpy(passwd, m_clearPasswd);
}
else if (strlen((const char *) m_encPasswd)>0)
{
char *pw = vncDecryptPasswd(m_encPasswd);
strcpy(passwd, pw);
free(pw);
}
else
{
AuthDialog ad;
#ifdef _ULTRAVNCAX_
ad.parent = GetTopMostWnd( m_hwndMain ? m_hwndMain : m_hwndAx );
#endif
///////////////ppppppppppppppppppppppppppppppppppppppppp
if (ad.DoDialog(m_ms_logon))
{
// flash = new BmpFlasher;
#ifndef UNDER_CE
strncpy(passwd, ad.m_passwd,254);
strncpy(user, ad.m_user,254);
strncpy(domain, ad.m_domain,254);
#else
int origlen = _tcslen(ad.m_passwd);
int newlen = WideCharToMultiByte(
CP_ACP, // code page
0, // performance and mapping flags
ad.m_passwd, // address of wide-character string
origlen, // number of characters in string
passwd, // address of buffer for new string
255, // size of buffer
NULL, NULL );
passwd[newlen]= '\0';
//user
origlen = _tcslen(ad.m_user);
newlen = WideCharToMultiByte(
CP_ACP, // code page
0, // performance and mapping flags
ad.m_user, // address of wide-character string
origlen, // number of characters in string
user, // address of buffer for new string
255, // size of buffer
NULL, NULL );
user[newlen]= '\0';
//domain
origlen = _tcslen(ad.m_domain);
newlen = WideCharToMultiByte(
CP_ACP, // code page
0, // performance and mapping flags
ad.m_domain, // address of wide-character string
origlen, // number of characters in string
domain, // address of buffer for new string
255, // size of buffer
NULL, NULL );
domain[newlen]= '\0';
#endif
if (strlen(user)==0 ||!m_ms_logon)//need longer passwd for ms
{
if (strlen(passwd) == 0) {
// if (flash) {flash->Killflash();}
vnclog.Print(0, _T("Password had zero length\n"));
throw WarningException(sz_L53);
}
if (strlen(passwd) > 8) {
passwd[8] = '\0';
}
}
if (m_ms_logon) vncEncryptPasswdMs(m_encPasswdMs, passwd);
vncEncryptPasswd(m_encPasswd, passwd);
}
else
{
// if (flash) {flash->Killflash();}
throw QuietException(sz_L54);
}
}
/*
// sf@2002 - DSM Plugin
if (m_pDSMPlugin->IsEnabled())
{
// Initialize the DSL Plugin with the entered password
if (!m_pDSMPlugin->SetPluginParams(NULL, passwd))
{
m_pDSMPlugin->SetEnabled(false);
m_fUsePlugin = false;
vnclog.Print(0, _T("DSMPlugin cannot be configured\n"));
throw WarningException("DSMPlugin cannot be configured");
}
m_fUsePlugin = true;
// TODO: Make a special challenge with time stamp
// to prevent recording the logon session for later replay
}
*/
// sf@2002
// m_ms_logon = false;
if (m_ms_logon) ReadExact((char *)challengems, CHALLENGESIZEMS);
ReadExact((char *)challenge, CHALLENGESIZE);
// MS logon
if (m_ms_logon)
{
int i=0;
for (i=0;i<32;i++)
{
challengems[i]=m_encPasswdMs[i]^challengems[i];
}
WriteExact((char *) user, sizeof(char)*256);
WriteExact((char *) domain, sizeof(char)*256);
WriteExact((char *) challengems, CHALLENGESIZEMS);
vncEncryptBytes(challenge, passwd);
/* Lose the plain-text password from memory */
int nLen = (int)strlen(passwd);
for ( i=0; i< nLen; i++) {
passwd[i] = '\0';
}
WriteExact((char *) challenge, CHALLENGESIZE);
}
else // Regular VNC logon
{
vncEncryptBytes(challenge, passwd);
/* Lose the plain-text password from memory */
int nLen = (int)strlen(passwd);
for (int i=0; i< nLen; i++) {
passwd[i] = '\0';
}
WriteExact((char *) challenge, CHALLENGESIZE);
}
ReadExact((char *) &authResult, 4);
authResult = Swap32IfLE(authResult);
switch (authResult)
{
case rfbVncAuthOK:
if (m_hwndStatus)vnclog.Print(0, _T("VNC authentication succeeded\n"));
SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L55);
g_passwordfailed=false;
break;
case rfbVncAuthFailed:
vnclog.Print(0, _T("VNC authentication failed!"));
g_passwordfailed=true;
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L56);
// if (flash) {flash->Killflash();}
throw WarningException(sz_L57);
case rfbVncAuthTooMany:
throw WarningException(
sz_L58);
default:
vnclog.Print(0, _T("Unknown VNC authentication result: %d\n"),
(int)authResult);
// if (flash) {flash->Killflash();}
throw ErrorException(sz_L59);
}
break;
}
case rfbMsLogon:
AuthMsLogon();
break;
default:
vnclog.Print(0, _T("Unknown authentication scheme from RFB server: %d\n"),
(int)authScheme);
// if (flash) {flash->Killflash();}
throw ErrorException(sz_L60);
}
}
// marscha@2006: Try to better hide the windows password.
// I know that this is no breakthrough in modern cryptography.
// It's just a patch/kludge/workaround.
void ClientConnection::AuthMsLogon() {
char gen[8], mod[8], pub[8], resp[8];
char user[256], passwd[64];
unsigned char key[8];
memset(m_clearPasswd, 0, sizeof(m_clearPasswd)); // ??
ReadExact(gen, sizeof(gen));
ReadExact(mod, sizeof(mod));
ReadExact(resp, sizeof(resp));
DH dh(bytesToInt64(gen), bytesToInt64(mod));
int64ToBytes(dh.createInterKey(), pub);
WriteExact(pub, sizeof(pub));
int64ToBytes(dh.createEncryptionKey(bytesToInt64(resp)), (char*) key);
vnclog.Print(100, _T("After DH: g=%I64u, m=%I64u, i=%I64u, key=%I64u\n"),
bytesToInt64(gen), bytesToInt64(mod), bytesToInt64(pub), bytesToInt64((char*) key));
// get username and passwd
AuthDialog ad;
#ifdef _ULTRAVNCAX_
ad.parent = GetTopMostWnd( m_hwndMain ? m_hwndMain : m_hwndAx );
#endif
if (ad.DoDialog(m_ms_logon, true)) {
#ifndef UNDER_CE
strncpy(passwd, ad.m_passwd, 64);
strncpy(user, ad.m_user, 254);
//strncpy(domain, ad.m_domain, 254);
#else
vncWc2Mb(passwd, ad.m_passwd, 64);
vncWc2Mb(user, ad.m_user, 256);
//vncWc2Mb(domain, ad.m_domain, 256);
#endif
//vncEncryptPasswdMs(m_encPasswdMs, passwd);
} else {
throw QuietException(sz_L54);
}
//user = domain + "\\" + user;
vncEncryptBytes2((unsigned char*) user, sizeof(user), key);
vncEncryptBytes2((unsigned char*) passwd, sizeof(passwd), key);
WriteExact(user, sizeof(user));
WriteExact(passwd, sizeof(passwd));
CARD32 authResult;
ReadExact((char *) &authResult, 4);
authResult = Swap32IfLE(authResult);
switch (authResult) {
case rfbVncAuthOK:
vnclog.Print(0, _T("MS-Logon (DH) authentication succeeded.\n"));
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L55);
g_passwordfailed=false;
break;
case rfbVncAuthFailed:
vnclog.Print(0, _T("MS-Logon (DH) authentication failed!\n"));
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L56);
g_passwordfailed=true;
throw WarningException(sz_L57);
case rfbVncAuthTooMany:
throw WarningException(sz_L58);
default:
vnclog.Print(0, _T("Unknown MS-Logon (DH) authentication result: %d\n"),
(int)authResult);
throw ErrorException(sz_L59);
}
}
void ClientConnection::SendClientInit()
{
rfbClientInitMsg ci;
ci.shared = m_opts.m_Shared;
WriteExact((char *)&ci, sz_rfbClientInitMsg); // sf@2002 - RSM Plugin
}
void ClientConnection::ReadServerInit()
{
ReadExact((char *)&m_si, sz_rfbServerInitMsg);
m_si.framebufferWidth = Swap16IfLE(m_si.framebufferWidth);
m_si.framebufferHeight = Swap16IfLE(m_si.framebufferHeight);
m_si.format.redMax = Swap16IfLE(m_si.format.redMax);
m_si.format.greenMax = Swap16IfLE(m_si.format.greenMax);
m_si.format.blueMax = Swap16IfLE(m_si.format.blueMax);
m_si.nameLength = Swap32IfLE(m_si.nameLength);
m_desktopName = new TCHAR[m_si.nameLength + 4 + 256];
#ifdef UNDER_CE
char *deskNameBuf = new char[m_si.nameLength + 4];
ReadString(deskNameBuf, m_si.nameLength);
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,
deskNameBuf, m_si.nameLength,
m_desktopName, m_si.nameLength+1);
delete deskNameBuf;
#else
ReadString(m_desktopName, m_si.nameLength);
#endif
// TCHAR tcDummy [MAX_PATH * 3];
// sprintf(tcDummy,"%s ",m_desktopName);
strcat(m_desktopName, " ");
SetWindowText(m_hwndMain, m_desktopName);
vnclog.Print(0, _T("Desktop name \"%s\"\n"),m_desktopName);
vnclog.Print(1, _T("Geometry %d x %d depth %d\n"),
m_si.framebufferWidth, m_si.framebufferHeight, m_si.format.depth );
//SetWindowText(m_hwndMain, m_desktopName);
if (m_pDSMPlugin->IsEnabled())
{
char szMess[255];
memset(szMess, 0, 255);
sprintf(szMess, "--- VMOpsVNC Viewer + %s-v%s",
m_pDSMPlugin->GetPluginName(),
m_pDSMPlugin->GetPluginVersion()
);
strcat(m_desktopName, szMess);
}
SetWindowText(m_hwndMain, m_desktopName);
SizeWindow();
}
void ClientConnection::SizeWindow()
{
// Find how large the desktop work area is
RECT workrect;
#ifdef _ULTRAVNCAX_
::GetClientRect( ::GetParent( m_hwndMain ), & workrect );
#else
SystemParametersInfo(SPI_GETWORKAREA, 0, &workrect, 0);
#endif
int workwidth = workrect.right - workrect.left;
int workheight = workrect.bottom - workrect.top;
vnclog.Print(2, _T("Screen work area is %d x %d\n"), workwidth, workheight);
// sf@2003 - AutoScaling
if (m_opts.m_fAutoScaling && !m_fScalingDone)
{
// We save the scales values coming from options
m_opts.m_saved_scale_num = m_opts.m_scale_num;
m_opts.m_saved_scale_den = m_opts.m_scale_den;
m_opts.m_saved_scaling = m_opts.m_scaling;
NONCLIENTMETRICS ncm = {0};
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
int TitleBarHeight = ncm.iCaptionHeight + 10;
int nLocalHeight = workheight;
nLocalHeight -= TitleBarHeight;
//if (m_opts.m_ShowToolbar)
nLocalHeight -= (m_TBr.bottom); // Always take toolbar into account in calculation
//
// we need to consider the ratio both from width and height
// - Kelven Yang 12/14/2008
//
m_opts.m_scale_num = min((int)((workheight * 100) / m_si.framebufferHeight),
(int)((workwidth * 100) / m_si.framebufferWidth));
// m_opts.m_scale_num = (int)((nLocalHeight * 100) / m_si.framebufferHeight);
if (m_opts.m_scale_num >= 100) {
// Sheng: Do not scale larger than the actual screen size
m_opts.m_scale_num = 100;
m_opts.m_scaling = false;
} else {
m_opts.m_scaling = true;
}
m_opts.m_scale_den = 100;
m_fScalingDone = true;
}
if (!m_opts.m_fAutoScaling && m_fScalingDone)
{
// Restore scale values to the original options values
m_opts.m_scale_num = m_opts.m_saved_scale_num;
m_opts.m_scale_den = m_opts.m_saved_scale_den;
m_opts.m_scaling = m_opts.m_saved_scaling;
m_fScalingDone = false;
}
// Size the window.
// Let's find out how big a window would be needed to display the
// whole desktop (assuming no scrollbars).
RECT fullwinrect;
if (m_opts.m_scaling)
SetRect(&fullwinrect, 0, 0,
m_si.framebufferWidth * m_opts.m_scale_num / m_opts.m_scale_den,
m_si.framebufferHeight * m_opts.m_scale_num / m_opts.m_scale_den);
else
SetRect(&fullwinrect, 0, 0, m_si.framebufferWidth, m_si.framebufferHeight);
AdjustWindowRectEx(&fullwinrect,
GetWindowLong(m_hwnd, GWL_STYLE) & ~WS_VSCROLL & ~WS_HSCROLL,
FALSE, GetWindowLong(m_hwnd, GWL_EXSTYLE));
/*
AdjustWindowRectEx(&fullwinrect,
GetWindowLong(m_hwndMain, GWL_STYLE),
FALSE, GetWindowLong(m_hwndMain, GWL_EXSTYLE));
*/
m_fullwinwidth = fullwinrect.right - fullwinrect.left;
m_fullwinheight = (fullwinrect.bottom - fullwinrect.top);
m_winwidth = min(m_fullwinwidth, workwidth);
m_winheight = min(m_fullwinheight, workheight);
//SetWindowPos(m_hwnd, HWND_TOP,
if (m_opts.m_ShowToolbar)
SetWindowPos(m_hwnd, m_hwndTBwin, 0, m_TBr.bottom, m_winwidth, m_winheight, SWP_SHOWWINDOW);
else
{
SetWindowPos(m_hwnd, m_hwndTBwin, 0, 0, m_winwidth, m_winheight, SWP_SHOWWINDOW);
SetWindowPos(m_hwndTBwin, NULL ,0, 0, 0, 0, SWP_HIDEWINDOW);
}
// Hauptfenster positionieren
/*
SetRect(&fullwinrect, 0, 0, m_si.framebufferWidth * m_opts.m_scale_num / m_opts.m_scale_den,
m_si.framebufferHeight* m_opts.m_scale_num / m_opts.m_scale_den );
*/
AdjustWindowRectEx(&fullwinrect,
GetWindowLong(m_hwndMain, GWL_STYLE) & ~WS_VSCROLL & ~WS_HSCROLL,
FALSE, GetWindowLong(m_hwndMain, GWL_EXSTYLE));
m_fullwinwidth = fullwinrect.right - fullwinrect.left;
m_fullwinheight = (fullwinrect.bottom - fullwinrect.top);
//m_winwidth = min(m_fullwinwidth+16, workwidth);
m_winwidth = min(m_fullwinwidth, workwidth);
//m_winheight = min(m_fullwinheight+m_TBr.bottom + m_TBr.top+16 , workheight);
if (m_opts.m_ShowToolbar)
m_winheight = min(m_fullwinheight + m_TBr.bottom + m_TBr.top , workheight);
else
m_winheight = min(m_fullwinheight, workheight);
HWND hwndIa = HWND_TOP;
UINT flags = SWP_SHOWWINDOW;
INT x = workrect.left + (workwidth-m_winwidth) / 2;
INT y = workrect.top + (workheight-m_winheight) / 2;
INT cx = m_winwidth;
INT cy = m_winheight;
#ifdef _ULTRAVNCAX_
// no z-order manipulation.
hwndIa = NULL;
flags |= SWP_NOZORDER;
#endif
SetWindowPos(m_hwndMain, hwndIa,
x,
y,
cx, cy, flags);
#ifndef _ULTRAVNCAX_
SetForegroundWindow(m_hwndMain);
#else
SetFocus( ::GetParent( m_hwndMain ) );
#endif
if (m_opts.m_ShowToolbar)
MoveWindow(m_hwndTBwin, 0, 0, workwidth, m_TBr.bottom - m_TBr.top, TRUE);
if (m_opts.m_ShowToolbar)
MoveWindow(m_hwndTB, 0, 0, m_winwidth-200, m_TBr.bottom - m_TBr.top, TRUE);
if (m_opts.m_ShowToolbar)
ShowWindow(m_hwndTB, SW_SHOW);
else
ShowWindow(m_hwndTB, SW_HIDE);
if (m_opts.m_ShowToolbar)
ShowWindow(m_hwndTBwin, SW_SHOW);
else
ShowWindow(m_hwndTB, SW_HIDE);
}
// We keep a local copy of the whole screen. This is not strictly necessary
// for VNC, but makes scrolling & deiconifying much smoother.
void ClientConnection::CreateLocalFramebuffer()
{
omni_mutex_lock l(m_bitmapdcMutex);
// We create a bitmap which has the same pixel characteristics as
// the local display, in the hope that blitting will be faster.
TempDC hdc(m_hwnd);
if (m_hBitmap != NULL)
DeleteObject(m_hBitmap);
m_hBitmap = CreateCompatibleBitmap(hdc, m_si.framebufferWidth, m_si.framebufferHeight);
if (m_hBitmap == NULL)
throw WarningException(sz_L61);
// Select this bitmap into the DC with an appropriate palette
ObjectSelector b(m_hBitmapDC, m_hBitmap);
PaletteSelector p(m_hBitmapDC, m_hPalette);
// Modif RDV@2002 - Cache Encoding
// Modif sf@2002
if (m_opts.m_fEnableCache)
{
if (m_hCacheBitmap != NULL) DeleteObject(m_hCacheBitmap);
m_hCacheBitmap = CreateCompatibleBitmap(m_hBitmapDC, m_si.framebufferWidth, m_si.framebufferHeight);
vnclog.Print(0, _T("Cache: Cache buffer bitmap creation\n"));
}
RECT rect;
SetRect(&rect, 0,0, m_si.framebufferWidth, m_si.framebufferHeight);
COLORREF bgcol = RGB(0, 0, 50);
FillSolidRect(&rect, bgcol);
COLORREF oldbgcol = SetBkColor( m_hBitmapDC, bgcol);
COLORREF oldtxtcol = SetTextColor(m_hBitmapDC, RGB(255,255,255));
rect.right = m_si.framebufferWidth / 2;
rect.bottom = m_si.framebufferHeight / 2;
DrawText (m_hBitmapDC, sz_L62, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
SetBkColor( m_hBitmapDC, oldbgcol);
SetTextColor(m_hBitmapDC, oldtxtcol);
InvalidateRect(m_hwnd, NULL, FALSE);
}
void ClientConnection::SetupPixelFormat() {
// Have we requested a reduction to 8-bit?
if (m_opts.m_Use8Bit)
{
switch (m_opts.m_Use8Bit)
{
case rfbPF256Colors:
m_myFormat = vnc8bitFormat;
break;
case rfbPF64Colors:
m_myFormat = vnc8bitFormat_64;
break;
case rfbPF8Colors:
m_myFormat = vnc8bitFormat_8;
break;
case rfbPF8GreyColors:
m_myFormat = vnc8bitFormat_8Grey;
break;
case rfbPF4GreyColors:
m_myFormat = vnc8bitFormat_4Grey;
break;
case rfbPF2GreyColors:
m_myFormat = vnc8bitFormat_2Grey;
break;
}
vnclog.Print(2, _T("Requesting 8-bit truecolour\n"));
// We don't support colormaps so we'll ask the server to convert
}
else if (!m_si.format.trueColour)
{
// We'll just request a standard 16-bit truecolor
vnclog.Print(2, _T("Requesting 16-bit truecolour\n"));
m_myFormat = vnc16bitFormat;
}
else
{
// Normally we just use the sever's format suggestion
m_myFormat = m_si.format;
m_myFormat.bigEndian = 0; // except always little endian
// It's silly requesting more bits than our current display has, but
// in fact it doesn't usually amount to much on the network.
// Windows doesn't support 8-bit truecolour.
// If our display is palette-based, we want more than 8 bit anyway,
// unless we're going to start doing palette stuff at the server.
// So the main use would be a 24-bit true-colour desktop being viewed
// on a 16-bit true-colour display, and unless you have lots of images
// and hence lots of raw-encoded stuff, the size of the pixel is not
// going to make much difference.
// We therefore don't bother with any restrictions, but here's the
// start of the code if we wanted to do it.
if (false) {
// Get a DC for the root window
TempDC hrootdc(NULL);
int localBitsPerPixel = GetDeviceCaps(hrootdc, BITSPIXEL);
int localRasterCaps = GetDeviceCaps(hrootdc, RASTERCAPS);
vnclog.Print(2, _T("Memory DC has depth of %d and %s pallete-based.\n"),
localBitsPerPixel, (localRasterCaps & RC_PALETTE) ? "is" : "is not");
// If we're using truecolor, and the server has more bits than we do
if ( (localBitsPerPixel > m_myFormat.depth) &&
! (localRasterCaps & RC_PALETTE)) {
m_myFormat.depth = localBitsPerPixel;
// create a bitmap compatible with the current display
// call GetDIBits twice to get the colour info.
// set colour masks and shifts
}
}
}
// The endian will be set before sending
}
void ClientConnection::SetFormatAndEncodings()
{
// Set pixel format to myFormat
rfbSetPixelFormatMsg spf;
spf.type = rfbSetPixelFormat;
spf.format = m_myFormat;
spf.format.redMax = Swap16IfLE(spf.format.redMax);
spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
WriteExact((char *)&spf, sz_rfbSetPixelFormatMsg, rfbSetPixelFormat);
// The number of bytes required to hold at least one pixel.
m_minPixelBytes = (m_myFormat.bitsPerPixel + 7) >> 3;
// Set encodings
char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]);
int len = 0;
se->type = rfbSetEncodings;
se->nEncodings = 0;
bool useCompressLevel = false;
int i = 0;
// Put the preferred encoding first, and change it if the
// preferred encoding is not actually usable.
for (i = LASTENCODING; i >= rfbEncodingRaw; i--)
{
if (m_opts.m_PreferredEncoding == i) {
if (m_opts.m_UseEnc[i])
{
encs[se->nEncodings++] = Swap32IfLE(i);
if ( i == rfbEncodingZlib ||
i == rfbEncodingTight ||
i == rfbEncodingZlibHex
)
{
useCompressLevel = true;
}
}
else
{
m_opts.m_PreferredEncoding--;
}
}
}
// Now we go through and put in all the other encodings in order.
// We do rather assume that the most recent encoding is the most
// desirable!
for (i = LASTENCODING; i >= rfbEncodingRaw; i--)
{
if ( (m_opts.m_PreferredEncoding != i) &&
(m_opts.m_UseEnc[i]))
{
encs[se->nEncodings++] = Swap32IfLE(i);
if ( i == rfbEncodingZlib ||
i == rfbEncodingTight ||
i == rfbEncodingZlibHex
)
{
useCompressLevel = true;
}
}
}
// Tight - Request desired compression level if applicable
if ( useCompressLevel && m_opts.m_useCompressLevel &&
m_opts.m_compressLevel >= 0 &&
m_opts.m_compressLevel <= 9) {
encs[se->nEncodings++] = Swap32IfLE( rfbEncodingCompressLevel0 +
m_opts.m_compressLevel );
}
// Tight - Request cursor shape updates if enabled by user
if (m_opts.m_requestShapeUpdates) {
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
if (!m_opts.m_ignoreShapeUpdates)
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); // marscha PointerPos
}
// Tight - Request JPEG quality level if JPEG compression was enabled by user
if ( m_opts.m_enableJpegCompression &&
m_opts.m_jpegQualityLevel >= 0 &&
m_opts.m_jpegQualityLevel <= 9) {
encs[se->nEncodings++] = Swap32IfLE( rfbEncodingQualityLevel0 +
m_opts.m_jpegQualityLevel );
}
// Modif rdv@2002
//Tell the server that we support the special Zlibencoding
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXOREnable);
// Tight - LastRect - SINGLE WINDOW
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize);
// Modif sf@2002
if (m_opts.m_fEnableCache)
{
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCacheEnable);
// vnclog.Print(0, _T("Cache: Enable Cache sent to Server\n"));
}
// len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
// sf@2002 - DSM Plugin
int nEncodings = se->nEncodings;
se->nEncodings = Swap16IfLE(se->nEncodings);
// WriteExact((char *)buf, len);
WriteExact((char *)buf, sz_rfbSetEncodingsMsg, rfbSetEncodings);
for (int x = 0; x < nEncodings; x++)
{
WriteExact((char *)&encs[x], sizeof(CARD32));
}
}
void ClientConnection::Createdib()
{
omni_mutex_lock l(m_bitmapdcMutex);
TempDC hdc(m_hwnd);
BitmapInfo bi;
UINT iUsage;
memset(&bi, 0, sizeof(bi));
iUsage = m_myFormat.trueColour ? DIB_RGB_COLORS : DIB_PAL_COLORS;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = m_myFormat.bitsPerPixel;
bi.bmiHeader.biSizeImage = (m_myFormat.bitsPerPixel / 8) * m_si.framebufferWidth * m_si.framebufferHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biWidth = m_si.framebufferWidth;
bi.bmiHeader.biHeight = -m_si.framebufferHeight;
bi.bmiHeader.biCompression = (m_myFormat.bitsPerPixel > 8) ? BI_BITFIELDS : BI_RGB;
bi.mask.red = m_myFormat.redMax << m_myFormat.redShift;
bi.mask.green = m_myFormat.greenMax << m_myFormat.greenShift;
bi.mask.blue = m_myFormat.blueMax << m_myFormat.blueShift;
if (m_hmemdc != NULL) {DeleteDC(m_hmemdc);m_hmemdc = NULL;m_DIBbits=NULL;}
if (m_membitmap != NULL) {DeleteObject(m_membitmap);m_membitmap= NULL;}
// m_hmemdc = CreateCompatibleDC(hdc);
m_hmemdc = CreateCompatibleDC(m_hBitmapDC);
m_membitmap = CreateDIBSection(m_hmemdc, (BITMAPINFO*)&bi.bmiHeader, iUsage, &m_DIBbits, NULL, 0);
ObjectSelector bb(m_hmemdc, m_membitmap);
if (m_myFormat.bitsPerPixel==8 && m_myFormat.trueColour)
{
struct Colour {
int r, g, b;
};
Colour rgbQ[256];
/*UINT num_entries;
num_entries =GetPaletteEntries(m_hPalette, 0, 0, NULL);
size_t pal_size = sizeof(LOGPALETTE) +(num_entries - 1) * sizeof(PALETTEENTRY);
LOGPALETTE* pLogPal =(LOGPALETTE*) new unsigned char[pal_size];
UINT num_got = GetPaletteEntries( m_hPalette, 0, num_entries, pLogPal->palPalEntry);
for (UINT i=0; i<num_got; ++i)
{
rgbQ[i].rgbRed = pLogPal->palPalEntry[i].peRed;
rgbQ[i].rgbGreen = pLogPal->palPalEntry[i].peGreen;
rgbQ[i].rgbBlue = pLogPal-> palPalEntry[i].peBlue;
}
delete [] pLogPal;*/
for (int i=0; i < (1<<(m_myFormat.depth)); i++) {
rgbQ[i].b = ((((i >> m_myFormat.blueShift) & m_myFormat.blueMax) * 65535) + m_myFormat.blueMax/2) / m_myFormat.blueMax;
rgbQ[i].g = ((((i >> m_myFormat.greenShift) & m_myFormat.greenMax) * 65535) + m_myFormat.greenMax/2) / m_myFormat.greenMax;
rgbQ[i].r = ((((i >> m_myFormat.redShift) & m_myFormat.redMax) * 65535) + m_myFormat.redMax/2) / m_myFormat.redMax;
}
for (i=0; i<256; i++)
{
bi.color[i].rgbRed = rgbQ[i].r >> 8;
bi.color[i].rgbGreen = rgbQ[i].g >> 8;
bi.color[i].rgbBlue = rgbQ[i].b >> 8;
bi.color[i].rgbReserved = 0;
}
SetDIBColorTable(m_hmemdc, 0, 256, bi.color);
}
}
// Closing down the connection.
// Close the socket, kill the thread.
void ClientConnection::KillThread()
{
#ifdef _ULTRAVNCAX_
if ( m_bKillThread )
return;
#endif
m_bKillThread = true;
m_running = false;
if (m_sock != INVALID_SOCKET) {
shutdown(m_sock, SD_BOTH);
closesocket(m_sock);
m_sock = INVALID_SOCKET;
}
#ifdef _ULTRAVNCAX_
if ( m_threadStarted )
#endif
WaitForSingleObject(KillEvent, 100000);
}
ClientConnection::~ClientConnection()
{
if (m_hwndStatus)
EndDialog(m_hwndStatus,0);
if (m_pNetRectBuf != NULL)
delete [] m_pNetRectBuf;
#ifndef _ULTRAVNCAX_
LowLevelHook::Release();
#endif
// Modif sf@2002 - FileTransfer
if (m_pFileTransfer)
delete(m_pFileTransfer);
// Modif sf@2002 - Text Chat
if (m_pTextChat)
delete(m_pTextChat);
// Modif sf@2002 - DSMPlugin handling
if (m_pDSMPlugin != NULL)
delete(m_pDSMPlugin);
if (zis)
delete zis;
if (fis)
delete fis;
if (m_pZRLENetRectBuf != NULL)
delete [] m_pZRLENetRectBuf;
if (m_sock != INVALID_SOCKET) {
shutdown(m_sock, SD_BOTH);
closesocket(m_sock);
m_sock = INVALID_SOCKET;
}
if (m_desktopName != NULL) delete [] m_desktopName;
delete [] m_netbuf;
if (m_hCacheBitmapDC != NULL)
DeleteDC(m_hCacheBitmapDC);
if (m_hCacheBitmapDC != NULL)
DeleteObject(m_hCacheBitmapDC);
if (m_hCacheBitmap != NULL)
DeleteObject(m_hCacheBitmap);
if (m_hBitmapDC != NULL)
DeleteDC(m_hBitmapDC);
if (m_hBitmapDC != NULL)
DeleteObject(m_hBitmapDC);
if (m_hBitmap != NULL)
DeleteObject(m_hBitmap);
if (m_hPalette != NULL)
DeleteObject(m_hPalette);
//UltraFast
if (m_hmemdc != NULL) {DeleteDC(m_hmemdc);m_hmemdc = NULL;m_DIBbits=NULL;}
if (m_membitmap != NULL) {DeleteObject(m_membitmap);m_membitmap = NULL;}
// if (flash) delete flash;
m_pApp->DeregisterConnection(this);
if (m_zipbuf!=NULL)
delete [] m_zipbuf;
if (m_filezipbuf!=NULL)
delete [] m_filezipbuf;
if (m_filechunkbuf!=NULL)
delete [] m_filechunkbuf;
if (m_zlibbuf!=NULL)
delete [] m_zlibbuf;
if (m_hwndTBwin!= 0)
DestroyWindow(m_hwndTBwin);
if (rcSource!=NULL)
delete[] rcSource;
if (rcMask!=NULL)
delete[] rcMask;
CloseHandle(KillEvent);
}
// You can specify a dx & dy outside the limits; the return value will
// tell you whether it actually scrolled.
bool ClientConnection::ScrollScreen(int dx, int dy)
{
dx = max(dx, -m_hScrollPos);
dx = min(dx, m_hScrollMax-(m_cliwidth)-m_hScrollPos);
dy = max(dy, -m_vScrollPos);
dy = min(dy, m_vScrollMax-(m_cliheight)-m_vScrollPos);
if (dx || dy) {
m_hScrollPos += dx;
m_vScrollPos += dy;
RECT clirect;
RECT Rtb;
GetClientRect(m_hwndMain, &clirect);
if (m_opts.m_ShowToolbar)
GetClientRect(m_hwndTBwin, &Rtb);
else
{
Rtb.top=0;
Rtb.bottom=0;
}
clirect.top += Rtb.top;
clirect.bottom += Rtb.bottom;
ScrollWindowEx(m_hwnd, -dx, -dy, NULL, &clirect, NULL, NULL, SW_INVALIDATE);
UpdateScrollbars();
UpdateWindow(m_hwnd);
return true;
}
return false;
}
// ProcessPointerEvent handles the delicate case of emulating 3 buttons
// on a two button mouse, then passes events off to SubProcessPointerEvent.
inline void ClientConnection::ProcessPointerEvent(int x, int y, DWORD keyflags, UINT msg)
{
if (m_opts.m_Emul3Buttons) {
// XXX To be done:
// If this is a left or right press, the user may be
// about to press the other button to emulate a middle press.
// We need to start a timer, and if it expires without any
// further presses, then we send the button press.
// If a press of the other button, or any release, comes in
// before timer has expired, we cancel timer & take different action.
if (m_waitingOnEmulateTimer)
{
if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP ||
abs(x - m_emulateButtonPressedX) > m_opts.m_Emul3Fuzz ||
abs(y - m_emulateButtonPressedY) > m_opts.m_Emul3Fuzz)
{
// if button released or we moved too far then cancel.
// First let the remote know where the button was down
SubProcessPointerEvent(
m_emulateButtonPressedX,
m_emulateButtonPressedY,
m_emulateKeyFlags);
// Then tell it where we are now
SubProcessPointerEvent(x, y, keyflags);
}
else if (
(msg == WM_LBUTTONDOWN && (m_emulateKeyFlags & MK_RBUTTON))
|| (msg == WM_RBUTTONDOWN && (m_emulateKeyFlags & MK_LBUTTON)))
{
// Triggered an emulate; remove left and right buttons, put
// in middle one.
DWORD emulatekeys = keyflags & ~(MK_LBUTTON|MK_RBUTTON);
emulatekeys |= MK_MBUTTON;
SubProcessPointerEvent(x, y, emulatekeys);
m_emulatingMiddleButton = true;
}
else
{
// handle movement normally & don't kill timer.
// just remove the pressed button from the mask.
DWORD keymask = m_emulateKeyFlags & (MK_LBUTTON|MK_RBUTTON);
DWORD emulatekeys = keyflags & ~keymask;
SubProcessPointerEvent(x, y, emulatekeys);
return;
}
// if we reached here, we don't need the timer anymore.
KillTimer(m_hwnd, m_emulate3ButtonsTimer);
m_waitingOnEmulateTimer = false;
}
else if (m_emulatingMiddleButton)
{
if ((keyflags & MK_LBUTTON) == 0 && (keyflags & MK_RBUTTON) == 0)
{
// We finish emulation only when both buttons come back up.
m_emulatingMiddleButton = false;
SubProcessPointerEvent(x, y, keyflags);
}
else
{
// keep emulating.
DWORD emulatekeys = keyflags & ~(MK_LBUTTON|MK_RBUTTON);
emulatekeys |= MK_MBUTTON;
SubProcessPointerEvent(x, y, emulatekeys);
}
}
else
{
// Start considering emulation if we've pressed a button
// and the other isn't pressed.
if ( (msg == WM_LBUTTONDOWN && !(keyflags & MK_RBUTTON))
|| (msg == WM_RBUTTONDOWN && !(keyflags & MK_LBUTTON)))
{
// Start timer for emulation.
m_emulate3ButtonsTimer =
SetTimer(
m_hwnd,
IDT_EMULATE3BUTTONSTIMER,
m_opts.m_Emul3Timeout,
NULL);
if (!m_emulate3ButtonsTimer)
{
vnclog.Print(0, _T("Failed to create timer for emulating 3 buttons"));
PostMessage(m_hwndMain, WM_CLOSE, 0, 0);
return;
}
m_waitingOnEmulateTimer = true;
// Note that we don't send the event here; we're batching it for
// later.
m_emulateKeyFlags = keyflags;
m_emulateButtonPressedX = x;
m_emulateButtonPressedY = y;
}
else
{
// just send event noramlly
SubProcessPointerEvent(x, y, keyflags);
}
}
}
else
{
SubProcessPointerEvent(x, y, keyflags);
}
}
// SubProcessPointerEvent takes windows positions and flags and converts
// them into VNC ones.
inline void ClientConnection::SubProcessPointerEvent(int x, int y, DWORD keyflags)
{
int mask;
if (m_opts.m_SwapMouse) {
mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) |
((keyflags & MK_MBUTTON) ? rfbButton3Mask : 0) |
((keyflags & MK_RBUTTON) ? rfbButton2Mask : 0) );
} else {
mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) |
((keyflags & MK_MBUTTON) ? rfbButton2Mask : 0) |
((keyflags & MK_RBUTTON) ? rfbButton3Mask : 0) );
}
if ((short)HIWORD(keyflags) > 0) {
mask |= rfbButton4Mask;
} else if ((short)HIWORD(keyflags) < 0) {
mask |= rfbButton5Mask;
}
try {
int x_scaled =
(x + m_hScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num;
int y_scaled =
(y + m_vScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num;
SendPointerEvent(x_scaled, y_scaled, mask);
if ((short)HIWORD(keyflags) != 0) {
// Immediately send a "button-up" after mouse wheel event.
mask &= !(rfbButton4Mask | rfbButton5Mask);
SendPointerEvent(x_scaled, y_scaled, mask);
}
} catch (Exception &e) {
e.Report();
PostMessage(m_hwndMain, WM_CLOSE, 0, 0);
}
}
//
// RealVNC 335 method
//
inline void ClientConnection::ProcessMouseWheel(int delta)
{
int wheelMask = rfbWheelUpMask;
if (delta < 0) {
wheelMask = rfbWheelDownMask;
delta = -delta;
}
while (delta > 0) {
SendPointerEvent(oldPointerX, oldPointerY, oldButtonMask | wheelMask);
SendPointerEvent(oldPointerX, oldPointerY, oldButtonMask & ~wheelMask);
delta -= 120;
}
}
//
// SendPointerEvent.
//
inline void
ClientConnection::SendPointerEvent(int x, int y, int buttonMask)
{
if (m_pFileTransfer->m_fFileTransferRunning && ( m_pFileTransfer->m_fVisible || m_pFileTransfer->m_fOldFTProtocole)) return;
if (m_pTextChat->m_fTextChatRunning && m_pTextChat->m_fVisible) return;
//omni_mutex_lock l(m_UpdateMutex);
/*
newtick=GetTickCount();
if ((newtick-oldtick)<100) return;
oldtick=newtick;
*/
rfbPointerEventMsg pe;
oldPointerX = x;
oldPointerY = y;
oldButtonMask = buttonMask;
pe.type = rfbPointerEvent;
pe.buttonMask = buttonMask;
if (x < 0) x = 0;
if (y < 0) y = 0;
// tight cursor handling
SoftCursorMove(x, y);
pe.x = Swap16IfLE(x);
pe.y = Swap16IfLE(y);
WriteExact((char *)&pe, sz_rfbPointerEventMsg, rfbPointerEvent); // sf@2002 - For DSM Plugin
}
//
// ProcessKeyEvent
//
// Normally a single Windows key event will map onto a single RFB
// key message, but this is not always the case. Much of the stuff
// here is to handle AltGr (=Ctrl-Alt) on international keyboards.
// Example cases:
//
// We want Ctrl-F to be sent as:
// Ctrl-Down, F-Down, F-Up, Ctrl-Up.
// because there is no keysym for ctrl-f, and because the ctrl
// will already have been sent by the time we get the F.
//
// On German keyboards, @ is produced using AltGr-Q, which is
// Ctrl-Alt-Q. But @ is a valid keysym in its own right, and when
// a German user types this combination, he doesn't mean Ctrl-@.
// So for this we will send, in total:
//
// Ctrl-Down, Alt-Down,
// (when we get the AltGr pressed)
//
// Alt-Up, Ctrl-Up, @-Down, Ctrl-Down, Alt-Down
// (when we discover that this is @ being pressed)
//
// Alt-Up, Ctrl-Up, @-Up, Ctrl-Down, Alt-Down
// (when we discover that this is @ being released)
//
// Alt-Up, Ctrl-Up
// (when the AltGr is released)
inline void ClientConnection::ProcessKeyEvent(int virtkey, DWORD keyData)
{
bool down = ((keyData & 0x80000000l) == 0);
// if virtkey found in mapping table, send X equivalent
// else
// try to convert directly to ascii
// if result is in range supported by X keysyms,
// raise any modifiers, send it, then restore mods
// else
// calculate what the ascii would be without mods
// send that
#ifdef _DEBUG
#ifdef UNDER_CE
char *keyname="";
#else
char keyname[32];
if (GetKeyNameText( keyData,keyname, 31)) {
// vnclog.Print(4, _T("Process key: %s (keyData %04x): virtkey %04x "), keyname, keyData,virtkey);
// if (virtkey==0x00dd)
// vnclog.Print(4, _T("Process key: %s (keyData %04x): virtkey %04x "), keyname, keyData,virtkey);
};
#endif
#endif
try {
KeyActionSpec kas = m_keymap.PCtoX(virtkey, keyData);
if (kas.releaseModifiers & KEYMAP_LCONTROL) {
SendKeyEvent(XK_Control_L, false );
vnclog.Print(5, _T("fake L Ctrl raised\n"));
}
if (kas.releaseModifiers & KEYMAP_LALT) {
SendKeyEvent(XK_Alt_L, false );
vnclog.Print(5, _T("fake L Alt raised\n"));
}
if (kas.releaseModifiers & KEYMAP_RCONTROL) {
SendKeyEvent(XK_Control_R, false );
vnclog.Print(5, _T("fake R Ctrl raised\n"));
}
if (kas.releaseModifiers & KEYMAP_RALT) {
SendKeyEvent(XK_Alt_R, false );
vnclog.Print(5, _T("fake R Alt raised\n"));
}
for (int i = 0; kas.keycodes[i] != XK_VoidSymbol && i < MaxKeysPerKey; i++) {
SendKeyEvent(kas.keycodes[i], down );
//vnclog.Print(4, _T("Sent keysym %04x (%s)\n"),
// kas.keycodes[i], down ? _T("press") : _T("release"));
}
if (kas.releaseModifiers & KEYMAP_RALT) {
SendKeyEvent(XK_Alt_R, true );
vnclog.Print(5, _T("fake R Alt pressed\n"));
}
if (kas.releaseModifiers & KEYMAP_RCONTROL) {
SendKeyEvent(XK_Control_R, true );
vnclog.Print(5, _T("fake R Ctrl pressed\n"));
}
if (kas.releaseModifiers & KEYMAP_LALT) {
SendKeyEvent(XK_Alt_L, false );
vnclog.Print(5, _T("fake L Alt pressed\n"));
}
if (kas.releaseModifiers & KEYMAP_LCONTROL) {
SendKeyEvent(XK_Control_L, false );
vnclog.Print(5, _T("fake L Ctrl pressed\n"));
}
} catch (Exception &e) {
e.Report();
PostMessage(m_hwndMain, WM_CLOSE, 0, 0);
}
}
//
// SendKeyEvent
//
inline void
ClientConnection::SendKeyEvent(CARD32 key, bool down)
{
if (m_pFileTransfer->m_fFileTransferRunning && ( m_pFileTransfer->m_fVisible || m_pFileTransfer->m_fOldFTProtocole)) return;
if (m_pTextChat->m_fTextChatRunning && m_pTextChat->m_fVisible) return;
rfbKeyEventMsg ke;
ke.type = rfbKeyEvent;
ke.down = down ? 1 : 0;
ke.key = Swap32IfLE(key);
WriteExact((char *)&ke, sz_rfbKeyEventMsg, rfbKeyEvent);
//vnclog.Print(0, _T("SendKeyEvent: key = x%04x status = %s ke.key=%d\n"), key,
// down ? _T("down") : _T("up"),ke.key);
}
#ifndef UNDER_CE
//
// SendClientCutText
//
void ClientConnection::SendClientCutText(char *str, int len)
{
if (m_pFileTransfer->m_fFileTransferRunning && ( m_pFileTransfer->m_fVisible || m_pFileTransfer->m_fOldFTProtocole)) return;
if (m_pTextChat->m_fTextChatRunning && m_pTextChat->m_fVisible) return;
rfbClientCutTextMsg cct;
cct.type = rfbClientCutText;
cct.length = Swap32IfLE(len);
WriteExact((char *)&cct, sz_rfbClientCutTextMsg, rfbClientCutText);
WriteExact(str, len);
vnclog.Print(6, _T("Sent %d bytes of clipboard\n"), len);
}
#endif
// Copy any updated areas from the bitmap onto the screen.
inline void ClientConnection::DoBlit()
{
if (m_hBitmap == NULL) return;
if (!m_running) return;
// No other threads can use bitmap DC
omni_mutex_lock l(m_bitmapdcMutex);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(m_hwnd, &ps);
// Select and realize hPalette
PaletteSelector p(hdc, m_hPalette);
ObjectSelector b(m_hBitmapDC, m_hBitmap);
if (m_opts.m_delay) {
// Display the area to be updated for debugging purposes
COLORREF oldbgcol = SetBkColor(hdc, RGB(0,0,0));
::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &ps.rcPaint, NULL, 0, NULL);
SetBkColor(hdc,oldbgcol);
::Sleep(m_pApp->m_options.m_delay);
}
if (m_opts.m_scaling)
{
int n = m_opts.m_scale_num;
int d = m_opts.m_scale_den;
SetStretchBltMode(hdc, HALFTONE);
SetBrushOrgEx(hdc, 0,0, NULL);
{
if(UltraFast && m_hmemdc)
{
ObjectSelector bb(m_hmemdc, m_membitmap);
StretchBlt(
hdc,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right-ps.rcPaint.left,
ps.rcPaint.bottom-ps.rcPaint.top,
m_hmemdc,
(ps.rcPaint.left+m_hScrollPos) * d / n,
(ps.rcPaint.top+m_vScrollPos) * d / n,
(ps.rcPaint.right-ps.rcPaint.left) * d / n,
(ps.rcPaint.bottom-ps.rcPaint.top) * d / n,
SRCCOPY);
}
else
{
if (!StretchBlt(
hdc,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right-ps.rcPaint.left,
ps.rcPaint.bottom-ps.rcPaint.top,
m_hBitmapDC,
(ps.rcPaint.left+m_hScrollPos) * d / n,
(ps.rcPaint.top+m_vScrollPos) * d / n,
(ps.rcPaint.right-ps.rcPaint.left) * d / n,
(ps.rcPaint.bottom-ps.rcPaint.top) * d / n,
SRCCOPY))
{
vnclog.Print(0, _T("Blit error %d\n"), GetLastError());
// throw ErrorException("Error in blit!\n");
};
}
}
}
else
{
if (UltraFast && m_hmemdc)
{
ObjectSelector bb(m_hmemdc, m_membitmap);
BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top,
m_hmemdc, ps.rcPaint.left+m_hScrollPos, ps.rcPaint.top+m_vScrollPos, SRCCOPY);
}
else
{
if (!BitBlt(
hdc,
ps.rcPaint.left,
ps.rcPaint.top ,
ps.rcPaint.right-ps.rcPaint.left,
ps.rcPaint.bottom-ps.rcPaint.top ,
m_hBitmapDC,
ps.rcPaint.left+m_hScrollPos,
//ps.rcPaint.top +m_vScrollPos- (m_TBr.bottom - m_TBr.top) , SRCCOPY))
ps.rcPaint.top +m_vScrollPos,
SRCCOPY))
{
vnclog.Print(0, _T("Blit error %d\n"), GetLastError());
// throw ErrorException("Error in blit!\n");
}
}
}
EndPaint(m_hwnd, &ps);
}
inline void ClientConnection::UpdateScrollbars()
{
// We don't update the actual scrollbar info in full-screen mode
// because it causes them to flicker.
bool setInfo = !InFullScreenMode();
SCROLLINFO scri;
scri.cbSize = sizeof(scri);
scri.fMask = SIF_ALL;
scri.nMin = 0;
scri.nMax = m_hScrollMax;
scri.nPage= m_cliwidth;
scri.nPos = m_hScrollPos;
if (setInfo)
SetScrollInfo(m_hwndMain, SB_HORZ, &scri, TRUE);
scri.cbSize = sizeof(scri);
scri.fMask = SIF_ALL;
scri.nMin = 0;
scri.nMax = m_vScrollMax ;
scri.nPage= m_cliheight;
scri.nPos = m_vScrollPos;
if (setInfo)
SetScrollInfo(m_hwndMain, SB_VERT, &scri, TRUE);
}
void ClientConnection::ShowConnInfo()
{
TCHAR buf[2048];
#ifndef UNDER_CE
char kbdname[9];
GetKeyboardLayoutName(kbdname);
#else
TCHAR *kbdname = _T("(n/a)");
#endif
TCHAR num[16];
_stprintf(
buf,
_T("Connected to: %s\n\r\n\r")
_T("Host: %s Port: %d\n\r")
_T("%s %s %s\n\r\n\r")
_T("Desktop geometry: %d x %d x %d\n\r")
_T("Using depth: %d\n\r")
_T("Line speed estimate: %d kbit/s\n")
_T("Current protocol version: %d.%d\n\r\n\r")
_T("Current keyboard name: %s\n\r\n\r")
_T("Using Plugin : %s - %s\n\r\n\r"), // sf@2002 - v1.1.2
m_desktopName, m_host, m_port,
strcmp(m_proxyhost,"") ? m_proxyhost : "",
strcmp(m_proxyhost,"") ? "Port" : "",
strcmp(m_proxyhost,"") ? itoa(m_proxyport, num, 10) : "",
m_si.framebufferWidth, m_si.framebufferHeight,
m_si.format.depth,
m_myFormat.depth, kbitsPerSecond,
m_majorVersion, m_minorVersion,
kbdname,
m_pDSMPlugin->IsEnabled() ? m_pDSMPlugin->GetPluginName() : "",
m_pDSMPlugin->IsEnabled() ? m_pDSMPlugin->GetPluginVersion() : "");
MessageBox(NULL, buf, _T("Connection info"), MB_ICONINFORMATION | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
}
// ********************************************************************
// Methods after this point are generally called by the worker thread.
// They finish the initialisation, then chiefly read data from the server.
// ********************************************************************
void* ClientConnection::run_undetached(void* arg) {
vnclog.Print(9,_T("Update-processing thread started\n"));
m_threadStarted = true;
try
{
// Modif sf@2002 - Server Scaling
m_nServerScale = m_opts.m_nServerScale;
if (m_nServerScale > 1) SendServerScale(m_nServerScale);
SendFullFramebufferUpdateRequest();
SizeWindow();
RealiseFullScreenMode();
if (!InFullScreenMode()) SizeWindow();
m_running = true;
UpdateWindow(m_hwnd);
// sf@2002 - Attempt to speed up the thing
// omni_thread::set_priority(omni_thread::PRIORITY_LOW);
rdr::U8 msgType;
while (!m_bKillThread)
{
// sf@2002 - DSM Plugin
if (!m_fUsePlugin)
{
msgType = fis->readU8();
m_nTO = 1; // Read the rest of the rfb message (normal case)
}
else if (m_pDSMPlugin->IsEnabled())
{
// Read the additional type char sent by the DSM Plugin (server)
// We need it to know the type of rfb message that follows
// because we can't see the type inside the transformed rfb message.
ReadExact((char *)&msgType, sizeof(msgType));
m_nTO = 0; // we'll need to read the whole transformed rfb message that follows
}
switch (msgType)
{
case rfbFramebufferUpdate:
ReadScreenUpdate();
break;
case rfbSetColourMapEntries:
vnclog.Print(3, _T("rfbSetColourMapEntries read but not supported\n") );
throw WarningException(sz_L63);
break;
case rfbBell:
ReadBell();
break;
case rfbServerCutText:
ReadServerCutText();
break;
// Modif sf@2002 - FileTransfer
// File Transfer Message
case rfbFileTransfer:
{
// vnclog.Print(0, _T("rfbFileTransfer\n") );
// m_pFileTransfer->ProcessFileTransferMsg();
// sf@2005 - FileTransfer rfbMessage and screen updates must be sent/received
// by the same thread
SendMessage(m_hwndMain, FileTransferSendPacketMessage, 1, 0);
}
break;
// Modif sf@2002 - Text Chat
case rfbTextChat:
m_pTextChat->ProcessTextChatMsg();
break;
// Modif sf@2002 - Server Scaling
// Server Scaled screen buffer size has changed, so we resize
// the viewer window
case rfbResizeFrameBuffer:
{
rfbResizeFrameBufferMsg rsmsg;
ReadExact(((char*)&rsmsg) + m_nTO, sz_rfbResizeFrameBufferMsg - m_nTO);
m_si.framebufferWidth = Swap16IfLE(rsmsg.framebufferWidth);
m_si.framebufferHeight = Swap16IfLE(rsmsg.framebufferHeigth);
ClearCache();
CreateLocalFramebuffer();
// SendFullFramebufferUpdateRequest();
Createdib();
m_pendingScaleChange = true;
m_pendingFormatChange = true;
SendAppropriateFramebufferUpdateRequest();
SizeWindow();
InvalidateRect(m_hwnd, NULL, TRUE);
RealiseFullScreenMode();
break;
}
default:
vnclog.Print(3, _T("Unknown message type x%02x\n"), msgType );
throw WarningException(sz_L64);
break;
/*
default:
log.Print(3, _T("Unknown message type x%02x\n"), msgType );
throw WarningException("Unhandled message type received!\n");
*/
}
// yield();
}
}
catch (WarningException)
{
// sf@2002
// m_pFileTransfer->m_fFileTransferRunning = false;
// m_pTextChat->m_fTextChatRunning = false;
PostMessage(m_hwndMain, WM_CLOSE, 0, 0);
}
catch (QuietException &e)
{
// sf@2002
// m_pFileTransfer->m_fFileTransferRunning = false;
// m_pTextChat->m_fTextChatRunning = false;
PostMessage(m_hwndMain, WM_CLOSE, 0, 0);
}
catch (rdr::Exception& e)
{
vnclog.Print(0,"rdr::Exception (1): %s\n",e.str());
// m_pFileTransfer->m_fFileTransferRunning = false;
// m_pTextChat->m_fTextChatRunning = false;
// throw QuietException(e.str());
PostMessage(m_hwndMain, WM_CLOSE, 0, 0);
}
SetEvent(KillEvent);
// sf@2002
m_pFileTransfer->m_fFileTransferRunning = false;
m_pTextChat->m_fTextChatRunning = false;
vnclog.Print(4, _T("Update-processing thread finishing\n") );
return this;
}
//
// Requesting screen updates from the server
//
inline void
ClientConnection::SendFramebufferUpdateRequest(int x, int y, int w, int h, bool incremental)
{
if (m_pFileTransfer->m_fFileTransferRunning && ( m_pFileTransfer->m_fVisible || m_pFileTransfer->m_fOldFTProtocole)) return;
if (m_pTextChat->m_fTextChatRunning && m_pTextChat->m_fVisible) return;
//omni_mutex_lock l(m_UpdateMutex);
rfbFramebufferUpdateRequestMsg fur;
// vnclog.Print(0, _T("Request %s update x=%d,y=%d,w=%d,h=%d\n"), incremental ? _T("incremental") : _T("full"),x,y,w,h);
fur.type = rfbFramebufferUpdateRequest;
fur.incremental = incremental ? 1 : 0;
fur.x = Swap16IfLE(x);
fur.y = Swap16IfLE(y);
fur.w = Swap16IfLE(w);
fur.h = Swap16IfLE(h);
//vnclog.Print(10, _T("Request %s update\n"), incremental ? _T("incremental") : _T("full"));
WriteExact((char *)&fur, sz_rfbFramebufferUpdateRequestMsg, rfbFramebufferUpdateRequest);
}
inline void ClientConnection::SendIncrementalFramebufferUpdateRequest()
{
SendFramebufferUpdateRequest(0, 0, m_si.framebufferWidth,
m_si.framebufferHeight, true);
}
void ClientConnection::SendFullFramebufferUpdateRequest()
{
SendFramebufferUpdateRequest(0, 0, m_si.framebufferWidth,
m_si.framebufferHeight, false);
}
void ClientConnection::SendAppropriateFramebufferUpdateRequest()
{
if (m_pendingFormatChange)
{
vnclog.Print(3, _T("Requesting new pixel format\n") );
// Cache init/reinit - A SetFormatAndEncoding() implies a cache reinit on server side
// Cache enabled, so it's going to be reallocated/reinited on server side
if (m_opts.m_fEnableCache)
{
// create viewer cache buffer if necessary
if (m_hCacheBitmap == NULL)
{
m_hCacheBitmapDC = CreateCompatibleDC(m_hBitmapDC);
m_hCacheBitmap = CreateCompatibleBitmap(m_hBitmapDC, m_si.framebufferWidth, m_si.framebufferHeight);
}
ClearCache(); // Clear the cache
m_pendingCacheInit = true; // Order full update to synchronize both sides caches
}
else // No cache requested - The cache on the other side is to be cleared/deleted
// Todo: fix the cache switching pb when viewer has been started without cache
{
/* causes balck rects after cache off/on
// Delete local cache
DeleteDC(m_hCacheBitmapDC);
if (m_hCacheBitmap != NULL) DeleteObject(m_hCacheBitmap);
if (m_hCacheBitmapDC != NULL) DeleteObject(m_hCacheBitmapDC);
m_hCacheBitmap = NULL;
m_pendingCacheInit = false;
*/
}
rfbPixelFormat oldFormat = m_myFormat;
SetupPixelFormat();
// tight cursor handling
SoftCursorFree();
Createdib();
SetFormatAndEncodings();
m_pendingFormatChange = false;
// If the pixel format has changed, or cache, or scale request whole screen
if (!PF_EQ(m_myFormat, oldFormat) || m_pendingCacheInit || m_pendingScaleChange)
{
SendFullFramebufferUpdateRequest();
}
else
{
SendIncrementalFramebufferUpdateRequest();
}
m_pendingScaleChange = false;
m_pendingCacheInit = false;
}
else
{
if (!m_dormant)
SendIncrementalFramebufferUpdateRequest();
}
}
//
// Modif sf@2002 - Server Scaling
//
bool ClientConnection::SendServerScale(int nScale)
{
rfbSetScaleMsg ssc;
int len = 0;
ssc.type = rfbSetScale;
ssc.scale = /*(unsigned short)*/ nScale;
WriteExact((char*)&ssc, sz_rfbSetScaleMsg, rfbSetScale);
return true;
}
//
// Modif rdv@2002 - Set Server input
//
bool ClientConnection::SendServerInput(BOOL enabled)
{
rfbSetServerInputMsg sim;
int len = 0;
sim.type = rfbSetServerInput;
sim.status = enabled;
WriteExact((char*)&sim, sz_rfbSetServerInputMsg, rfbSetServerInput);
return true;
}
//
// Modif rdv@2002 - Single window
//
bool ClientConnection::SendSW(int x, int y)
{
rfbSetSWMsg sw;
int len = 0;
if (x==9999 && y==9999)
{
sw.type = rfbSetSW;
sw.x = Swap16IfLE(1);
sw.y = Swap16IfLE(1);
}
else
{
int x_scaled =
(x + m_hScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num;
int y_scaled =
(y + m_vScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num;
sw.type = rfbSetSW;
sw.x = Swap16IfLE(x_scaled);
sw.y = Swap16IfLE(y_scaled);
}
WriteExact((char*)&sw, sz_rfbSetSWMsg, rfbSetSW);
m_SWselect=false;
return true;
}
// A ScreenUpdate message has been received
inline void ClientConnection::ReadScreenUpdate()
{
HDC hdcX,hdcBits;
bool fTimingAlreadyStopped = false;
fis->startTiming();
rfbFramebufferUpdateMsg sut;
ReadExact(((char *) &sut)+m_nTO, sz_rfbFramebufferUpdateMsg-m_nTO);
sut.nRects = Swap16IfLE(sut.nRects);
HRGN UpdateRegion=CreateRectRgn(0,0,0,0);
bool Recover_from_sync=false;
//if (sut.nRects == 0) return; XXX tjr removed this - is this OK?
for (UINT i=0; i < sut.nRects; i++)
{
rfbFramebufferUpdateRectHeader surh;
ReadExact((char *) &surh, sz_rfbFramebufferUpdateRectHeader);
surh.r.x = Swap16IfLE(surh.r.x);
surh.r.y = Swap16IfLE(surh.r.y);
surh.r.w = Swap16IfLE(surh.r.w);
surh.r.h = Swap16IfLE(surh.r.h);
surh.encoding = Swap32IfLE(surh.encoding);
// vnclog.Print(0, _T("%d %d\n"), i,sut.nRects);
//vnclog.Print(0, _T("encoding %d\n"), surh.encoding);
// Tight - If lastrect we must quit this loop (nRects = 0xFFFF)
if (surh.encoding == rfbEncodingLastRect)
break;
if (surh.encoding == rfbEncodingNewFBSize)
{
ReadNewFBSize(&surh);
break;
}
// Tight cursor handling
if ( surh.encoding == rfbEncodingXCursor ||
surh.encoding == rfbEncodingRichCursor )
{
ReadCursorShape(&surh);
continue;
}
// marscha PointerPos
if (surh.encoding == rfbEncodingPointerPos) {
//vnclog.Print(0, _T("reading cursorPos (%d,%d)\n"), surh.r.x, surh.r.y);
ReadCursorPos(&surh);
continue;
}
if (surh.encoding !=rfbEncodingNewFBSize && surh.encoding != rfbEncodingCacheZip && surh.encoding != rfbEncodingSolMonoZip && surh.encoding !=rfbEncodingUltraZip)
SoftCursorLockArea(surh.r.x, surh.r.y, surh.r.w, surh.r.h);
// Modif sf@2002 - DSM Plugin
// With DSM, all rects contents (excepted caches) are buffered into memory in one shot
// then they will be read in this buffer by the "regular" Read*Type*Rect() functions
if (m_fUsePlugin && m_pDSMPlugin->IsEnabled())
{
if (!m_fReadFromNetRectBuf)
{
switch (surh.encoding)
{
case rfbEncodingRaw:
case rfbEncodingRRE:
case rfbEncodingCoRRE:
case rfbEncodingHextile:
case rfbEncodingUltra:
case rfbEncodingZlib:
case rfbEncodingXOR_Zlib:
case rfbEncodingXORMultiColor_Zlib:
case rfbEncodingXORMonoColor_Zlib:
case rfbEncodingSolidColor:
case rfbEncodingTight:
case rfbEncodingZlibHex:
{
// Get the size of the rectangle data buffer
ReadExact((char*)&(m_nReadSize), sizeof(CARD32));
m_nReadSize = Swap32IfLE(m_nReadSize);
// Read the whole rect buffer and put the result in m_netbuf
CheckNetRectBufferSize((int)(m_nReadSize));
CheckBufferSize((int)(m_nReadSize)); // sf@2003
ReadExact((char*)(m_pNetRectBuf), (int)(m_nReadSize));
// Tell the following ReadExact() function calls to Read Data from memory
m_nNetRectBufOffset = 0;
m_fReadFromNetRectBuf = true;
}
break;
}
}
// ZRLE special case
if (!fis->GetReadFromMemoryBuffer())
{
if (surh.encoding == rfbEncodingZRLE)
{
// Get the size of the rectangle data buffer
ReadExact((char*)&(m_nZRLEReadSize), sizeof(CARD32));
m_nZRLEReadSize = Swap32IfLE(m_nZRLEReadSize);
// Read the whole rect buffer and put the result in m_netbuf
CheckZRLENetRectBufferSize((int)(m_nZRLEReadSize));
CheckBufferSize((int)(m_nZRLEReadSize)); // sf@2003
ReadExact((char*)(m_pZRLENetRectBuf), (int)(m_nZRLEReadSize));
// Tell the following Read() function calls to Read Data from memory
fis->SetReadFromMemoryBuffer(m_nZRLEReadSize, (char*)(m_pZRLENetRectBuf));
}
}
}
RECT cacherect;
if (m_opts.m_fEnableCache)
{
cacherect.left=surh.r.x;
cacherect.right=surh.r.x+surh.r.w;
cacherect.top=surh.r.y;
cacherect.bottom=surh.r.y+surh.r.h;
}
if (m_TrafficMonitor)
{
hdcX = GetDC(m_TrafficMonitor);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,m_bitmapBACK);
BitBlt(hdcX,4,2,22,20,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdcX);
}
//vnclog.Print(0, _T("encoding %d\n"), surh.encoding);
if (surh.encoding==rfbEncodingUltra || surh.encoding==rfbEncodingUltraZip)
{
UltraFast=true;
}
else
{
// sf@2003 - The only one that is missing in the test below is "raw"... maybe a "else" would be enought ?
/*
if (surh.encoding==rfbEncodingHextile || surh.encoding==rfbEncodingTight || surh.encoding==rfbEncodingZRLE
|| surh.encoding==rfbEncodingSolidColor || surh.encoding==rfbEncodingSolMonoZip
|| surh.encoding==rfbEncodingRRE || surh.encoding==rfbEncodingCoRRE|| surh.encoding==rfbEncodingZlib
|| surh.encoding==rfbEncodingZlibHex || surh.encoding==rfbEncodingXOR_Zlib|| surh.encoding==rfbEncodingXORMultiColor_Zlib
)*/
UltraFast=false;
}
// sf@2004
if (m_fUsePlugin && m_pDSMPlugin->IsEnabled() && (m_fReadFromNetRectBuf || fis->GetReadFromMemoryBuffer()))
{
fis->stopTiming();
kbitsPerSecond = fis->kbitsPerSecond();
fTimingAlreadyStopped = true;
}
// vnclog.Print(0, _T("known encoding %d - not supported!\n"), surh.encoding);
switch (surh.encoding)
{
case rfbEncodingHextile:
SaveArea(cacherect);
ReadHextileRect(&surh);
EncodingStatusWindow=rfbEncodingHextile;
break;
case rfbEncodingUltra:
ReadUltraRect(&surh);
EncodingStatusWindow=rfbEncodingUltra;
break;
case rfbEncodingUltraZip:
ReadUltraZip(&surh,&UpdateRegion);
break;
case rfbEncodingRaw:
SaveArea(cacherect);
ReadRawRect(&surh);
EncodingStatusWindow=rfbEncodingRaw;
break;
case rfbEncodingCopyRect:
ReadCopyRect(&surh);
break;
case rfbEncodingCache:
ReadCacheRect(&surh);
break;
case rfbEncodingCacheZip:
ReadCacheZip(&surh,&UpdateRegion);
break;
case rfbEncodingSolMonoZip:
ReadSolMonoZip(&surh,&UpdateRegion);
break;
case rfbEncodingRRE:
SaveArea(cacherect);
ReadRRERect(&surh);
EncodingStatusWindow=rfbEncodingRRE;
break;
case rfbEncodingCoRRE:
SaveArea(cacherect);
ReadCoRRERect(&surh);
EncodingStatusWindow=rfbEncodingCoRRE;
break;
case rfbEncodingZlib:
SaveArea(cacherect);
ReadZlibRect(&surh,0);
EncodingStatusWindow=rfbEncodingZlib;
break;
case rfbEncodingZlibHex:
SaveArea(cacherect);
ReadZlibHexRect(&surh);
EncodingStatusWindow=rfbEncodingZlibHex;
break;
case rfbEncodingXOR_Zlib:
SaveArea(cacherect);
ReadZlibRect(&surh,1);
break;
case rfbEncodingXORMultiColor_Zlib:
SaveArea(cacherect);
ReadZlibRect(&surh,2);
break;
case rfbEncodingXORMonoColor_Zlib:
SaveArea(cacherect);
ReadZlibRect(&surh,3);
break;
case rfbEncodingSolidColor:
SaveArea(cacherect);
ReadSolidRect(&surh);
break;
case rfbEncodingZRLE:
SaveArea(cacherect);
zrleDecode(surh.r.x, surh.r.y, surh.r.w, surh.r.h);
EncodingStatusWindow=rfbEncodingZRLE;
break;
case rfbEncodingTight:
SaveArea(cacherect);
ReadTightRect(&surh);
EncodingStatusWindow=rfbEncodingTight;
break;
default:
// vnclog.Print(0, _T("Unknown encoding %d - not supported!\n"), surh.encoding);
// Try to empty buffer...
// so next update should be back in sync
BYTE * buffer;
int i=0;
while (TRUE)
{
int aantal=fis->Check_if_buffer_has_data();
if (aantal>0) buffer = new BYTE [aantal];
if (aantal>0)
{
i=0;
ReadExact(((char *) buffer), aantal);
delete [] buffer;
Sleep(5);
}
else if (aantal==0)
{
if (i==5) break;
Sleep(200);
i++;
}
else break;
}
vnclog.Print(0, _T("Buffer cleared, sync should be back OK..Continue \n"));
Recover_from_sync=true;
break;
}
if (Recover_from_sync)
{
Recover_from_sync=false;
break;
}
if (surh.encoding !=rfbEncodingNewFBSize && surh.encoding != rfbEncodingCacheZip && surh.encoding != rfbEncodingSolMonoZip && surh.encoding != rfbEncodingUltraZip)
{
RECT rect;
rect.left = surh.r.x;
rect.top = surh.r.y;
rect.right = surh.r.x + surh.r.w ;
rect.bottom = surh.r.y + surh.r.h;
InvalidateScreenRect(&rect);
}
else if (surh.encoding !=rfbEncodingNewFBSize)
{
InvalidateRgn(m_hwnd, UpdateRegion, FALSE);
HRGN tempregion=CreateRectRgn(0,0,0,0);
CombineRgn(UpdateRegion,UpdateRegion,tempregion,RGN_AND);
DeleteObject(tempregion);
}
if (m_TrafficMonitor)
{
hdcX = GetDC(m_TrafficMonitor);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,m_bitmapNONE);
BitBlt(hdcX,4,2,22,20,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdcX);
}
SoftCursorUnlockScreen();
}
if (!fTimingAlreadyStopped)
{
fis->stopTiming();
kbitsPerSecond = fis->kbitsPerSecond();
}
// sf@2002
// We only change the preferred encoding if FileTransfer is not running and if
// the last encoding change occured more than 30s ago
if (m_opts.autoDetect
&&
!m_pFileTransfer->m_fFileTransferRunning
&&
(timeGetTime() - m_lLastChangeTime) > 30000)
{
int nOldServerScale = m_nServerScale;
// If connection speed > 1Mbits/s - All to the max
/*if (kbitsPerSecond > 2000 && (m_nConfig != 7))
{
m_nConfig = 1;
m_opts.m_PreferredEncoding = rfbEncodingUltra;
m_opts.m_Use8Bit = false; // Max colors
m_opts.m_fEnableCache = false;
m_pendingFormatChange = true;
m_lLastChangeTime = timeGetTime();
}*/
if (kbitsPerSecond > 1000 && (m_nConfig != 1))
{
m_nConfig = 1;
m_opts.m_PreferredEncoding = rfbEncodingHextile;
m_opts.m_Use8Bit = rfbPFFullColors; // Max colors
m_opts.m_fEnableCache = false;
m_pendingFormatChange = true;
m_lLastChangeTime = timeGetTime();
}
// Medium connection speed
else if (kbitsPerSecond < 256 && kbitsPerSecond > 128 && (m_nConfig != 2))
{
m_nConfig = 2;
m_opts.m_PreferredEncoding = rfbEncodingZRLE; //rfbEncodingZlibHex;
m_opts.m_Use8Bit = rfbPF256Colors;
// m_opts.m_compressLevel = 9;
m_opts.m_fEnableCache = false;
m_pendingFormatChange = true;
m_lLastChangeTime = timeGetTime();
}
// Modem (including cable modem) connection speed
else if (kbitsPerSecond < 128 && kbitsPerSecond > 19 && (m_nConfig != 3))
{
m_nConfig = 3;
m_opts.m_PreferredEncoding = rfbEncodingTight; // rfbEncodingZRLE;
m_opts.m_Use8Bit = rfbPF64Colors;
// m_opts.m_compressLevel = 9;
m_opts.m_fEnableCache = false;
m_pendingFormatChange = true;
m_lLastChangeTime = timeGetTime();
}
// Slow Modem connection speed
// Not sure it's a good thing in Auto mode...because in some cases
// (CTRL-ALT-DEL, initial screen loading, connection short hangups...)
// the speed can be momentary VERY slow. The fast fuzzy/normal modes switching
// can be quite disturbing and useless in these situations.
else if (kbitsPerSecond < 19 && kbitsPerSecond > 5 && (m_nConfig != 4))
{
m_nConfig = 4;
m_opts.m_PreferredEncoding = rfbEncodingTight; //rfbEncodingZRLE;
m_opts.m_Use8Bit = rfbPF8Colors;
// m_opts.m_compressLevel = 9;
// m_opts.m_scaling = true;
// m_opts.m_scale_num = 2;
// m_opts.m_scale_den = 1;
// m_nServerScale = 2;
// m_opts.m_nServerScale = 2;
m_opts.m_fEnableCache = false;
m_pendingFormatChange = true;
}
/*
if (m_nServerScale != nOldServerScale)
{
SendServerScale(m_nServerScale);
}
*/
}
// Inform the other thread that an update is needed.
PostMessage(m_hwnd, WM_REGIONUPDATED, NULL, NULL);
DeleteObject(UpdateRegion);
}
void ClientConnection::SetDormant(bool newstate)
{
vnclog.Print(5, _T("%s dormant mode\n"), newstate ? _T("Entering") : _T("Leaving"));
m_dormant = newstate;
if (!m_dormant)
SendIncrementalFramebufferUpdateRequest();
}
// The server has copied some text to the clipboard - put it
// in the local clipboard too.
void ClientConnection::ReadServerCutText()
{
rfbServerCutTextMsg sctm;
vnclog.Print(6, _T("Read remote clipboard change\n"));
ReadExact(((char *) &sctm)+m_nTO, sz_rfbServerCutTextMsg-m_nTO);
int len = Swap32IfLE(sctm.length);
CheckBufferSize(len);
if (len == 0) {
m_netbuf[0] = '\0';
} else {
ReadString(m_netbuf, len);
}
UpdateLocalClipboard(m_netbuf, len);
}
void ClientConnection::ReadBell()
{
rfbBellMsg bm;
ReadExact(((char *) &bm)+m_nTO, sz_rfbBellMsg-m_nTO);
#ifdef UNDER_CE
MessageBeep( MB_OK );
#else
if (! ::PlaySound("VNCViewerBell", NULL,
SND_APPLICATION | SND_ALIAS | SND_NODEFAULT | SND_ASYNC) ) {
::Beep(440, 125);
}
#endif
if (m_opts.m_DeiconifyOnBell) {
if (IsIconic(m_hwnd)) {
SetDormant(false);
ShowWindow(m_hwnd, SW_SHOWNORMAL);
}
}
vnclog.Print(6, _T("Bell!\n"));
}
// General utilities -------------------------------------------------
// Reads the number of bytes specified into the buffer given
void ClientConnection::ReadExact(char *inbuf, int wanted)
{
//omni_mutex_lock l(m_readMutex);
// Status window and connection activity updates
// We comment this because it just takes too much time to the viewer thread
/*
HDC hdcX,hdcBits;
if (m_TrafficMonitor)
{
hdcX = GetDC(m_TrafficMonitor);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,m_bitmapBACK);
BitBlt(hdcX,1,1,22,20,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdcX);
}
*/
// m_BytesRead += wanted;
/*
m_BytesRead = fis->GetBytesRead();
SetDlgItemInt(m_hwndStatus, IDC_RECEIVED, m_BytesRead, false);
SetDlgItemInt(m_hwndStatus, IDC_SPEED, kbitsPerSecond, false);
*/
try
{
// sf@2002 - DSM Plugin
if (m_fUsePlugin)
{
if (m_pDSMPlugin->IsEnabled())
{
omni_mutex_lock l(m_pDSMPlugin->m_RestMutex);
// If we must read already restored data from memory
if (m_fReadFromNetRectBuf)
{
memcpy(inbuf, m_pNetRectBuf + m_nNetRectBufOffset, wanted);
m_nNetRectBufOffset += wanted;
if (m_nNetRectBufOffset == m_nReadSize)
{
// Next ReadExact calls should read the socket
m_fReadFromNetRectBuf = false;
m_nNetRectBufOffset = 0;
}
}
// Read restored data from ZRLE mem netbuffer
else if (fis->GetReadFromMemoryBuffer())
{
fis->readBytes(inbuf, wanted);
}
else // read tansformed data from the socket (normal case)
{
// Get the DSMPlugin destination buffer where to put transformed incoming data
// The number of bytes to read calculated from bufflen is given back in nTransDataLen
int nTransDataLen = 0;
BYTE* pTransBuffer = m_pDSMPlugin->RestoreBufferStep1(NULL, wanted, &nTransDataLen);
if (pTransBuffer == NULL)
{
// m_pDSMPlugin->RestoreBufferUnlock();
throw WarningException(sz_L65);
}
// Read bytes directly into Plugin Dest rest. buffer
fis->readBytes(pTransBuffer, nTransDataLen);
// Ask plugin to restore data from its local rest. buffer into inbuf
int nRestDataLen = 0;
m_pDSMPlugin->RestoreBufferStep2((BYTE*)inbuf, nTransDataLen, &nRestDataLen);
// Check if we actually get the real original data length
if (nRestDataLen != wanted)
{
throw WarningException(sz_L66);
}
}
}
else
{
fis->readBytes(inbuf, wanted);
}
}
else
{
fis->readBytes(inbuf, wanted);
}
}
catch (rdr::Exception& e)
{
vnclog.Print(0, "rdr::Exception (2): %s\n",e.str());
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L67);
throw QuietException(e.str());
}
// Too slow !
/*
if (m_TrafficMonitor)
{
hdcX = GetDC(m_TrafficMonitor);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,m_bitmapNONE);
BitBlt(hdcX,1,1,22,20,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdcX);
}
*/
}
void ClientConnection::ReadExactProxy(char *inbuf, int wanted)
{
//omni_mutex_lock l(m_readMutex);
// Status window and connection activity updates
// We comment this because it just takes too much time to the viewer thread
try
{
{
fis->readBytes(inbuf, wanted);
}
}
catch (rdr::Exception& e)
{
vnclog.Print(0, "rdr::Exception (2): %s\n",e.str());
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_STATUS,sz_L67);
throw QuietException(e.str());
}
}
// Read the number of bytes and return them zero terminated in the buffer
/*inline*/ void ClientConnection::ReadString(char *buf, int length)
{
if (length > 0)
ReadExact(buf, length);
buf[length] = '\0';
vnclog.Print(10, _T("Read a %d-byte string\n"), length);
}
//
// sf@2002 - DSM Plugin
//
void ClientConnection::WriteExact(char *buf, int bytes, CARD8 msgType)
{
if (!m_fUsePlugin)
{
WriteExact(buf, bytes);
}
else if (m_pDSMPlugin->IsEnabled())
{
// Send the transformed message type first
WriteExact((char*)&msgType, sizeof(msgType));
// Then send the transformed rfb message content
WriteExact(buf, bytes);
}
}
// Sends the number of bytes specified from the buffer
void ClientConnection::WriteExact(char *buf, int bytes)
{
if (bytes == 0) return;
// Too slow
/*
HDC hdcX,hdcBits;
if (m_TrafficMonitor)
{
hdcX = GetDC(m_TrafficMonitor);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,m_bitmapFRONT);
BitBlt(hdcX,1,1,22,20,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdcX);
}
*/
omni_mutex_lock l(m_writeMutex);
//vnclog.Print(10, _T(" writing %d bytes\n"), bytes);
m_BytesSend += bytes;
/*
SetDlgItemInt(m_hwndStatus,IDC_SEND,m_BytesSend,false);
*/
int i = 0;
int j;
// sf@2002 - DSM Plugin
char *pBuffer = buf;
if (m_fUsePlugin)
{
if (m_pDSMPlugin->IsEnabled())
{
int nTransDataLen = 0;
pBuffer = (char*)(m_pDSMPlugin->TransformBuffer((BYTE*)buf, bytes, &nTransDataLen));
if (pBuffer == NULL || (bytes > 0 && nTransDataLen == 0))
throw WarningException(sz_L68);
bytes = nTransDataLen;
}
}
while (i < bytes)
{
j = send(m_sock, pBuffer+i, bytes-i, 0);
if (j == SOCKET_ERROR || j==0)
{
LPVOID lpMsgBuf;
int err = ::GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL ); // Process any inserts in lpMsgBuf.
vnclog.Print(1, _T("Socket error %d: %s\n"), err, lpMsgBuf);
LocalFree( lpMsgBuf );
m_running = false;
throw WarningException(sz_L69);
}
i += j;
}
// Too slow
/*
if (m_TrafficMonitor)
{
hdcX = GetDC(m_TrafficMonitor);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,m_bitmapNONE);
BitBlt(hdcX,1,1,22,20,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(m_TrafficMonitor,hdcX);
}
*/
}
// Sends the number of bytes specified from the buffer
void ClientConnection::WriteExactProxy(char *buf, int bytes)
{
if (bytes == 0) return;
omni_mutex_lock l(m_writeMutex);
//vnclog.Print(10, _T(" writing %d bytes\n"), bytes);
m_BytesSend += bytes;
/*
SetDlgItemInt(m_hwndStatus,IDC_SEND,m_BytesSend,false);
*/
int i = 0;
int j;
// sf@2002 - DSM Plugin
char *pBuffer = buf;
while (i < bytes)
{
j = send(m_sock, pBuffer+i, bytes-i, 0);
if (j == SOCKET_ERROR || j==0)
{
LPVOID lpMsgBuf;
int err = ::GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL ); // Process any inserts in lpMsgBuf.
vnclog.Print(1, _T("Socket error %d: %s\n"), err, lpMsgBuf);
LocalFree( lpMsgBuf );
m_running = false;
throw WarningException(sz_L69);
}
i += j;
}
}
// Makes sure netbuf is at least as big as the specified size.
// Note that netbuf itself may change as a result of this call.
// Throws an exception on failure.
void ClientConnection::CheckBufferSize(int bufsize)
{
if (m_netbufsize > bufsize) return;
omni_mutex_lock l(m_bufferMutex);
char *newbuf = new char[bufsize+256];
if (newbuf == NULL) {
throw ErrorException(sz_L70);
}
// Only if we're successful...
if (m_netbuf != NULL)
delete [] m_netbuf;
m_netbuf = newbuf;
m_netbufsize=bufsize + 256;
vnclog.Print(4, _T("bufsize expanded to %d\n"), m_netbufsize);
}
// Makes sure zipbuf is at least as big as the specified size.
// Note that zlibbuf itself may change as a result of this call.
// Throws an exception on failure.
// sf@2002
void ClientConnection::CheckZipBufferSize(int bufsize)
{
unsigned char *newbuf;
if (m_zipbufsize > bufsize) return;
omni_mutex_lock l(m_ZipBufferMutex);
newbuf = (unsigned char *)new char[bufsize + 256];
if (newbuf == NULL) {
throw ErrorException(sz_L71);
}
// Only if we're successful...
if (m_zipbuf != NULL)
delete [] m_zipbuf;
m_zipbuf = newbuf;
m_zipbufsize = bufsize + 256;
vnclog.Print(4, _T("zipbufsize expanded to %d\n"), m_zipbufsize);
}
void ClientConnection::CheckFileZipBufferSize(int bufsize)
{
unsigned char *newbuf;
if (m_filezipbufsize > bufsize) return;
omni_mutex_lock l(m_FileZipBufferMutex);
newbuf = (unsigned char *)new char[bufsize + 256];
if (newbuf == NULL) {
throw ErrorException(sz_L71);
}
// Only if we're successful...
if (m_filezipbuf != NULL)
delete [] m_filezipbuf;
m_filezipbuf = newbuf;
m_filezipbufsize = bufsize + 256;
vnclog.Print(4, _T("zipbufsize expanded to %d\n"), m_filezipbufsize);
}
void ClientConnection::CheckFileChunkBufferSize(int bufsize)
{
unsigned char *newbuf;
if (m_filechunkbufsize > bufsize) return;
omni_mutex_lock l(m_FileChunkBufferMutex);
newbuf = (unsigned char *)new char[bufsize + 256];
if (newbuf == NULL) {
throw ErrorException(sz_L71);
}
if (m_filechunkbuf != NULL)
delete [] m_filechunkbuf;
m_filechunkbuf = newbuf;
m_filechunkbufsize = bufsize + 256;
vnclog.Print(4, _T("m_filechunkbufsize expanded to %d\n"), m_filechunkbufsize);
}
// Processing NewFBSize pseudo-rectangle. Create new framebuffer of
// the size specified in pfburh->r.w and pfburh->r.h, and change the
// window size correspondingly.
//
void ClientConnection::ReadNewFBSize(rfbFramebufferUpdateRectHeader *pfburh)
{
m_si.framebufferWidth = pfburh->r.w;
m_si.framebufferHeight = pfburh->r.h;
ClearCache();
CreateLocalFramebuffer();
SendFullFramebufferUpdateRequest();
Createdib();\
m_pendingScaleChange = true;
m_pendingFormatChange = true;
SendAppropriateFramebufferUpdateRequest();
SizeWindow();
InvalidateRect(m_hwnd, NULL, TRUE);
RealiseFullScreenMode();
}
//
// sf@2002 - DSMPlugin
//
//
// Ensures that the temporary "alignement" buffer in large enough
//
inline void ClientConnection::CheckNetRectBufferSize(int nBufSize)
{
if (m_nNetRectBufSize > nBufSize) return;
omni_mutex_lock l(m_NetRectBufferMutex);
BYTE *newbuf = new BYTE[nBufSize + 256];
if (newbuf == NULL)
{
// Error
}
if (m_pNetRectBuf != NULL)
delete [] m_pNetRectBuf;
m_pNetRectBuf = newbuf;
m_nNetRectBufSize = nBufSize + 256;
}
//
// Ensures that the temporary "alignement" buffer in large enough
//
inline void ClientConnection::CheckZRLENetRectBufferSize(int nBufSize)
{
if (m_nZRLENetRectBufSize > nBufSize) return;
omni_mutex_lock l(m_ZRLENetRectBufferMutex);
BYTE *newbuf = new BYTE[nBufSize + 256];
if (newbuf == NULL)
{
// Error
}
if (m_pZRLENetRectBuf != NULL)
delete [] m_pZRLENetRectBuf;
m_pZRLENetRectBuf = newbuf;
m_nZRLENetRectBufSize = nBufSize + 256;
}
//
// Format file size so it is user friendly to read
//
void ClientConnection::GetFriendlySizeString(__int64 Size, char* szText)
{
szText[0] = '\0';
if( Size > (1024*1024*1024) )
{
__int64 lRest = (Size % (1024*1024*1024));
Size /= (1024*1024*1024);
wsprintf(szText,"%u.%4.4lu Gb", (unsigned long)Size, (unsigned long)((__int64)(lRest) * 10000 / 1024 / 1024 / 1024));
}
else if( Size > (1024*1024) )
{
unsigned long lRest = (Size % (1024*1024));
Size /= (1024*1024);
wsprintf(szText,"%u.%3.3lu Mb", (unsigned long)Size, (unsigned long)((__int64)(lRest) * 1000 / 1024 / 1024));
}
else if ( Size > 1024 )
{
unsigned long lRest = Size % (1024);
Size /= 1024;
wsprintf(szText,"%u.%2.2lu Kb", (unsigned long)Size, lRest * 100 / 1024);
}
else
{
wsprintf(szText,"%u bytes", (unsigned long)Size);
}
}
//
// sf@2002
//
void ClientConnection::UpdateStatusFields()
{
char szText[256];
// Bytes Received
m_BytesRead = fis->GetBytesRead();
GetFriendlySizeString(m_BytesRead, szText);
// SetDlgItemInt(m_hwndStatus, IDC_RECEIVED, m_BytesRead, false);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_RECEIVED, szText);
// Bytes Sent
GetFriendlySizeString(m_BytesSend, szText);
if (m_hwndStatus)SetDlgItemText(m_hwndStatus,IDC_SEND, szText);
// Speed
if (m_hwndStatus)SetDlgItemInt(m_hwndStatus, IDC_SPEED, kbitsPerSecond, false);
// Encoder
if (m_fStatusOpen) // It's called by the status window timer... fixme
{
if (EncodingStatusWindow!=OldEncodingStatusWindow)
{
OldEncodingStatusWindow = EncodingStatusWindow;
switch (EncodingStatusWindow)
{
case rfbEncodingRaw:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "Raw, Cache" : "Raw");
break;
case rfbEncodingRRE:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "RRE, Cache" : "RRE");
break;
case rfbEncodingCoRRE:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "CoRRE, Cache" : "CoRRE");
break;
case rfbEncodingHextile:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "Hextile, Cache" : "Hextile");
break;
case rfbEncodingUltra:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "Ultra, Cache" : "Ultra");
break;
case rfbEncodingZlib:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "XORZlib, Cache" : "XORZlib");
break;
case rfbEncodingZRLE:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "ZRLE, Cache" :"ZRLE");
break;
case rfbEncodingTight:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "Tight, Cache" : "Tight");
break;
case rfbEncodingZlibHex:
if (m_hwndStatus)SetDlgItemText(m_hwndStatus, IDC_ENCODER, m_opts.m_fEnableCache ? "ZlibHex, Cache" : "ZlibHex");
break;
}
}
}
else
OldEncodingStatusWindow = -1;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
void ClientConnection::GTGBS_ScrollToolbar(int dx, int dy)
{
/* dx = max(dx, -m_hScrollPos);
dx = min(dx, m_hScrollMax-(m_cliwidth)-m_hScrollPos);
dy = max(dy, -m_vScrollPos);
dy = min(dy, m_vScrollMax-(m_cliheight)-m_vScrollPos);
if (dx || dy) {
RECT clirect;
GetClientRect(m_hwndTBwin, &clirect);
ScrollWindowEx(m_hwndTBwin, dx, dy, NULL, &clirect, NULL, NULL, SW_ERASE );
DoBlit();
}
*/
}
void ClientConnection::GTGBS_CreateDisplay()
{
// Das eigendliche HauptFenster erstellen,
// welches das VNC-Fenster und die Toolbar enth<74>lt
WNDCLASS wndclass;
wndclass.style = 0;
wndclass.lpfnWndProc = ClientConnection::WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_pApp->m_instance;
wndclass.hIcon = LoadIcon(m_pApp->m_instance, MAKEINTRESOURCE(IDI_MAINICON));
switch (m_opts.m_localCursor) {
case NOCURSOR:
wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_NOCURSOR));
break;
case NORMALCURSOR:
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
break;
case DOTCURSOR:
default:
wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_DOTCURSOR));
}
wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = (const TCHAR *) NULL;
wndclass.lpszClassName = _T("VNCMDI_Window");
RegisterClass(&wndclass);
#ifdef _WIN32_WCE
DWORD winstyle = WS_VSCROLL | WS_HSCROLL | WS_CAPTION | WS_SYSMENU;
#else
DWORD winstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX |WS_MAXIMIZEBOX | WS_THICKFRAME | WS_VSCROLL | WS_HSCROLL;
#endif
int x = CW_USEDEFAULT;
int y = CW_USEDEFAULT;
int w = 320;
int h = 200;
HWND parent = NULL;
#ifdef _ULTRAVNCAX_
winstyle = WS_CHILD | WS_VSCROLL | WS_HSCROLL;
x = 0;
y = 0;
RECT rectClient;
::GetClientRect( m_hwndAx, & rectClient );
w = rectClient.right;
h = rectClient.bottom;
parent = m_hwndAx;
#endif
m_hwndMain = CreateWindow(_T("VNCMDI_Window"),
_T("VNCviewer"),
winstyle,
x,
y,
//CW_USEDEFAULT,
//CW_USEDEFAULT,
w,h,
parent, // Parent handle
NULL, // Menu handle
m_pApp->m_instance,
NULL);
//ShowWindow(m_hwndMain,SW_SHOW);
SetWindowLong(m_hwndMain, GWL_USERDATA, (LONG) this);
#ifdef _ULTRAVNCAX_
*m_pHwndAppFrame = m_hwndMain;
#endif
}
//
//
//
LRESULT CALLBACK ClientConnection::GTGBS_ShowStatusWindow(LPVOID lpParameter)
{
ClientConnection *_this = (ClientConnection*)lpParameter;
_this->m_fStatusOpen = true;
DialogBoxParam(_this->m_pApp->m_instance,MAKEINTRESOURCE(IDD_STATUS),NULL,(DLGPROC)ClientConnection::GTGBS_StatusProc,(LPARAM)_this);
// _this->m_fStatusOpen = false;
return 0;
}
//
//
//
LRESULT CALLBACK ClientConnection::GTGBS_StatusProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
ClientConnection* _this = (ClientConnection *) GetWindowLong(hwnd, GWL_USERDATA);
switch (iMsg)
{
case WM_INITDIALOG:
{
// sf@2002 - Make the window always on top
RECT Rect;
GetWindowRect(hwnd, &Rect);
SetWindowPos(hwnd,
HWND_TOPMOST,
Rect.left,
Rect.top,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
SWP_SHOWWINDOW);
char wt[MAX_PATH];
ClientConnection *_this = (ClientConnection *)lParam;
SetWindowLong(hwnd, GWL_USERDATA, (LONG) _this);
SetDlgItemInt(hwnd,IDC_RECEIVED,_this->m_BytesRead,false);
SetDlgItemInt(hwnd,IDC_SEND,_this->m_BytesSend,false);
if (_this->m_host != NULL) {
SetDlgItemText(hwnd,IDC_VNCSERVER,_this->m_host);
sprintf(wt,"%s %s",sz_L72,_this->m_host);
SetWindowText(hwnd,wt);
} else {
SetDlgItemText(hwnd,IDC_VNCSERVER,_T(""));
SetWindowText(hwnd,sz_L73);
}
if(_this->m_port != NULL)
SetDlgItemInt(hwnd,IDC_PORT,_this->m_port,FALSE);
else
SetDlgItemText(hwnd,IDC_PORT,_T(""));
if(_this->m_sock != NULL )
{
if (_this->m_pDSMPlugin->IsEnabled())
{
char szMess[255];
memset(szMess, 0, 255);
sprintf(szMess, "%s (%s-v%s)",
sz_L49,
_this->m_pDSMPlugin->GetPluginName(),
_this->m_pDSMPlugin->GetPluginVersion()
);
SetDlgItemText(hwnd,IDC_STATUS, szMess);
}
else
SetDlgItemText(hwnd,IDC_STATUS,sz_L49);
}
else
{
SetDlgItemText(hwnd,IDC_STATUS,sz_L74);
}
//CentreWindow(hwnd);
ShowWindow(hwnd,SW_SHOW);
_this->m_hwndStatus = hwnd;
if (_this->m_running) {
//Normaler status
ShowWindow(GetDlgItem(hwnd,IDQUIT),SW_HIDE);
ShowWindow(GetDlgItem(hwnd,IDCLOSE),SW_SHOW);
// sf@2002
if (!_this->m_nStatusTimer)
_this->m_nStatusTimer = SetTimer( hwnd, 3333, 1000, NULL);
} else {
//Verbindungsaufbau status
ShowWindow(GetDlgItem(hwnd,IDQUIT),SW_SHOW);
ShowWindow(GetDlgItem(hwnd,IDCLOSE),SW_HIDE);
SetDlgItemText(hwnd,IDC_STATUS,sz_L43);
HMENU hMenu = GetSystemMenu(hwnd,0);
EnableMenuItem(hMenu,SC_CLOSE,MF_BYCOMMAND | MF_GRAYED);
}
return TRUE;
}
case WM_CLOSE:
{
EndDialog(hwnd, TRUE);
return TRUE;
}
case WM_COMMAND:
{
if (LOWORD(wParam) == IDCLOSE) {
EndDialog(hwnd, TRUE);
}
if (LOWORD(wParam) == IDQUIT) {
_this->Pressed_Cancel=true;
EndDialog(hwnd, TRUE);
}
/*if (LOWORD(wParam) == IDQUIT) {
PostQuitMessage(0);
ClientConnection *_this = (ClientConnection *) GetWindowLong(hwnd, GWL_USERDATA);
_this->KillThread();
//EndDialog(hwnd, TRUE);
}*/
return TRUE;
}
// sf@2002 - Every timer tic, we update the status values (speed, Sent, received, Encoder)
case WM_TIMER:
{
_this->UpdateStatusFields();
return TRUE;
}
case WM_DESTROY:
{
// sf@2002 - Destroy the status timer... TODO: improve this
if (_this->m_nStatusTimer != 0)
{
KillTimer(hwnd, _this->m_nStatusTimer);
_this->m_nStatusTimer = 0;
}
_this->OldEncodingStatusWindow = -1;
_this->m_fStatusOpen = false;
return TRUE;
}
}
return FALSE;
}
//
//
//
LRESULT CALLBACK ClientConnection::GTGBS_SendCustomKey_proc(HWND Dlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
{
case WM_INITDIALOG:
{
SetFocus(GetDlgItem(Dlg,IDC_CUSTOM_KEY));
ShowWindow(Dlg, SW_SHOW);
// Window always on top
RECT Rect;
GetWindowRect(Dlg, &Rect);
SetWindowPos(Dlg,
HWND_TOPMOST,
Rect.left,
Rect.top,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
SWP_SHOWWINDOW);
return TRUE;
}
case WM_CLOSE:
{
EndDialog(Dlg, 0);
return TRUE;
}
case WM_COMMAND:
{
BOOL Okay;
UINT Key;
UINT STRG=0;
UINT ALT=0;
UINT ALTGR=0;
if (LOWORD(wParam) == IDCANCEL) {
EndDialog(Dlg, 0);
}
if (LOWORD(wParam) == IDOK) {
if (SendMessage(GetDlgItem(Dlg,IDC_STRG), BM_GETCHECK, 0, 0) == BST_CHECKED)
STRG=1;
if (SendMessage(GetDlgItem(Dlg,IDC_ALT), BM_GETCHECK, 0, 0) == BST_CHECKED)
ALT=1;
if (SendMessage(GetDlgItem(Dlg,IDC_ALTGR), BM_GETCHECK, 0, 0) == BST_CHECKED)
ALTGR=1;
Key = GetDlgItemInt(Dlg,IDC_CUSTOM_KEY,&Okay,FALSE);
if (ALT!=0)
Key |=KEYMAP_LALT;
if (ALTGR != 0)
Key |= KEYMAP_RALT;
if (STRG != 0)
Key |= KEYMAP_RCONTROL;
if (Okay)
EndDialog(Dlg, Key);
else
EndDialog(Dlg, 0);
}
}
}
return 0;
}
//
// Process windows messages
//
LRESULT CALLBACK ClientConnection::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
// This is a static method, so we don't know which instantiation we're
// dealing with. But we've stored a 'pseudo-this' in the window data.
ClientConnection *_this = (ClientConnection *) GetWindowLong(hwnd, GWL_USERDATA);
if (_this == NULL)
return DefWindowProc(hwnd, iMsg, wParam, lParam);
// HWND parent;
{
// Main Window
// if ( hwnd == _this->m_hwndMain)
{
switch (iMsg)
{
// case WM_TIMER:
// KillTimer(hwnd,_this->m_FTtimer);
// _this->m_FTtimer=0;
// _this->m_pFileTransfer->SendFileChunk();
// break;
case WM_SYSCOMMAND:
{
switch (LOWORD(wParam))
{
case ID_SW:
if (!_this->m_SWselect)
{
_this->m_SWselect=true;
}
break;
case ID_DESKTOP:
if (!_this->m_SWselect)
{
_this->m_SWselect=true;
_this->SendSW(9999,9999);
}
break;
// Toggle toolbar & toolbar menu option
case ID_DBUTTON:
_this->m_opts.m_ShowToolbar = !_this->m_opts.m_ShowToolbar;
CheckMenuItem(GetSystemMenu(_this->m_hwndMain, FALSE),
ID_DBUTTON,
MF_BYCOMMAND | (_this->m_opts.m_ShowToolbar ? MF_CHECKED :MF_UNCHECKED));
_this->SizeWindow();
_this->SetFullScreenMode(_this->InFullScreenMode());
break;
/*
case ID_BUTTON:
_this->m_opts.m_ShowToolbar=true;
_this->SizeWindow();
_this->SetFullScreenMode(_this->InFullScreenMode());
break;
*/
case ID_AUTOSCALING:
_this->m_opts.m_fAutoScaling = !_this->m_opts.m_fAutoScaling;
CheckMenuItem(GetSystemMenu(_this->m_hwndMain, FALSE),
ID_AUTOSCALING,
MF_BYCOMMAND | (_this->m_opts.m_fAutoScaling ? MF_CHECKED :MF_UNCHECKED));
_this->SizeWindow();
InvalidateRect(hwnd, NULL, TRUE);
_this->RealiseFullScreenMode();
break;
case ID_DINPUT:
_this->m_remote_mouse_disable = true;
if (_this->m_opts.m_ShowToolbar)
{
RECT rect;
GetWindowRect(hwnd, &rect);
_this->m_winwidth = rect.right - rect.left;
_this->m_winheight = rect.bottom - rect.top ;
if ((_this->m_winwidth) > 140+85+14*24)
{
DestroyWindow(_this->m_hwndTB);
_this->m_BigToolbar=true;
_this->CreateButtons(false,_this->m_fServerKnowsFileTransfer);
}
else
{
_this->m_BigToolbar=false;
DestroyWindow(_this->m_hwndTB);
_this->CreateButtons(true,_this->m_fServerKnowsFileTransfer);
}
SendMessage(hwnd,WM_SIZE,(WPARAM)ID_DINPUT,(LPARAM)0);
}
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendServerInput(true);
break;
case ID_INPUT:
_this->m_remote_mouse_disable = false;
if (_this->m_opts.m_ShowToolbar)
{
RECT rect;
GetWindowRect(hwnd, &rect);
_this->m_winwidth = rect.right - rect.left;
_this->m_winheight = rect.bottom - rect.top ;
if ((_this->m_winwidth) > 140+85+14*24)
{
DestroyWindow(_this->m_hwndTB);
_this->m_BigToolbar=true;
_this->CreateButtons(false,_this->m_fServerKnowsFileTransfer);
}
else
{
_this->m_BigToolbar=false;
DestroyWindow(_this->m_hwndTB);
_this->CreateButtons(true,_this->m_fServerKnowsFileTransfer);
}
SendMessage(hwnd,WM_SIZE,(WPARAM)ID_DINPUT,(LPARAM)0);
}
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendServerInput(false);
break;
case SC_MINIMIZE:
_this->SetDormant(true);
if (_this->m_hwndStatus)ShowWindow(_this->m_hwndStatus,SW_MINIMIZE);
break;
case SC_MAXIMIZE: //Added by: Lars Werner (http://lars.werner.no)
_this->SetFullScreenMode(!_this->InFullScreenMode());
break;
case SC_RESTORE:
_this->SetDormant(false);
if (_this->m_hwndStatus)ShowWindow(_this->m_hwndStatus,SW_NORMAL);
break;
case ID_NEWCONN:
_this->m_pApp->NewConnection();
return 0;
case ID_CONN_SAVE_AS:
_this->SaveConnection();
return 0;
case IDC_OPTIONBUTTON:
{
if (_this->m_fOptionsOpen) return 0;
_this->m_fOptionsOpen = true;
// Modif sf@2002 - Server Scaling
int nOldServerScale = _this->m_nServerScale;
int prev_scale_num = _this->m_opts.m_scale_num;
int prev_scale_den = _this->m_opts.m_scale_den;
bool fOldToolbarState = _this->m_opts.m_ShowToolbar;
int nOldAutoMode = _this->m_opts.autoDetect;
if (_this->m_opts.DoDialog(true))
{
/*
// Modif sf@2002 - Cache
if (_this->m_opts.m_fEnableCache && _this->m_hCacheBitmap == NULL)
{
_this->m_hCacheBitmapDC = CreateCompatibleDC(_this->m_hBitmapDC);
_this->m_hCacheBitmap = CreateCompatibleBitmap(_this->m_hBitmapDC, _this->m_si.framebufferWidth, _this->m_si.framebufferHeight);
_this->m_pendingCacheInit = true;
}
*/
// Modif sf@2002 - Server Scaling
_this->m_nServerScale = _this->m_opts.m_nServerScale;
if (_this->m_nServerScale != nOldServerScale)
{
_this->SendServerScale(_this->m_nServerScale);
}
else
{
if (prev_scale_num != _this->m_opts.m_scale_num ||
prev_scale_den != _this->m_opts.m_scale_den)
{
// Resize the window if scaling factors were changed
_this->SizeWindow(/*false*/);
InvalidateRect(hwnd, NULL, TRUE);
// Make the window corresponds to the requested state
_this->RealiseFullScreenMode();
}
if (fOldToolbarState != _this->m_opts.m_ShowToolbar)
_this->SizeWindow();
_this->m_pendingFormatChange = true;
}
}
if (nOldAutoMode != _this->m_opts.autoDetect)
_this->m_nConfig = 0;
_this->OldEncodingStatusWindow = -2; // force update in status window
_this->m_fOptionsOpen = false;
return 0;
}
case IDD_APP_ABOUT:
#ifndef _ULTRAVNCAX_
ShowAboutBox();
#else
ShowAboutBox( GetTopMostWnd( _this->m_hwndMain ? _this->m_hwndMain : _this->m_hwndAx ) );
#endif
return 0;
case ID_CONN_ABOUT:
_this->ShowConnInfo();
return 0;
case ID_FULLSCREEN:
// Toggle full screen mode
_this->SetFullScreenMode(!_this->InFullScreenMode());
return 0;
case ID_VIEWONLYTOGGLE:
// Toggle view only mode
_this->m_opts.m_ViewOnly = !_this->m_opts.m_ViewOnly;
// Todo update menu state
return 0;
case ID_REQUEST_REFRESH:
// Request a full-screen update
_this->SendFullFramebufferUpdateRequest();
return 0;
case ID_VK_LWINDOWN:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Super_L, true);
return 0;
case ID_VK_LWINUP:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Super_L, false);
return 0;
case ID_VK_RWINDOWN:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Super_R, true);
return 0;
case ID_VK_RWINUP:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Super_R, false);
return 0;
case ID_VK_APPSDOWN:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Menu, true);
return 0;
case ID_VK_APPSUP:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Menu, false);
return 0;
// Send START Button
case ID_CONN_CTLESC:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Control_L,true);
_this->SendKeyEvent(XK_Escape,true);
_this->SendKeyEvent(XK_Control_L,false);
_this->SendKeyEvent(XK_Escape,false);
return 0;
// Send Ctrl-Alt-Del
case ID_CONN_CTLALTDEL:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Control_L, true);
_this->SendKeyEvent(XK_Alt_L, true);
_this->SendKeyEvent(XK_Delete, true);
_this->SendKeyEvent(XK_Delete, false);
_this->SendKeyEvent(XK_Alt_L, false);
_this->SendKeyEvent(XK_Control_L, false);
return 0;
case ID_CONN_CTLDOWN:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Control_L, true);
return 0;
case ID_CONN_CTLUP:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Control_L, false);
return 0;
case ID_CONN_ALTDOWN:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Alt_L, true);
return 0;
case ID_CONN_ALTUP:
if (_this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Alt_L, false);
return 0;
case ID_CLOSEDAEMON:
if (MessageBox(NULL, sz_L75,
sz_L76,
MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
{
vnclog.Print(1, _T("PostQuitMessage in handling ID_CLOSEDAEMON\n"));
PostQuitMessage(0);
}
return 0;
// Modif sf@2002 - FileTransfer
case ID_FILETRANSFER:
// Check if the Server knows FileTransfer
if (!_this->m_fServerKnowsFileTransfer)
{
MessageBox(NULL, sz_L77,
sz_L78,
MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
// Don't call FileTRansfer GUI is already open !
if (_this->m_pFileTransfer->m_fFileTransferRunning)
{
_this->m_pFileTransfer->ShowFileTransferWindow(true);
return 0;
/*
MessageBox(NULL, sz_L79,
sz_L80,
MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
*/
}
if (_this->m_pTextChat->m_fTextChatRunning)
{
_this->m_pTextChat->ShowChatWindow(true);
MessageBox( NULL,
sz_L86,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
// Call FileTransfer Dialog
_this->m_pFileTransfer->m_fFileTransferRunning = true;
_this->m_pFileTransfer->m_fFileCommandPending = false;
#ifndef _ULTRAVNCAX_
_this->m_pFileTransfer->DoDialog();
#else
_this->m_pFileTransfer->DoDialog ( GetTopMostWnd( _this->m_hwndMain ? _this->m_hwndMain : _this->m_hwndAx ) );
#endif
_this->m_pFileTransfer->m_fFileTransferRunning = false;
// Refresh Screen
// _this->SendFullFramebufferUpdateRequest();
if (_this->m_pFileTransfer->m_fVisible || _this->m_pFileTransfer->m_fOldFTProtocole)
_this->SendAppropriateFramebufferUpdateRequest();
return 0;
// sf@2002 - Text Chat
case ID_TEXTCHAT:
// We use same flag as FT for now
// Check if the Server knows FileTransfer
if (!_this->m_fServerKnowsFileTransfer)
{
MessageBox(NULL, sz_L81,
sz_L82,
MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
if (_this->m_pTextChat->m_fTextChatRunning)
{
_this->m_pTextChat->ShowChatWindow(true);
return 0;
/*
MessageBox(NULL, sz_L83,
sz_L84,
MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
*/
}
if (_this->m_pFileTransfer->m_fFileTransferRunning)
{
_this->m_pFileTransfer->ShowFileTransferWindow(true);
MessageBox(NULL,
sz_L85,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
_this->m_pTextChat->m_fTextChatRunning = true;
_this->m_pTextChat->DoDialog();
return 0;
// sf@2002
case ID_MAXCOLORS:
if (_this->m_opts.m_Use8Bit)
{
_this->m_opts.m_Use8Bit = rfbPFFullColors; //false;
_this->m_pendingFormatChange = true;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
// sf@2002
case ID_256COLORS:
// if (!_this->m_opts.m_Use8Bit)
{
_this->m_opts.m_Use8Bit = rfbPF256Colors; //true;
_this->m_pendingFormatChange = true;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
// Modif sf@2002
case ID_HALFSCREEN:
{
// Toggle halfSize screen mode (server side)
int nOldServerScale = _this->m_nServerScale;
// Modif sf@2002 - Server Scaling
_this->m_opts.m_fAutoScaling = false;
_this->m_nServerScale = 2;
_this->m_opts.m_nServerScale = 2;
_this->m_opts.m_scaling = true;
_this->m_opts.m_scale_num = 100;
_this->m_opts.m_scale_den = 100;
if (_this->m_nServerScale != nOldServerScale)
{
_this->SendServerScale(_this->m_nServerScale);
// _this->m_pendingFormatChange = true;
}
else
{
_this->SizeWindow();
InvalidateRect(hwnd, NULL, TRUE);
_this->RealiseFullScreenMode();
_this->m_pendingFormatChange = true;
}
return 0;
}
// Modif sf@2002
case ID_FUZZYSCREEN:
{
// Toggle fuzzy screen mode (server side)
int nOldServerScale = _this->m_nServerScale;
// We don't forbid AutoScaling if selected
// so the viewer zoom factor is more accurate
_this->m_nServerScale = 2;
_this->m_opts.m_nServerScale = 2;
_this->m_opts.m_scaling = true;
_this->m_opts.m_scale_num = 200;
_this->m_opts.m_scale_den = 100;
if (_this->m_nServerScale != nOldServerScale)
{
_this->SendServerScale(_this->m_nServerScale);
// _this->m_pendingFormatChange = true;
}
else
{
_this->SizeWindow();
InvalidateRect(hwnd, NULL, TRUE);
_this->RealiseFullScreenMode();
_this->m_pendingFormatChange = true;
}
return 0;
}
// Modif sf@2002
case ID_NORMALSCREEN:
{
// Toggle normal screen
int nOldServerScale = _this->m_nServerScale;
_this->m_opts.m_fAutoScaling = false;
_this->m_nServerScale = 1;
_this->m_opts.m_nServerScale = 1;
_this->m_opts.m_scaling = false;
_this->m_opts.m_scale_num = 100;
_this->m_opts.m_scale_den = 100;
if (_this->m_nServerScale != nOldServerScale)
{
_this->SendServerScale(_this->m_nServerScale);
// _this->m_pendingFormatChange = true;
}
else
{
_this->SizeWindow();
InvalidateRect(hwnd, NULL, TRUE);
_this->SetFullScreenMode(false);
_this->m_pendingFormatChange = true;
}
return 0;
}
} // end switch lowparam syscommand
break;
}//end case wm_syscommand
#ifndef UNDER_CE
case WM_SIZING:
{
// Don't allow sizing larger than framebuffer
RECT *lprc = (LPRECT) lParam;
switch (wParam) {
case WMSZ_RIGHT:
case WMSZ_TOPRIGHT:
case WMSZ_BOTTOMRIGHT:
lprc->right = min(lprc->right, lprc->left + _this->m_fullwinwidth+1 );
break;
case WMSZ_LEFT:
case WMSZ_TOPLEFT:
case WMSZ_BOTTOMLEFT:
lprc->left = max(lprc->left, lprc->right - _this->m_fullwinwidth);
break;
}
switch (wParam) {
case WMSZ_TOP:
case WMSZ_TOPLEFT:
case WMSZ_TOPRIGHT:
if (_this->m_opts.m_ShowToolbar)
lprc->top = max(lprc->top, lprc->bottom - _this->m_fullwinheight -_this->m_TBr.bottom);
else
lprc->top = max(lprc->top, lprc->bottom - _this->m_fullwinheight);
break;
case WMSZ_BOTTOM:
case WMSZ_BOTTOMLEFT:
case WMSZ_BOTTOMRIGHT:
if (_this->m_opts.m_ShowToolbar)
lprc->bottom = min(lprc->bottom, lprc->top + _this->m_fullwinheight + _this->m_TBr.bottom);
else
lprc->bottom = min(lprc->bottom, lprc->top + _this->m_fullwinheight);
break;
}
return 0;
}
#endif
case WM_QUERYOPEN:
_this->SetDormant(false);
return true;
case WM_SETFOCUS:
TheAccelKeys.SetWindowHandle(_this->m_opts.m_NoHotKeys ? 0 : hwnd);
return 0;
case WM_KILLFOCUS:
if (!_this->m_running) return 0;
if ( _this->m_opts.m_ViewOnly) return 0;
_this->SendKeyEvent(XK_Alt_L, false);
_this->SendKeyEvent(XK_Control_L, false);
_this->SendKeyEvent(XK_Shift_L, false);
_this->SendKeyEvent(XK_Alt_R, false);
_this->SendKeyEvent(XK_Control_R, false);
_this->SendKeyEvent(XK_Shift_R, false);
return 0;
case WM_CLOSE:
{
#ifndef _ULTRAVNCAX_
// sf@2002 - Do not close vncviewer if the File Transfer GUI is open !
if (_this->m_pFileTransfer->m_fFileTransferRunning)
{
_this->m_pFileTransfer->ShowFileTransferWindow(true);
MessageBox(NULL, sz_L85,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
// sf@2002 - Do not close vncviewer if the Text Chat GUI is open !
if (_this->m_pTextChat->m_fTextChatRunning)
{
_this->m_pTextChat->ShowChatWindow(true);
MessageBox(NULL, sz_L86,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
if (_this->m_fOptionsOpen)
{
MessageBox(NULL, sz_L87,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
#endif
// Close the worker thread as well
_this->KillThread();
DestroyWindow(_this->m_hwndTB);
_this->m_hwndTB = NULL;
DestroyWindow(_this->m_TrafficMonitor);
_this->m_TrafficMonitor = NULL;
DestroyWindow(_this->m_logo_wnd);
_this->m_logo_wnd = NULL;
DestroyWindow(_this->m_button_wnd);
_this->m_button_wnd = NULL;
// DestroyWindow(_this->m_hwndTBwin);
DestroyWindow(_this->m_hwnd);
_this->m_hwnd = NULL;
DestroyWindow(hwnd);
vnclog.Print(1, _T("ClientConnection Handle WM_CLOSE done\n"));
return 0;
}
case WM_DESTROY:
{
#ifndef UNDER_CE
// Remove us from the clipboard viewer chain
BOOL res = ChangeClipboardChain( _this->m_hwnd, _this->m_hwndNextViewer);
#endif
if (_this->m_waitingOnEmulateTimer)
{
KillTimer(_this->m_hwnd, _this->m_emulate3ButtonsTimer);
_this->m_waitingOnEmulateTimer = false;
}
// if (_this->m_FTtimer != 0)
// {
// KillTimer(hwnd, _this->m_FTtimer);
// _this->m_FTtimer = 0;
// }
//_this->m_hwnd = 0;
// We are currently in the main thread.
// The worker thread should be about to finish if
// it hasn't already. Wait for it.
if(_this->m_hwndTB)
DestroyWindow(_this->m_hwndTB);
_this->m_hwndTB = NULL;
if(_this->m_TrafficMonitor)
DestroyWindow(_this->m_TrafficMonitor);
_this->m_TrafficMonitor = NULL;
if(_this->m_logo_wnd)
DestroyWindow(_this->m_logo_wnd);
_this->m_logo_wnd = NULL;
if(_this->m_button_wnd)
DestroyWindow(_this->m_button_wnd);
_this->m_button_wnd = NULL;
if(_this->m_hwnd)
DestroyWindow(_this->m_hwnd);
_this->m_hwnd = NULL;
::SetWindowLong(hwnd, GWL_USERDATA, 0);
_this->KillThread();
try {
void *p;
_this->join(&p); // After joining, _this is no longer valid
} catch (omni_thread_invalid& e) {
// The thread probably hasn't been started yet,
}
//PostQuitMessage(0);
vnclog.Print(1, _T("ClientConnection Handle WM_DESTROY done\n"));
return 0;
}
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
if (!_this->m_running) return 0;
if ( _this->m_opts.m_ViewOnly) return 0;
_this->ProcessKeyEvent((int) wParam, (DWORD) lParam);
return 0;
}
/*
case WM_CHAR:
case WM_SYSCHAR:
#ifdef UNDER_CE
{
int key = wParam;
vnclog.Print(4,_T("CHAR msg : %02x\n"), key);
// Control keys which are in the Keymap table will already
// have been handled.
if (key == 0x0D || // return
key == 0x20 || // space
key == 0x08) // backspace
return 0;
if (key < 32) key += 64; // map ctrl-keys onto alphabet
if (key > 32 && key < 127) {
_this->SendKeyEvent(wParam & 0xff, true);
_this->SendKeyEvent(wParam & 0xff, false);
}
return 0;
}
#endif
*/
case WM_DEADCHAR:
case WM_SYSDEADCHAR:
return 0;
case WM_WINDOWPOSCHANGED:
case WM_SIZE:
{
// Calculate window dimensions
RECT rect;
RECT Rtb;
GetWindowRect(hwnd, &rect);
_this->m_winwidth = rect.right - rect.left;
_this->m_winheight = rect.bottom - rect.top ;
if (_this->m_opts.m_ShowToolbar)
{
GetWindowRect(_this->m_hwndTBwin, &Rtb);
//MoveWindow(_this->m_hwndTB,
// 0,0,_this->m_winwidth - 106, 32,TRUE);
//SetWindowPos(_this->m_hwndTBwin, HWND_TOP, 0, 0, _this->m_winwidth, 32,SWP_FRAMECHANGED);
if ((_this->m_winwidth) > 140+85+14*24)
{
if (_this->m_BigToolbar==false)
{
DestroyWindow(_this->m_hwndTB);
_this->m_BigToolbar=true;
_this->CreateButtons(false,_this->m_fServerKnowsFileTransfer);
}
}
else
{
if (_this->m_BigToolbar==true)
{
_this->m_BigToolbar=false;
DestroyWindow(_this->m_hwndTB);
_this->CreateButtons(true,_this->m_fServerKnowsFileTransfer);
}
}
SetWindowPos(_this->m_hwndTB,HWND_TOP,0,0,_this->m_winwidth - 200, 32,SWP_FRAMECHANGED);
if (_this->m_TrafficMonitor)
{
MoveWindow(_this->m_TrafficMonitor,
_this->m_winwidth - 55,2,35,30,TRUE);
MoveWindow(_this->m_logo_wnd,
_this->m_winwidth - 185,2,130,28,TRUE);
MoveWindow(_this->m_button_wnd,
_this->m_winwidth - 200,10,10,10,TRUE);
}
if (_this->m_logo_wnd)
{
MoveWindow(_this->m_logo_wnd,
_this->m_winwidth - 185,2,130,28,TRUE);
MoveWindow(_this->m_button_wnd,
_this->m_winwidth - 200,10,10,10,TRUE);
}
UpdateWindow(_this->m_hwndTB);
UpdateWindow(_this->m_logo_wnd);
UpdateWindow(_this->m_button_wnd);
}
else
{
Rtb.top=0;Rtb.bottom=0;
}
// If the current window size would be large enough to hold the
// whole screen without scrollbars, or if we're full-screen,
// we turn them off. Under CE, the scroll bars are unchangeable.
#ifndef UNDER_CE
if (_this->InFullScreenMode() ||
_this->m_winwidth >= _this->m_fullwinwidth &&
_this->m_winheight >= (_this->m_fullwinheight + ((Rtb.bottom - Rtb.top) )) ) {
//_this->m_winheight >= _this->m_fullwinheight ) {
ShowScrollBar(hwnd, SB_HORZ, FALSE);
ShowScrollBar(hwnd, SB_VERT, FALSE);
} else {
ShowScrollBar(hwnd, SB_HORZ, TRUE);
ShowScrollBar(hwnd, SB_VERT, TRUE);
}
#endif
// Update these for the record
// And consider that in full-screen mode the window
// is actually bigger than the remote screen.
GetClientRect(hwnd, &rect);
_this->m_cliwidth = min( (int)(rect.right - rect.left),
(int)(_this->m_si.framebufferWidth * _this->m_opts.m_scale_num / _this->m_opts.m_scale_den));
if (_this->m_opts.m_ShowToolbar)
_this->m_cliheight = min( (int)rect.bottom - rect.top ,
(int)_this->m_si.framebufferHeight * _this->m_opts.m_scale_num / _this->m_opts.m_scale_den + _this->m_TBr.bottom);
else
_this->m_cliheight = min( (int)(rect.bottom - rect.top) ,
(int)(_this->m_si.framebufferHeight * _this->m_opts.m_scale_num / _this->m_opts.m_scale_den));
_this->m_hScrollMax = (int)_this->m_si.framebufferWidth * _this->m_opts.m_scale_num / _this->m_opts.m_scale_den;
if (_this->m_opts.m_ShowToolbar)
_this->m_vScrollMax = (int)(_this->m_si.framebufferHeight *
_this->m_opts.m_scale_num / _this->m_opts.m_scale_den)
+ _this->m_TBr.bottom;
else
_this->m_vScrollMax = (int)(_this->m_si.framebufferHeight*
_this->m_opts.m_scale_num / _this->m_opts.m_scale_den);
int newhpos, newvpos;
newhpos = max(0,
min(_this->m_hScrollPos,
_this->m_hScrollMax - max(_this->m_cliwidth, 0)
)
);
newvpos = max(0,
min(_this->m_vScrollPos,
_this->m_vScrollMax - max(_this->m_cliheight, 0)
)
);
ScrollWindowEx(_this->m_hwnd,
_this->m_hScrollPos - newhpos,
_this->m_vScrollPos - newvpos,
NULL, &rect, NULL, NULL, SW_INVALIDATE);
_this->m_hScrollPos = newhpos;
_this->m_vScrollPos = newvpos;
_this->UpdateScrollbars();
//Added by: Lars Werner (http://lars.werner.no)
if(wParam==SIZE_MAXIMIZED&&_this->InFullScreenMode()==FALSE)
{
_this->SetFullScreenMode(!_this->InFullScreenMode());
//MessageBox(NULL,"Fullscreeen from maximizehora...","KAKE",MB_OK);
//return 0;
}
//Modified by: Lars Werner (http://lars.werner.no)
if(_this->InFullScreenMode()==TRUE)
return 0;
else
break;
}
case WM_HSCROLL:
{
int dx = 0;
int pos = HIWORD(wParam);
switch (LOWORD(wParam)) {
case SB_LINEUP:
dx = -2; break;
case SB_LINEDOWN:
dx = 2; break;
case SB_PAGEUP:
dx = _this->m_cliwidth * -1/4; break;
case SB_PAGEDOWN:
dx = _this->m_cliwidth * 1/4; break;
case SB_THUMBPOSITION:
dx = pos - _this->m_hScrollPos;
case SB_THUMBTRACK:
dx = pos - _this->m_hScrollPos;
}
_this->ScrollScreen(dx,0);
return 0;
}
case WM_VSCROLL:
{
int dy = 0;
int pos = HIWORD(wParam);
switch (LOWORD(wParam)) {
case SB_LINEUP:
dy = -2; break;
case SB_LINEDOWN:
dy = 2; break;
case SB_PAGEUP:
dy = _this->m_cliheight * -1/4; break;
case SB_PAGEDOWN:
dy = _this->m_cliheight * 1/4; break;
case SB_THUMBPOSITION:
dy = pos - _this->m_vScrollPos;
case SB_THUMBTRACK:
dy = pos - _this->m_vScrollPos;
}
_this->ScrollScreen(0,dy);
return 0;
}
// RealVNC 335 method
case WM_MOUSEWHEEL:
if (!_this->m_opts.m_ViewOnly)
_this->ProcessMouseWheel((SHORT)HIWORD(wParam));
return 0;
//Added by: Lars Werner (http://lars.werner.no) - These is the custom messages from the TitleBar
case tbWM_CLOSE:
SendMessage(_this->m_hwndMain, WM_CLOSE,NULL,NULL);
return 0;
case tbWM_MINIMIZE:
_this->SetDormant(true);
ShowWindow(_this->m_hwndMain, SW_MINIMIZE);
return 0;
case tbWM_MAXIMIZE:
//_this->SetFullScreenMode(!_this->InFullScreenMode());
_this->SetFullScreenMode(FALSE);
return 0;
} // end of iMsg switch
//return DefWindowProc(hwnd, iMsg, wParam, lParam);
// Process asynchronous FileTransfer in this thread
if ((iMsg == FileTransferSendPacketMessage) && (_this->m_pFileTransfer != NULL))
{
if (LOWORD(wParam) == 0)
{
// if (_this->m_FTtimer != 0)_this->m_FTtimer=SetTimer(hwnd,11, 100, 0);//
_this->m_pFileTransfer->SendFileChunk();
}
else
_this->m_pFileTransfer->ProcessFileTransferMsg();
return 0;
}
} // End if Main Window
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
// We know about an unused variable here.
#pragma warning(disable : 4101)
}
//
//
//
LRESULT CALLBACK ClientConnection::WndProcTBwin(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
ClientConnection *_this = (ClientConnection *) GetWindowLong(hwnd, GWL_USERDATA);
if (_this == NULL) return DefWindowProc(hwnd, iMsg, wParam, lParam);
HWND parent;
if (_this->m_opts.m_ShowToolbar==true)
{
parent = _this->m_hwndMain;
switch (iMsg)
{
case WM_PAINT:
{
if (_this->m_logo_wnd)
{
/*HDC hdcX,hdcBits;
hdcX = GetDC(_this->m_logo_wnd);
hdcBits = CreateCompatibleDC(hdcX);
SelectObject(hdcBits,_this->m_logo_min);
BitBlt(hdcX,0,0,70,28,hdcBits,0,0,SRCCOPY);
DeleteDC(hdcBits);
ReleaseDC(_this->m_logo_wnd,hdcX);*/
UpdateWindow(_this->m_logo_wnd);
}
break;
}
case WM_COMMAND:
if (LOWORD(wParam) == ID_BUTTON_INFO)
{
if (IsWindow(_this->m_hwndStatus)){
if (_this->m_hwndStatus)SetForegroundWindow(_this->m_hwndStatus);
if (_this->m_hwndStatus)ShowWindow(_this->m_hwndStatus, SW_NORMAL);
}else{
SECURITY_ATTRIBUTES lpSec;
DWORD threadID;
_this->m_statusThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE )ClientConnection::GTGBS_ShowStatusWindow,(LPVOID)_this,0,&threadID);
}
return 0;
}
if (LOWORD(wParam) ==9998)
{
vnclog.Print(0,_T("CLICKK %d\n"),HIWORD(wParam));
switch (HIWORD(wParam)) {
case 0:
{
int port;
TCHAR fulldisplay[256];
TCHAR display[256];
GetDlgItemText(hwnd, 9999, display, 256);
_tcscpy(fulldisplay, display);
vnclog.Print(0,_T("CLICKK %s\n"),fulldisplay);
ParseDisplay(fulldisplay, display, 256, &port);
_this->m_pApp->NewConnection(display,port, NULL, NULL);
}
}
break;
return TRUE;
}
if (LOWORD(wParam) == ID_BUTTON_SEP)
{
UINT Key;
//_this->SendKeyEvent(XK_Execute, true);
//_this->SendKeyEvent(XK_Execute, false);
Key = DialogBox(_this->m_pApp->m_instance,MAKEINTRESOURCE(IDD_CUSTUM_KEY),NULL,(DLGPROC)ClientConnection::GTGBS_SendCustomKey_proc);
if (Key>0){
vnclog.Print(0,_T("START Send Custom Key %d\n"),Key);
if ( (Key & KEYMAP_LALT) == KEYMAP_LALT){
_this->SendKeyEvent(XK_Alt_L,true);
_this->SendKeyEvent(Key ^ KEYMAP_LALT,true);
_this->SendKeyEvent(Key ^ KEYMAP_LALT,false);
_this->SendKeyEvent(XK_Alt_L,false);
}else if ( (Key & KEYMAP_RALT) ==KEYMAP_RALT){
_this->SendKeyEvent(XK_Alt_R,true);
_this->SendKeyEvent(XK_Control_R,true);
_this->SendKeyEvent(Key ^ KEYMAP_RALT,true);
_this->SendKeyEvent(Key ^ KEYMAP_RALT,false);
_this->SendKeyEvent(XK_Alt_R,false);
_this->SendKeyEvent(XK_Control_R,false);
}else if ( (Key & KEYMAP_RCONTROL) == KEYMAP_RCONTROL){
_this->SendKeyEvent(XK_Control_R,true);
_this->SendKeyEvent(Key ^ KEYMAP_RCONTROL,true);
_this->SendKeyEvent(Key ^ KEYMAP_RCONTROL,false);
_this->SendKeyEvent(XK_Control_R,false);
}else{
_this->SendKeyEvent(Key,true);
_this->SendKeyEvent(Key,false);
}
vnclog.Print(0,_T("END Send Custom Key %d\n"),Key);
}
SetForegroundWindow(_this->m_hwnd);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_END )
{
SendMessage(parent,WM_CLOSE,(WPARAM)0,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_CAD )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_CONN_CTLALTDEL,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_FULLSCREEN )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_FULLSCREEN,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_FTRANS )
{
if (_this->m_pFileTransfer->m_fFileTransferRunning)
{
_this->m_pFileTransfer->ShowFileTransferWindow(true);
}
else
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_FILETRANSFER,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_DBUTTON )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_DBUTTON,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_SW )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_SW,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_DESKTOP )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_DESKTOP,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_TEXTCHAT )
{
if (_this->m_pTextChat->m_fTextChatRunning)
{
_this->m_pTextChat->ShowChatWindow(true);
}
else
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_TEXTCHAT,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_DINPUT )
{
if (_this->m_remote_mouse_disable)
{
_this->m_remote_mouse_disable=false;
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_INPUT,(LPARAM)0);
SendMessage(parent,WM_SIZE,(WPARAM)ID_DINPUT,(LPARAM)0);
}
else
{
_this->m_remote_mouse_disable=true;
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_DINPUT,(LPARAM)0);
SendMessage(parent,WM_SIZE,(WPARAM)ID_DINPUT,(LPARAM)0);
}
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_PROPERTIES )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)IDC_OPTIONBUTTON,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_REFRESH )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_REQUEST_REFRESH,(LPARAM)0);
return 0;
}
if (LOWORD(wParam) == ID_BUTTON_STRG_ESC )
{
SendMessage(parent,WM_SYSCOMMAND,(WPARAM)ID_CONN_CTLESC,(LPARAM)0);
return 0;
}
}
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
//
//
//
LRESULT CALLBACK ClientConnection::WndProchwnd(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
// HWND parent;
ClientConnection *_this = (ClientConnection *) GetWindowLong(hwnd, GWL_USERDATA);
if (_this == NULL) return DefWindowProc(hwnd, iMsg, wParam, lParam);
switch (iMsg)
{
case WM_CREATE:
SetTimer(_this->m_hwnd,3335, 1000, NULL);
return 0;
case WM_REGIONUPDATED:
//_this->DoBlit();
_this->SendAppropriateFramebufferUpdateRequest();
return 0;
case WM_PAINT:
_this->DoBlit();
return 0;
case WM_TIMER:
if (wParam == _this->m_emulate3ButtonsTimer)
{
_this->SubProcessPointerEvent(
_this->m_emulateButtonPressedX,
_this->m_emulateButtonPressedY,
_this->m_emulateKeyFlags);
KillTimer(_this->m_hwnd, _this->m_emulate3ButtonsTimer);
_this->m_waitingOnEmulateTimer = false;
}
return 0;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
if (_this->m_SWselect)
{
_this->m_SWpoint.x=LOWORD(lParam);
_this->m_SWpoint.y=HIWORD(lParam);
_this->SendSW(_this->m_SWpoint.x,_this->m_SWpoint.y);
return 0;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
{
if (_this->m_SWselect) {return 0;}
if (!_this->m_running) return 0;
// if (GetFocus() != hwnd) return 0;
// if (GetFocus() != _this->m_hwnd) return 0;
#ifndef _ULTRAVNCAX_
if (GetFocus() != _this->m_hwndMain) return 0;
#endif
int x = LOWORD(lParam);
int y = HIWORD(lParam);
wParam = MAKEWPARAM(LOWORD(wParam), 0);
if (_this->InFullScreenMode()) {
if (_this->BumpScroll(x,y))
return 0;
}
if ( _this->m_opts.m_ViewOnly) return 0;
_this->ProcessPointerEvent(x,y, wParam, iMsg);
return 0;
}
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
if (!_this->m_running) return 0;
if ( _this->m_opts.m_ViewOnly) return 0;
_this->ProcessKeyEvent((int) wParam, (DWORD) lParam);
return 0;
}
case WM_CHAR:
case WM_SYSCHAR:
#ifdef UNDER_CE
{
int key = wParam;
vnclog.Print(4,_T("CHAR msg : %02x\n"), key);
// Control keys which are in the Keymap table will already
// have been handled.
if (key == 0x0D || // return
key == 0x20 || // space
key == 0x08) // backspace
return 0;
if (key < 32) key += 64; // map ctrl-keys onto alphabet
if (key > 32 && key < 127) {
_this->SendKeyEvent(wParam & 0xff, true);
_this->SendKeyEvent(wParam & 0xff, false);
}
return 0;
}
#endif
case WM_DEADCHAR:
case WM_SYSDEADCHAR:
return 0;
case WM_SETFOCUS:
if (_this->InFullScreenMode())
SetWindowPos(hwnd, HWND_TOPMOST, 0,0,100,100, SWP_NOMOVE | SWP_NOSIZE);
return 0;
// Cacnel modifiers when we lose focus
case WM_KILLFOCUS:
{
if (!_this->m_running) return 0;
if (_this->InFullScreenMode()) {
// We must top being topmost, but we want to choose our
// position carefully.
HWND foreground = GetForegroundWindow();
HWND hwndafter = NULL;
if ((foreground == NULL) ||
(GetWindowLong(foreground, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
hwndafter = HWND_NOTOPMOST;
} else {
hwndafter = GetNextWindow(foreground, GW_HWNDNEXT);
}
SetWindowPos(hwnd, hwndafter, 0,0,100,100, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
/*
vnclog.Print(6, _T("Losing focus - cancelling modifiers\n"));
_this->SendKeyEvent(XK_Alt_L, false);
_this->SendKeyEvent(XK_Control_L, false);
_this->SendKeyEvent(XK_Shift_L, false);
_this->SendKeyEvent(XK_Alt_R, false);
_this->SendKeyEvent(XK_Control_R, false);
_this->SendKeyEvent(XK_Shift_R, false);
*/
return 0;
}
case WM_CLOSE:
{
#ifndef _ULTRAVNCAX_
// sf@2002 - Do not close vncviewer if the File Transfer GUI is open !
if (_this->m_pFileTransfer->m_fFileTransferRunning)
{
_this->m_pFileTransfer->ShowFileTransferWindow(true);
MessageBox(NULL, sz_L85,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
// sf@2002 - Do not close vncviewer if the Text Chat GUI is open !
if (_this->m_pTextChat->m_fTextChatRunning)
{
_this->m_pTextChat->ShowChatWindow(true);
MessageBox(NULL, sz_L86,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
if (_this->m_fOptionsOpen)
{
MessageBox(NULL, sz_L87,
sz_L88,
MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
return 0;
}
#endif
// Close the worker thread as well
_this->KillThread();
DestroyWindow(hwnd);
return 0;
}
case WM_DESTROY:
{
#ifndef UNDER_CE
// Remove us from the clipboard viewer chain
BOOL res = ChangeClipboardChain( hwnd, _this->m_hwndNextViewer);
#endif
if (_this->m_waitingOnEmulateTimer)
{
KillTimer(_this->m_hwnd, _this->m_emulate3ButtonsTimer);
KillTimer(_this->m_hwnd, 3335);
_this->m_waitingOnEmulateTimer = false;
}
/*
_this->m_hwnd = 0;
// We are currently in the main thread.
// The worker thread should be about to finish if
// it hasn't already. Wait for it.
try {
void *p;
_this->join(&p); // After joining, _this is no longer valid
} catch (omni_thread_invalid& e) {
// The thread probably hasn't been started yet,
}*/
return 0;
}
case WM_QUERYNEWPALETTE:
{
TempDC hDC(hwnd);
// Select and realize hPalette
PaletteSelector p(hDC, _this->m_hPalette);
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
return TRUE;
}
case WM_PALETTECHANGED:
// If this application did not change the palette, select
// and realize this application's palette
if ((HWND) wParam != hwnd)
{
// Need the window's DC for SelectPalette/RealizePalette
TempDC hDC(hwnd);
PaletteSelector p(hDC, _this->m_hPalette);
// When updating the colors for an inactive window,
// UpdateColors can be called because it is faster than
// redrawing the client area (even though the results are
// not as good)
#ifndef UNDER_CE
UpdateColors(hDC);
#else
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
#endif
}
break;
#ifndef UNDER_CE
case WM_SIZING:
{
// Don't allow sizing larger than framebuffer
RECT *lprc = (LPRECT) lParam;
switch (wParam) {
case WMSZ_RIGHT:
case WMSZ_TOPRIGHT:
case WMSZ_BOTTOMRIGHT:
lprc->right = min(lprc->right, lprc->left + _this->m_fullwinwidth+1);
break;
case WMSZ_LEFT:
case WMSZ_TOPLEFT:
case WMSZ_BOTTOMLEFT:
lprc->left = max(lprc->left, lprc->right - _this->m_fullwinwidth);
break;
}
switch (wParam) {
case WMSZ_TOP:
case WMSZ_TOPLEFT:
case WMSZ_TOPRIGHT:
lprc->top = max(lprc->top, lprc->bottom - _this->m_fullwinheight);
break;
case WMSZ_BOTTOM:
case WMSZ_BOTTOMLEFT:
case WMSZ_BOTTOMRIGHT:
lprc->bottom = min(lprc->bottom, lprc->top + _this->m_fullwinheight);
break;
}
return 0;
}
case WM_SETCURSOR:
{
// if we have the focus, let the cursor change as normal
if (GetFocus() == hwnd)
break;
HCURSOR h;
switch (_this->m_opts.m_localCursor) {
case NOCURSOR:
h= LoadCursor(_this->m_pApp->m_instance, MAKEINTRESOURCE(IDC_NOCURSOR));
break;
case NORMALCURSOR:
h= LoadCursor(NULL, IDC_ARROW);
break;
case DOTCURSOR:
default:
h= LoadCursor(_this->m_pApp->m_instance, MAKEINTRESOURCE(IDC_DOTCURSOR));
}
if (_this->m_SWselect) h= LoadCursor(_this->m_pApp->m_instance, MAKEINTRESOURCE(IDC_CURSOR1));
SetCursor(h);
return 0;
}
case WM_DRAWCLIPBOARD:
_this->ProcessLocalClipboardChange();
return 0;
case WM_CHANGECBCHAIN:
{
// The clipboard chain is changing
HWND hWndRemove = (HWND) wParam; // handle of window being removed
HWND hWndNext = (HWND) lParam; // handle of next window in chain
// If next window is closing, update our pointer.
if (hWndRemove == _this->m_hwndNextViewer)
_this->m_hwndNextViewer = hWndNext;
// Otherwise, pass the message to the next link.
else if (_this->m_hwndNextViewer != NULL)
::SendMessage(_this->m_hwndNextViewer, WM_CHANGECBCHAIN,
(WPARAM) hWndRemove, (LPARAM) hWndNext );
return 0;
}
#endif
// Modif VNCon MultiView support
// Messages used by VNCon - Copyright (C) 2001-2003 - Alastair Burr
case WM_GETSCALING:
{
WPARAM wPar;
wPar = MAKEWPARAM(_this->m_hScrollMax, _this->m_vScrollMax);
SendMessage((HWND)wParam, WM_GETSCALING, wPar, lParam);
return TRUE;
}
case WM_SETSCALING:
{
_this->m_opts.m_scaling = true;
_this->m_opts.m_scale_num = wParam;
_this->m_opts.m_scale_den = lParam;
if (_this->m_opts.m_scale_num == 1 && _this->m_opts.m_scale_den == 1)
_this->m_opts.m_scaling = false;
_this->SizeWindow();
InvalidateRect(hwnd, NULL, TRUE);
return TRUE;
}
case WM_SETVIEWONLY:
{
_this->m_opts.m_ViewOnly = (wParam == 1);
return TRUE;
}
// End Modif for VNCon MultiView support
}//end switch (iMsg)
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
void
ClientConnection:: ConvertAll(int width, int height, int xx, int yy,int bytes_per_pixel,BYTE* source,BYTE* dest,int framebufferWidth)
{
int bytesPerInputRow = width * bytes_per_pixel;
int bytesPerOutputRow = framebufferWidth * bytes_per_pixel;
BYTE *sourcepos,*destpos;
destpos = (BYTE *)dest + (bytesPerOutputRow * yy)+(xx * bytes_per_pixel);
sourcepos=(BYTE*)source;
int y;
width*=bytes_per_pixel;
for (y=0; y<height; y++) {
memcpy(destpos, sourcepos, width);
sourcepos = (BYTE*)sourcepos + bytesPerInputRow;
destpos = (BYTE*)destpos + bytesPerOutputRow;
}
}
bool
ClientConnection:: Check_Rectangle_borders(int x,int y,int w,int h)
{
if (x<0) return false;
if (y<0) return false;
if (x+w>m_si.framebufferWidth) return false;
if (y+h>m_si.framebufferHeight) return false;
if (x+w<x) return false;
if (y+h<y) return false;
return true;
}
#pragma warning(default :4101)