// 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 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 #include #include #include #include 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; ipalPalEntry[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ä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; ym_si.framebufferWidth) return false; if (y+h>m_si.framebufferHeight) return false; if (x+w