ClientConnection.cpp
上传用户:sbftbdw
上传日期:2007-01-03
资源大小:379k
文件大小:56k
源码类别:

远程控制编程

开发平台:

Visual C++

  1. //  Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
  2. //
  3. //  This file is part of the VNC system.
  4. //
  5. //  The VNC system is free software; you can redistribute it and/or modify
  6. //  it under the terms of the GNU General Public License as published by
  7. //  the Free Software Foundation; either version 2 of the License, or
  8. //  (at your option) any later version.
  9. //
  10. //  This program is distributed in the hope that it will be useful,
  11. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //  GNU General Public License for more details.
  14. //
  15. //  You should have received a copy of the GNU General Public License
  16. //  along with this program; if not, write to the Free Software
  17. //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  18. //  USA.
  19. //
  20. // If the source code for the VNC system is not available from the place 
  21. // whence you received this file, check http://www.orl.co.uk/vnc or contact
  22. // the authors on vnc@orl.co.uk for information on obtaining it.
  23. // Many thanks to Randy Brown <rgb@inven.com> for providing the 3-button
  24. // emulation code.
  25. // This is the main source for a ClientConnection object.
  26. // It handles almost everything to do with a connection to a server.
  27. // The decoding of specific rectangle encodings is done in separate files.
  28. #include "stdhdrs.h"
  29. #include "vncviewer.h"
  30. #ifdef UNDER_CE
  31. #include "omnithreadce.h"
  32. #define SD_BOTH 0x02
  33. #else
  34. #include "omnithread.h"
  35. #endif
  36. #include "ClientConnection.h"
  37. #include "SessionDialog.h"
  38. #include "AuthDialog.h"
  39. #include "AboutBox.h"
  40. #include "Exception.h"
  41. extern "C" {
  42. #include "vncauth.h"
  43. }
  44. #define INITIALNETBUFSIZE 4096
  45. #define MAX_ENCODINGS 10
  46. #define VWR_WND_CLASS_NAME _T("VNCviewer")
  47. const rfbPixelFormat vnc8bitFormat = {8, 8, 1, 1, 7,7,3, 0,3,6,0,0};
  48. const rfbPixelFormat vnc16bitFormat = {16, 16, 1, 1, 63, 31, 31, 0,6,11,0,0};
  49. static LRESULT CALLBACK ClientConnection::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
  50. // Some handy classes for temporary GDI object selection
  51. // These select objects when constructed and automatically release them when destructed.
  52. class ObjectSelector {
  53. public:
  54. ObjectSelector(HDC hdc, HGDIOBJ hobj) { m_hdc = hdc; m_hOldObj = SelectObject(hdc, hobj); }
  55. ~ObjectSelector() { m_hOldObj = SelectObject(m_hdc, m_hOldObj); }
  56. HGDIOBJ m_hOldObj;
  57. HDC m_hdc;
  58. };
  59. class PaletteSelector {
  60. public:
  61. PaletteSelector(HDC hdc, HPALETTE hpal) { 
  62. m_hdc = hdc; 
  63. m_hOldPal = SelectPalette(hdc, hpal, FALSE); 
  64. RealizePalette(hdc);
  65. }
  66. ~PaletteSelector() { 
  67. m_hOldPal = SelectPalette(m_hdc, m_hOldPal, FALSE); 
  68. RealizePalette(m_hdc);
  69. }
  70. HPALETTE m_hOldPal;
  71. HDC m_hdc;
  72. };
  73. class TempDC {
  74. public:
  75. TempDC(HWND hwnd) { m_hdc = GetDC(hwnd); m_hwnd = hwnd; }
  76. ~TempDC() { ReleaseDC(m_hwnd, m_hdc); }
  77. operator HDC() {return m_hdc;};
  78. HDC m_hdc;
  79. HWND m_hwnd;
  80. };
  81. // *************************************************************************
  82. //  A Client connection involves two threads - the main one which sets up
  83. //  connections and processes window messages and inputs, and a 
  84. //  client-specific one which receives, decodes and draws output data 
  85. //  from the remote server.
  86. //  This first section contains bits which are generally called by the main
  87. //  program thread.
  88. // *************************************************************************
  89. ClientConnection::ClientConnection(VNCviewerApp *pApp)
  90. {
  91. Init(pApp);
  92. }
  93. ClientConnection::ClientConnection(VNCviewerApp *pApp, SOCKET sock) 
  94. {
  95. Init(pApp);
  96. m_sock = sock;
  97. struct sockaddr_in svraddr;
  98. int sasize = sizeof(svraddr);
  99. if (getpeername(sock, (struct sockaddr *) &svraddr, 
  100. &sasize) != SOCKET_ERROR) {
  101. _stprintf(m_host, _T("%d.%d.%d.%d"), 
  102. svraddr.sin_addr.S_un.S_un_b.s_b1, 
  103. svraddr.sin_addr.S_un.S_un_b.s_b2, 
  104. svraddr.sin_addr.S_un.S_un_b.s_b3, 
  105. svraddr.sin_addr.S_un.S_un_b.s_b4);
  106. m_port = svraddr.sin_port;
  107. } else {
  108. _tcscpy(m_host,_T("(unknown)"));
  109. m_port = 0;
  110. };
  111. }
  112. ClientConnection::ClientConnection(VNCviewerApp *pApp, LPTSTR host, int port)
  113. {
  114. Init(pApp);
  115. _tcsncpy(m_host, host, 256);
  116. m_port = port;
  117. }
  118. void ClientConnection::Init(VNCviewerApp *pApp)
  119. {
  120. m_hwnd = 0;
  121. m_desktopName = NULL;
  122. m_port = -1;
  123. m_netbuf = NULL;
  124. m_netbufsize = 0;
  125. m_hwndNextViewer = NULL;
  126. m_pApp = pApp;
  127. m_dormant = false;
  128. m_hBitmapDC = NULL;
  129. m_hBitmap = NULL;
  130. m_hPalette = NULL;
  131. // We take the initial conn options from the application defaults
  132. m_opts = m_pApp->m_options;
  133. m_sock = INVALID_SOCKET;
  134. m_bKillThread = false;
  135. m_threadStarted = true;
  136. m_running = false;
  137. m_pendingFormatChange = false;
  138. m_hScrollPos = 0; m_vScrollPos = 0;
  139. m_waitingOnEmulateTimer = false;
  140. m_emulatingMiddleButton = false;
  141. // Create a buffer for various network operations
  142. CheckBufferSize(INITIALNETBUFSIZE);
  143. m_pApp->RegisterConnection(this);
  144. UpdateWindow(m_hwnd);
  145. }
  146. // 
  147. // Run() creates the connection if necessary, does the initial negotiations
  148. // and then starts the thread running which does the output (update) processing.
  149. // If Run throws an Exception, the caller must delete the ClientConnection object.
  150. //
  151. void ClientConnection::Run()
  152. {
  153. // Get the host name and port if we haven't got it
  154. if (m_port == -1) 
  155. GetConnectDetails();
  156. // Connect if we're not already connected
  157. if (m_sock == INVALID_SOCKET) 
  158. Connect();
  159. SetSocketOptions();
  160. NegotiateProtocolVersion();
  161. Authenticate();
  162. // Set up widows etc 
  163. CreateDisplay();
  164. SendClientInit();
  165. ReadServerInit();
  166. CreateLocalFramebuffer();
  167. SetupPixelFormat();
  168. SetFormatAndEncodings();
  169. // This starts the worker thread.
  170. // The rest of the processing continues in run_undetached.
  171. start_undetached();
  172. }
  173. void ClientConnection::CreateDisplay() 
  174. {
  175. // Create the window
  176. WNDCLASS wndclass;
  177. wndclass.style = 0;
  178. wndclass.lpfnWndProc = ClientConnection::WndProc;
  179. wndclass.cbClsExtra = 0;
  180. wndclass.cbWndExtra = 0;
  181. wndclass.hInstance = m_pApp->m_instance;
  182. wndclass.hIcon = LoadIcon(m_pApp->m_instance, MAKEINTRESOURCE(IDI_MAINICON));
  183. wndclass.hCursor = LoadCursor(m_pApp->m_instance, MAKEINTRESOURCE(IDC_DOTCURSOR));
  184. wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  185.     wndclass.lpszMenuName = (const TCHAR *) NULL;
  186. wndclass.lpszClassName = VWR_WND_CLASS_NAME;
  187. RegisterClass(&wndclass);
  188. #ifdef _WIN32_WCE
  189. const DWORD winstyle = WS_VSCROLL | WS_HSCROLL | WS_CAPTION | WS_SYSMENU;
  190. #else
  191. const DWORD winstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | 
  192.   WS_MINIMIZEBOX | WS_THICKFRAME | WS_VSCROLL | WS_HSCROLL;
  193. #endif
  194. m_hwnd = CreateWindow(VWR_WND_CLASS_NAME,
  195.       _T("VNCviewer"),
  196.       winstyle,
  197.       CW_USEDEFAULT,
  198.       CW_USEDEFAULT,
  199.       CW_USEDEFAULT,       // x-size
  200.       CW_USEDEFAULT,       // y-size
  201.       NULL,                // Parent handle
  202.       NULL,                // Menu handle
  203.       m_pApp->m_instance,
  204.       NULL);
  205. ShowWindow(m_hwnd, SW_HIDE);
  206. // record which client created this window
  207. SetWindowLong(m_hwnd, GWL_USERDATA, (LONG) this);
  208. // Create a memory DC which we'll use for drawing to
  209. // the local framebuffer
  210. m_hBitmapDC = CreateCompatibleDC(NULL);
  211. // Set a suitable palette up
  212. if (GetDeviceCaps(m_hBitmapDC, RASTERCAPS) & RC_PALETTE) {
  213. log.Print(3, _T("Palette-based display - %d entries, %d reservedn"), 
  214. GetDeviceCaps(m_hBitmapDC, SIZEPALETTE), GetDeviceCaps(m_hBitmapDC, NUMRESERVED));
  215. BYTE buf[sizeof(LOGPALETTE)+216*sizeof(PALETTEENTRY)];
  216. LOGPALETTE *plp = (LOGPALETTE *) buf;
  217. int pepos = 0;
  218. for (int r = 5; r >= 0; r--) {
  219. for (int g = 5; g >= 0; g--) {
  220. for (int b = 5; b >= 0; b--) {
  221. plp->palPalEntry[pepos].peRed   = r * 255 / 5; 
  222. plp->palPalEntry[pepos].peGreen = g * 255 / 5;
  223. plp->palPalEntry[pepos].peBlue  = b * 255 / 5;
  224. plp->palPalEntry[pepos].peFlags  = NULL;
  225. pepos++;
  226. }
  227. }
  228. }
  229. plp->palVersion = 0x300;
  230. plp->palNumEntries = 216;
  231. m_hPalette = CreatePalette(plp);
  232. }
  233. // Add stuff to System menu
  234. HMENU hsysmenu = GetSystemMenu(m_hwnd, FALSE);
  235. if (!m_opts.m_restricted) {
  236. AppendMenu(hsysmenu, MF_STRING, IDC_OPTIONBUTTON, _T("Connection &options..."));
  237. AppendMenu(hsysmenu, MF_STRING, ID_CONN_ABOUT, _T("Connection &info"));
  238. AppendMenu(hsysmenu, MF_STRING, ID_REQUEST_REFRESH, _T("Request screen &refresh"));
  239. AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
  240. AppendMenu(hsysmenu, MF_STRING, ID_FULLSCREEN, _T("&Full screen"));
  241. AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
  242.   AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLALTDEL, _T("Send Ctl-Alt-Del"));
  243. AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLDOWN, _T("Ctrl Down"));
  244. AppendMenu(hsysmenu, MF_STRING, ID_CONN_CTLUP, _T("Ctrl Up"));
  245. AppendMenu(hsysmenu, MF_STRING, ID_CONN_ALTDOWN, _T("Alt Down"));
  246. AppendMenu(hsysmenu, MF_STRING, ID_CONN_ALTUP, _T("Alt Up"));
  247. AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
  248. AppendMenu(hsysmenu, MF_STRING, ID_NEWCONN, _T("Ne&w connection..."));
  249. }
  250.     AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
  251. AppendMenu(hsysmenu, MF_STRING, IDD_APP_ABOUT, _T("&About VNCviewer..."));
  252. if (m_opts.m_listening) {
  253. AppendMenu(hsysmenu, MF_SEPARATOR, NULL, NULL);
  254. AppendMenu(hsysmenu, MF_STRING, ID_CLOSEDAEMON, _T("Close listening &daemon"));
  255. }
  256. DrawMenuBar(m_hwnd);
  257. // Set up clipboard watching
  258. #ifndef _WIN32_WCE
  259. // We want to know when the clipboard changes, so
  260. // insert ourselves in the viewer chain. But doing
  261. // this will cause us to be notified immediately of
  262. // the current state.
  263. // We don't want to send that.
  264. m_initialClipboardSeen = false;
  265. m_hwndNextViewer = SetClipboardViewer(m_hwnd); 
  266. #endif
  267. }
  268. void ClientConnection::GetConnectDetails()
  269. {
  270. SessionDialog sessdlg(&m_opts);
  271. if (!sessdlg.DoDialog()) {
  272. throw QuietException("User Cancelled");
  273. }
  274. _tcsncpy(m_host, sessdlg.m_host, 256);
  275. m_port = sessdlg.m_port;
  276. }
  277. void ClientConnection::Connect()
  278. {
  279. struct sockaddr_in thataddr;
  280. int res;
  281. m_sock = socket(PF_INET, SOCK_STREAM, 0);
  282. if (m_sock == INVALID_SOCKET) throw WarningException(_T("Error creating socket"));
  283. int one = 1;
  284. // The host may be specified as a dotted address "a.b.c.d"
  285. // Try that first
  286. thataddr.sin_addr.s_addr = inet_addr(m_host);
  287. // If it wasn't one of those, do gethostbyname
  288. if (thataddr.sin_addr.s_addr == INADDR_NONE) {
  289. LPHOSTENT lphost;
  290. lphost = gethostbyname(m_host);
  291. if (lphost == NULL) { 
  292. throw WarningException("Failed to get server address.nr"
  293. "Did you type the host name correctly?"); 
  294. };
  295. thataddr.sin_addr.s_addr = ((LPIN_ADDR) lphost->h_addr)->s_addr;
  296. };
  297. thataddr.sin_family = AF_INET;
  298. thataddr.sin_port = htons(m_port);
  299. res = connect(m_sock, (LPSOCKADDR) &thataddr, sizeof(thataddr));
  300. if (res == SOCKET_ERROR) throw WarningException("Failed to connect to server");
  301. log.Print(0, _T("Connected to %s port %dn"), m_host, m_port);
  302. }
  303. void ClientConnection::SetSocketOptions() {
  304. // Disable Nagle's algorithm
  305. BOOL nodelayval = TRUE;
  306. if (setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, (const char *) &nodelayval, sizeof(BOOL)))
  307. throw WarningException("Error disabling Nagle's algorithm");
  308. }
  309. void ClientConnection::NegotiateProtocolVersion()
  310. {
  311. rfbProtocolVersionMsg pv;
  312.    /* if the connection is immediately closed, don't report anything, so
  313.        that pmw's monitor can make test connections */
  314.     try {
  315. ReadExact(pv, sz_rfbProtocolVersionMsg);
  316. } catch (Exception &c) {
  317. log.Print(0, _T("Error reading protocol version: %sn"), c);
  318. throw QuietException(c.m_info);
  319. }
  320.     pv[sz_rfbProtocolVersionMsg] = 0;
  321. // XXX This is a hack.  Under CE we just return to the server the
  322. // version number it gives us without parsing it.  
  323. // Too much hassle replacing sscanf for now. Fix this!
  324. #ifdef UNDER_CE
  325. m_majorVersion = rfbProtocolMajorVersion;
  326. m_minorVersion = rfbProtocolMinorVersion;
  327. #else
  328.     if (sscanf(pv,rfbProtocolVersionFormat,&m_majorVersion,&m_minorVersion) != 2) {
  329. throw WarningException(_T("Invalid protocol"));
  330.     }
  331.     log.Print(0, _T("RFB server supports protocol version %d.%dn"),
  332.     m_majorVersion,m_minorVersion);
  333.     if ((m_majorVersion == 3) && (m_minorVersion < 3)) {
  334.         /* if server is 3.2 we can't use the new authentication */
  335. log.Print(0, _T("Can't use IDEA authenticationn"));
  336.         /* This will be reported later if authentication is requested*/
  337.     } else {
  338.         /* any other server version, just tell the server what we want */
  339. m_majorVersion = rfbProtocolMajorVersion;
  340. m_minorVersion = rfbProtocolMinorVersion;
  341.     }
  342.     sprintf(pv,rfbProtocolVersionFormat,m_majorVersion,m_minorVersion);
  343. #endif
  344.     WriteExact(pv, sz_rfbProtocolVersionMsg);
  345. log.Print(0, _T("Connected to RFB server, using protocol version %d.%dn"),
  346. rfbProtocolMajorVersion, rfbProtocolMinorVersion);
  347. }
  348. void ClientConnection::Authenticate()
  349. {
  350. CARD32 authScheme, reasonLen, authResult;
  351.     CARD8 challenge[CHALLENGESIZE];
  352. ReadExact((char *)&authScheme, 4);
  353.     authScheme = Swap32IfLE(authScheme);
  354.     switch (authScheme) {
  355.     case rfbConnFailed:
  356. ReadExact((char *)&reasonLen, 4);
  357. reasonLen = Swap32IfLE(reasonLen);
  358. CheckBufferSize(reasonLen+1);
  359. ReadString(m_netbuf, reasonLen);
  360. log.Print(0, _T("RFB connection failed, reason: %sn"), m_netbuf);
  361. throw WarningException(m_netbuf);
  362.         break;
  363.     case rfbNoAuth:
  364. log.Print(0, _T("No authentication neededn"));
  365. break;
  366.     case rfbVncAuth:
  367. {
  368.             if ((m_majorVersion == 3) && (m_minorVersion < 3)) {
  369.                 /* if server is 3.2 we can't use the new authentication */
  370.                 log.Print(0, _T("Can't use IDEA authenticationn"));
  371.                 MessageBox(NULL, 
  372.                     _T("Sorry - this server uses an older authentication schemenr")
  373.                     _T("which is no longer supported."), 
  374.                     _T("Protocol Version error"), 
  375.                     MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST);
  376.                 throw WarningException("Can't use IDEA authentication any more!");
  377.             }
  378. ReadExact((char *)challenge, CHALLENGESIZE);
  379. AuthDialog ad;
  380. ad.DoDialog();
  381. char passwd[256];
  382. #ifndef UNDER_CE
  383. strcpy(passwd, ad.m_passwd);
  384. #else
  385.             int origlen = _tcslen(ad.m_passwd);
  386.             int newlen = WideCharToMultiByte(
  387.                 CP_ACP,    // code page
  388.                 0,         // performance and mapping flags
  389.                 ad.m_passwd, // address of wide-character string
  390.                 origlen,   // number of characters in string
  391.                 passwd,    // address of buffer for new string
  392.                 255,       // size of buffer
  393.                 NULL, NULL );
  394.  
  395.             passwd[newlen]= '';
  396. #endif
  397. if (strlen(passwd) == 0) {
  398. log.Print(0, _T("Password had zero lengthn"));
  399. throw WarningException("Empty password");
  400. }
  401. if (strlen(passwd) > 8) {
  402. passwd[8] = '';
  403. }
  404.     
  405. vncEncryptBytes(challenge, passwd);
  406. /* Lose the password from memory */
  407. for (int i=0; i< (int) strlen(passwd); i++) {
  408. passwd[i] = '';
  409. }
  410. WriteExact((char *) challenge, CHALLENGESIZE);
  411. ReadExact((char *) &authResult, 4);
  412. authResult = Swap32IfLE(authResult);
  413. switch (authResult) {
  414. case rfbVncAuthOK:
  415. log.Print(0, _T("VNC authentication succeededn"));
  416. break;
  417. case rfbVncAuthFailed:
  418. log.Print(0, _T("VNC authentication failed!"));
  419. throw WarningException("VNC authentication failed!");
  420. case rfbVncAuthTooMany:
  421. throw WarningException(
  422. "VNC authentication failed - too many tries!");
  423. default:
  424. log.Print(0, _T("Unknown VNC authentication result: %dn"),
  425. (int)authResult);
  426. throw ErrorException("Unknown VNC authentication result!");
  427. }
  428. break;
  429. }
  430. default:
  431. log.Print(0, _T("Unknown authentication scheme from RFB server: %dn"),
  432. (int)authScheme);
  433. throw ErrorException("Unknown authentication scheme!");
  434.     }
  435. }
  436. void ClientConnection::SendClientInit()
  437. {
  438.     rfbClientInitMsg ci;
  439. ci.shared = m_opts.m_Shared;
  440.     WriteExact((char *)&ci, sz_rfbClientInitMsg);
  441. }
  442. void ClientConnection::ReadServerInit()
  443. {
  444.     ReadExact((char *)&m_si, sz_rfbServerInitMsg);
  445.     m_si.framebufferWidth = Swap16IfLE(m_si.framebufferWidth);
  446.     m_si.framebufferHeight = Swap16IfLE(m_si.framebufferHeight);
  447.     m_si.format.redMax = Swap16IfLE(m_si.format.redMax);
  448.     m_si.format.greenMax = Swap16IfLE(m_si.format.greenMax);
  449.     m_si.format.blueMax = Swap16IfLE(m_si.format.blueMax);
  450.     m_si.nameLength = Swap32IfLE(m_si.nameLength);
  451.     m_desktopName = new TCHAR[m_si.nameLength + 2];
  452. #ifdef UNDER_CE
  453.     char *deskNameBuf = new char[m_si.nameLength + 2];
  454. ReadString(deskNameBuf, m_si.nameLength);
  455.     
  456. MultiByteToWideChar( CP_ACP,   MB_PRECOMPOSED, 
  457.      deskNameBuf, m_si.nameLength,
  458.      m_desktopName, m_si.nameLength+1);
  459.     delete deskNameBuf;
  460. #else
  461.     ReadString(m_desktopName, m_si.nameLength);
  462. #endif
  463.     
  464. SetWindowText(m_hwnd, m_desktopName);
  465. PaletteSelector p(m_hBitmapDC, m_hPalette);
  466. log.Print(0, _T("Desktop name "%s"n"),m_desktopName);
  467. log.Print(1, _T("Geometry %d x %d depth %dn"),
  468. m_si.framebufferWidth, m_si.framebufferHeight, m_si.format.depth );
  469. SetWindowText(m_hwnd, m_desktopName);
  470. // Find how large the desktop work area is
  471. RECT workrect;
  472. SystemParametersInfo(SPI_GETWORKAREA, 0, &workrect, 0);
  473. int workwidth = workrect.right -  workrect.left;
  474. int workheight = workrect.bottom - workrect.top;
  475. log.Print(2, _T("Screen work area is %d x %dn"), workwidth, workheight);
  476. // Size the window.
  477. // Let's find out how big a window would be needed to display the
  478. // whole desktop (assuming no scrollbars).
  479. RECT fullwinrect;
  480. SetRect(&fullwinrect, 0, 0, m_si.framebufferWidth, m_si.framebufferHeight);
  481. AdjustWindowRectEx(&fullwinrect, 
  482.    GetWindowLong(m_hwnd, GWL_STYLE) & ~WS_VSCROLL & ~WS_HSCROLL, 
  483.    FALSE, GetWindowLong(m_hwnd, GWL_EXSTYLE));
  484. m_fullwinwidth = fullwinrect.right - fullwinrect.left;
  485. m_fullwinheight = fullwinrect.bottom - fullwinrect.top;
  486. m_winwidth  = min(m_fullwinwidth,  workwidth);
  487. m_winheight = min(m_fullwinheight, workheight);
  488. SetWindowPos(m_hwnd, HWND_TOP,
  489. workrect.left + (workwidth-m_winwidth) / 2,
  490. workrect.top + (workheight-m_winheight) / 2,
  491. m_winwidth, m_winheight, SWP_SHOWWINDOW);
  492. SetForegroundWindow(m_hwnd);
  493. RealiseFullScreenMode();
  494. }
  495. // We keep a local copy of the whole screen.  This is not sctrictly necessary
  496. // for VNC, but makes scrolling & deiconifying much smoother.
  497. void ClientConnection::CreateLocalFramebuffer() {
  498. // We create a bitmap which has the same pixel characteristics as
  499. // the local display, in the hope that blitting will be faster.
  500. TempDC hdc(m_hwnd);
  501. m_hBitmap = ::CreateCompatibleBitmap(hdc, 
  502. m_si.framebufferWidth, 
  503. m_si.framebufferHeight);
  504. if (m_hBitmap == NULL)
  505. throw WarningException("Error creating local image of screen.");
  506. // Select this bitmap into the DC with an appropriate palette
  507. ObjectSelector b(m_hBitmapDC, m_hBitmap);
  508. PaletteSelector p(m_hBitmapDC, m_hPalette);
  509. // Put a "please wait" message up initially
  510.     RECT rect;
  511. SetRect(&rect, 0,0, m_si.framebufferWidth, m_si.framebufferHeight);
  512. COLORREF bgcol = RGB(0xcc, 0xcc, 0xcc);
  513. FillSolidRect(&rect, bgcol);
  514. COLORREF oldbgcol  = SetBkColor(  m_hBitmapDC, bgcol);
  515. COLORREF oldtxtcol = SetTextColor(m_hBitmapDC, RGB(0,0,64));
  516. rect.right = m_si.framebufferWidth / 2;
  517. rect.bottom = m_si.framebufferHeight / 2;
  518.     DrawText (m_hBitmapDC, _T("Please wait - initial screen loading"), -1, &rect,
  519.                     DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  520. SetBkColor(  m_hBitmapDC, oldbgcol);
  521. SetTextColor(m_hBitmapDC, oldtxtcol);
  522. InvalidateRect(m_hwnd, NULL, FALSE);
  523. }
  524. void ClientConnection::SetupPixelFormat() {
  525. // Have we requested a reduction to 8-bit?
  526.     if (m_opts.m_Use8Bit) {
  527.       
  528. log.Print(2, _T("Requesting 8-bit truecolourn"));  
  529. m_myFormat = vnc8bitFormat;
  530.     
  531. // We don't support colormaps so we'll ask the server to convert
  532.     } else if (!m_si.format.trueColour) {
  533.         
  534.         // We'll just request a standard 16-bit truecolor
  535.         log.Print(2, _T("Requesting 16-bit truecolourn"));
  536.         m_myFormat = vnc16bitFormat;
  537.         
  538.     } else {
  539. // Normally we just use the sever's format suggestion
  540. m_myFormat = m_si.format;
  541. // It's silly requesting more bits than our current display has, but
  542. // in fact it doesn't usually amount to much on the network.
  543. // Windows doesn't support 8-bit truecolour.
  544. // If our display is palette-based, we want more than 8 bit anyway,
  545. // unless we're going to start doing palette stuff at the server.
  546. // So the main use would be a 24-bit true-colour desktop being viewed
  547. // on a 16-bit true-colour display, and unless you have lots of images
  548. // and hence lots of raw-encoded stuff, the size of the pixel is not
  549. // going to make much difference.
  550. //   We therefore don't bother with any restrictions, but here's the
  551. // start of the code if we wanted to do it.
  552. if (false) {
  553. // Get a DC for the root window
  554. TempDC hrootdc(NULL);
  555. int localBitsPerPixel = GetDeviceCaps(hrootdc, BITSPIXEL);
  556. int localRasterCaps   = GetDeviceCaps(hrootdc, RASTERCAPS);
  557. log.Print(2, _T("Memory DC has depth of %d and %s pallete-based.n"), 
  558. localBitsPerPixel, (localRasterCaps & RC_PALETTE) ? "is" : "is not");
  559. // If we're using truecolor, and the server has more bits than we do
  560. if ( (localBitsPerPixel > m_myFormat.depth) && 
  561. ! (localRasterCaps & RC_PALETTE)) {
  562. m_myFormat.depth = localBitsPerPixel;
  563. // create a bitmap compatible with the current display
  564. // call GetDIBits twice to get the colour info.
  565. // set colour masks and shifts
  566. }
  567. }
  568. }
  569. // The endian will be set before sending
  570. }
  571. void ClientConnection::SetFormatAndEncodings()
  572. {
  573. // Set pixel format to myFormat
  574.     
  575. rfbSetPixelFormatMsg spf;
  576.     spf.type = rfbSetPixelFormat;
  577.     spf.format = m_myFormat;
  578.     spf.format.redMax = Swap16IfLE(spf.format.redMax);
  579.     spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
  580.     spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
  581. spf.format.bigEndian = 0;
  582.     WriteExact((char *)&spf, sz_rfbSetPixelFormatMsg);
  583.     // The number of bytes required to hold at least one pixel.
  584. m_minPixelBytes = (m_myFormat.bitsPerPixel + 7) >> 3;
  585. // Set encodings
  586.     char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
  587.     rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
  588.     CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]);
  589.     int len = 0;
  590.     se->type = rfbSetEncodings;
  591.     se->nEncodings = 0;
  592. // Put the preferred encoding first, and change it if the
  593. // preferred encoding is not actually usable.
  594. for (int i = LASTENCODING; i >= rfbEncodingRaw; i--)
  595. {
  596. if (m_opts.m_PreferredEncoding == i) {
  597. if (m_opts.m_UseEnc[i]) {
  598. encs[se->nEncodings++] = Swap32IfLE(i);
  599. } else {
  600. m_opts.m_PreferredEncoding--;
  601. }
  602. }
  603. }
  604. // Now we go through and put in all the other encodings in order.
  605. // We do rather assume that the most recent encoding is the most
  606. // desirable!
  607. for (i = LASTENCODING; i >= rfbEncodingRaw; i--)
  608. {
  609. if ( (m_opts.m_PreferredEncoding != i) &&
  610.  (m_opts.m_UseEnc[i]))
  611. {
  612. encs[se->nEncodings++] = Swap32IfLE(i);
  613. }
  614. }
  615.     len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
  616.     se->nEncodings = Swap16IfLE(se->nEncodings);
  617.     WriteExact((char *) buf, len);
  618. }
  619. // Closing down the connection.
  620. // Close the socket, kill the thread.
  621. void ClientConnection::KillThread()
  622. {
  623. m_bKillThread = true;
  624. m_running = false;
  625. if (m_sock != INVALID_SOCKET) {
  626. shutdown(m_sock, SD_BOTH);
  627. closesocket(m_sock);
  628. m_sock = INVALID_SOCKET;
  629. }
  630. }
  631. ClientConnection::~ClientConnection()
  632. {
  633. if (m_hwnd != 0)
  634. DestroyWindow(m_hwnd);
  635. if (m_sock != INVALID_SOCKET) {
  636. shutdown(m_sock, SD_BOTH);
  637. closesocket(m_sock);
  638. m_sock = INVALID_SOCKET;
  639. }
  640. if (m_desktopName != NULL) delete [] m_desktopName;
  641. delete [] m_netbuf;
  642. DeleteDC(m_hBitmapDC);
  643. if (m_hBitmap != NULL)
  644. DeleteObject(m_hBitmap);
  645. if (m_hBitmapDC != NULL)
  646. DeleteObject(m_hBitmapDC);
  647. if (m_hPalette != NULL)
  648. DeleteObject(m_hPalette);
  649. m_pApp->DeregisterConnection(this);
  650. }
  651. // You can specify a dx & dy outside the limits; the return value will
  652. // tell you whether it actually scrolled.
  653. bool ClientConnection::ScrollScreen(int dx, int dy) 
  654. {
  655. dx = max(dx, -m_hScrollPos);
  656. //dx = min(dx, m_hScrollMax-(m_cliwidth-1)-m_hScrollPos);
  657. dx = min(dx, m_hScrollMax-(m_cliwidth)-m_hScrollPos);
  658. dy = max(dy, -m_vScrollPos);
  659. //dy = min(dy, m_vScrollMax-(m_cliheight-1)-m_vScrollPos);
  660. dy = min(dy, m_vScrollMax-(m_cliheight)-m_vScrollPos);
  661. if (dx || dy) {
  662. m_hScrollPos += dx;
  663. m_vScrollPos += dy;
  664. RECT clirect;
  665. GetClientRect(m_hwnd, &clirect);
  666. ScrollWindowEx(m_hwnd, -dx, -dy, NULL, &clirect, NULL, NULL,  SW_INVALIDATE);
  667. UpdateScrollbars();
  668. UpdateWindow(m_hwnd);
  669. return true;
  670. }
  671. return false;
  672. }
  673. // Process windows messages
  674. LRESULT CALLBACK ClientConnection::WndProc(HWND hwnd, UINT iMsg, 
  675.    WPARAM wParam, LPARAM lParam) {
  676. // This is a static method, so we don't know which instantiation we're 
  677. // dealing with.  But we've stored a 'pseudo-this' in the window data.
  678. ClientConnection *_this = (ClientConnection *) GetWindowLong(hwnd, GWL_USERDATA);
  679. switch (iMsg) {
  680. case WM_CREATE:
  681. return 0;
  682. case WM_PAINT:
  683. _this->DoBlit();
  684. return 0;
  685. case WM_TIMER:
  686.   if (wParam == _this->m_emulate3ButtonsTimer)
  687.     {
  688.       _this->SubProcessPointerEvent( 
  689.     _this->m_emulateButtonPressedX,
  690.     _this->m_emulateButtonPressedY,
  691.     _this->m_emulateKeyFlags);
  692.       KillTimer(_this->m_hwnd, _this->m_emulate3ButtonsTimer);
  693.       _this->m_waitingOnEmulateTimer = false;
  694.     }
  695.   return 0;
  696.  
  697. case WM_LBUTTONDOWN:
  698. case WM_LBUTTONUP:
  699. case WM_MBUTTONDOWN:
  700. case WM_MBUTTONUP:
  701. case WM_RBUTTONDOWN:
  702. case WM_RBUTTONUP:
  703. case WM_MOUSEMOVE:
  704. {
  705. if (!_this->m_running) return 0;
  706. if (GetFocus() != hwnd) return 0;
  707. int x = LOWORD(lParam);
  708. int y = HIWORD(lParam);
  709. if (_this->InFullScreenMode()) {
  710. if (_this->BumpScroll(x,y))
  711. return 0;
  712. }
  713. if ( _this->m_opts.m_ViewOnly) return 0;
  714. _this->ProcessPointerEvent(x,y, wParam, iMsg);
  715. return 0;
  716. }
  717. case WM_KEYDOWN:
  718. case WM_KEYUP:
  719. case WM_SYSKEYDOWN:
  720. case WM_SYSKEYUP:
  721. {
  722. if (!_this->m_running) return 0;
  723. if ( _this->m_opts.m_ViewOnly) return 0;
  724.             _this->ProcessKeyEvent((int) wParam, (DWORD) lParam);
  725. return 0;
  726. }
  727. case WM_CHAR:
  728. case WM_SYSCHAR:
  729. #ifdef UNDER_CE
  730.         {
  731.             int key = wParam;
  732.             log.Print(4,_T("CHAR msg : %02xn"), key);
  733.             // Control keys which are in the Keymap table will already
  734.             // have been handled.
  735.             if (key == 0x0D  ||  // return
  736.                 key == 0x20 ||   // space
  737.                 key == 0x08)     // backspace
  738.                 return 0;
  739.             if (key < 32) key += 64;  // map ctrl-keys onto alphabet
  740.             if (key > 32 && key < 127) {
  741.                 _this->SendKeyEvent(wParam & 0xff, true);
  742.                 _this->SendKeyEvent(wParam & 0xff, false);
  743.             }
  744.             return 0;
  745.         }
  746. #endif
  747. case WM_DEADCHAR:
  748. case WM_SYSDEADCHAR:
  749.   return 0;
  750. case WM_SETFOCUS:
  751. if (_this->InFullScreenMode())
  752. SetWindowPos(hwnd, HWND_TOPMOST, 0,0,100,100, SWP_NOMOVE | SWP_NOSIZE);
  753. return 0;
  754. // Cacnel modifiers when we lose focus
  755. case WM_KILLFOCUS:
  756. {
  757. if (!_this->m_running) return 0;
  758. if (_this->InFullScreenMode()) {
  759. // We must top being topmost, but we want to choose our
  760. // position carefully.
  761. HWND foreground = GetForegroundWindow();
  762. HWND hwndafter = NULL;
  763. if ((foreground == NULL) || 
  764. (GetWindowLong(foreground, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
  765. hwndafter = HWND_NOTOPMOST;
  766. } else {
  767. hwndafter = GetNextWindow(foreground, GW_HWNDNEXT); 
  768. }
  769. SetWindowPos(hwnd, hwndafter, 0,0,100,100, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  770. }
  771. log.Print(6, _T("Losing focus - cancelling modifiersn"));
  772. _this->SendKeyEvent(XK_Alt_L,     false);
  773. _this->SendKeyEvent(XK_Control_L, false);
  774. _this->SendKeyEvent(XK_Shift_L,   false);
  775. _this->SendKeyEvent(XK_Alt_R,     false);
  776. _this->SendKeyEvent(XK_Control_R, false);
  777. _this->SendKeyEvent(XK_Shift_R,   false);
  778. return 0;
  779. }
  780. case WM_CLOSE:
  781. {
  782. // Close the worker thread as well
  783. _this->KillThread();
  784. DestroyWindow(hwnd);
  785. return 0;
  786. }
  787. case WM_DESTROY:
  788. {
  789. #ifndef UNDER_CE
  790. // Remove us from the clipboard viewer chain
  791. BOOL res = ChangeClipboardChain( hwnd, _this->m_hwndNextViewer);
  792. #endif
  793. if (_this->m_waitingOnEmulateTimer)
  794.   {
  795.     KillTimer(_this->m_hwnd, _this->m_emulate3ButtonsTimer);
  796.     _this->m_waitingOnEmulateTimer = false;
  797.   }
  798.   
  799. _this->m_hwnd = 0;
  800. // We are currently in the main thread.
  801. // The worker thread should be about to finish if
  802. // it hasn't already. Wait for it.
  803. try {
  804. void *p;
  805. _this->join(&p);  // After joining, _this is no longer valid
  806. } catch (omni_thread_invalid& e) {
  807. // The thread probably hasn't been started yet,
  808. }
  809. return 0;
  810. }
  811. case WM_SIZE:
  812. {
  813. // Calculate window dimensions
  814. RECT rect;
  815. GetWindowRect(hwnd, &rect);
  816. // update these for the record
  817. _this->m_winwidth = rect.right - rect.left;
  818. _this->m_winheight = rect.bottom - rect.top;
  819. // If the current window size would be large enough to hold the
  820. // whole screen without scrollbars, or if we're full-screen,
  821. // we turn them off.  Under CE, the scroll bars are unchangeable.
  822. #ifndef UNDER_CE
  823. if (_this->InFullScreenMode() ||
  824. _this->m_winwidth  >= _this->m_fullwinwidth  &&
  825. _this->m_winheight >= _this->m_fullwinheight ) {
  826. ShowScrollBar(hwnd, SB_HORZ, FALSE);
  827. ShowScrollBar(hwnd, SB_VERT, FALSE);
  828. } else {
  829. ShowScrollBar(hwnd, SB_HORZ, TRUE);
  830. ShowScrollBar(hwnd, SB_VERT, TRUE);
  831. }
  832. #endif
  833.             // Update these for the record
  834. // And consider that in full-screen mode the window
  835. // is actually bigger than the remote screen.
  836. GetClientRect(hwnd, &rect);
  837. _this->m_cliwidth = min( rect.right - rect.left, 
  838.  _this->m_si.framebufferWidth );
  839. _this->m_cliheight = min( rect.bottom - rect.top,
  840.  _this->m_si.framebufferHeight );
  841. _this->m_hScrollMax = _this->m_si.framebufferWidth;
  842. _this->m_vScrollMax = _this->m_si.framebufferHeight;
  843.             
  844. int newhpos, newvpos;
  845. newhpos = max(0, min(_this->m_hScrollPos, 
  846.  _this->m_hScrollMax - max(_this->m_cliwidth, 0)));
  847. newvpos = max(0, min(_this->m_vScrollPos, 
  848.                  _this->m_vScrollMax - max(_this->m_cliheight, 0)));
  849. ScrollWindowEx(hwnd, _this->m_hScrollPos-newhpos, _this->m_vScrollPos-newvpos,
  850. NULL, &rect, NULL, NULL,  SW_INVALIDATE);
  851. _this->m_hScrollPos = newhpos;
  852. _this->m_vScrollPos = newvpos;
  853.             _this->UpdateScrollbars();
  854. return 0;
  855. }
  856. case WM_HSCROLL:
  857. {
  858. int dx = 0;
  859. int pos = HIWORD(wParam);
  860. switch (LOWORD(wParam)) {
  861. case SB_LINEUP:
  862. dx = -2; break;
  863. case SB_LINEDOWN:
  864. dx = 2; break;
  865. case SB_PAGEUP:
  866. dx = _this->m_cliwidth * -1/4; break;
  867. case SB_PAGEDOWN:
  868. dx = _this->m_cliwidth * 1/4; break;
  869. case SB_THUMBPOSITION:
  870. dx = pos - _this->m_hScrollPos;
  871. case SB_THUMBTRACK:
  872. dx = pos - _this->m_hScrollPos;
  873. }
  874. _this->ScrollScreen(dx,0);
  875. return 0;
  876. }
  877. case WM_VSCROLL:
  878. {
  879. int dy = 0;
  880. int pos = HIWORD(wParam);
  881. switch (LOWORD(wParam)) {
  882. case SB_LINEUP:
  883. dy = -2; break;
  884. case SB_LINEDOWN:
  885. dy = 2; break;
  886. case SB_PAGEUP:
  887. dy = _this->m_cliheight * -1/4; break;
  888. case SB_PAGEDOWN:
  889. dy = _this->m_cliheight * 1/4; break;
  890. case SB_THUMBPOSITION:
  891. dy = pos - _this->m_vScrollPos;
  892. case SB_THUMBTRACK:
  893. dy = pos - _this->m_vScrollPos;
  894. }
  895. _this->ScrollScreen(0,dy);
  896. return 0;
  897. }
  898.     case WM_QUERYNEWPALETTE:
  899.         {
  900. TempDC hDC(hwnd);
  901. // Select and realize hPalette
  902. PaletteSelector p(hDC, _this->m_hPalette);
  903. InvalidateRect(hwnd, NULL, FALSE);
  904. UpdateWindow(hwnd);
  905. return TRUE;
  906.         }
  907. case WM_PALETTECHANGED:
  908. // If this application did not change the palette, select
  909. // and realize this application's palette
  910. if ((HWND) wParam != hwnd)
  911. {
  912. // Need the window's DC for SelectPalette/RealizePalette
  913. TempDC hDC(hwnd);
  914. PaletteSelector p(hDC, _this->m_hPalette);
  915. // When updating the colors for an inactive window,
  916. // UpdateColors can be called because it is faster than
  917. // redrawing the client area (even though the results are
  918. // not as good)
  919. #ifndef UNDER_CE
  920. UpdateColors(hDC);
  921. #else
  922. InvalidateRect(hwnd, NULL, FALSE);
  923. UpdateWindow(hwnd);
  924. #endif
  925. }
  926.         break;
  927. #ifndef UNDER_CE
  928. case WM_SIZING:
  929. {
  930. // Don't allow sizing larger than framebuffer
  931. RECT *lprc = (LPRECT) lParam;
  932. switch (wParam) {
  933. case WMSZ_RIGHT: 
  934. case WMSZ_TOPRIGHT:
  935. case WMSZ_BOTTOMRIGHT:
  936. lprc->right = min(lprc->right, lprc->left + _this->m_fullwinwidth+1);
  937. break;
  938. case WMSZ_LEFT:
  939. case WMSZ_TOPLEFT:
  940. case WMSZ_BOTTOMLEFT:
  941. lprc->left = max(lprc->left, lprc->right - _this->m_fullwinwidth);
  942. break;
  943. }
  944. switch (wParam) {
  945. case WMSZ_TOP:
  946. case WMSZ_TOPLEFT:
  947. case WMSZ_TOPRIGHT:
  948. lprc->top = max(lprc->top, lprc->bottom - _this->m_fullwinheight);
  949. break;
  950. case WMSZ_BOTTOM:
  951. case WMSZ_BOTTOMLEFT:
  952. case WMSZ_BOTTOMRIGHT:
  953. lprc->bottom = min(lprc->bottom, lprc->top + _this->m_fullwinheight);
  954. break;
  955. }
  956. return 0;
  957. }
  958. case WM_SETCURSOR:
  959. {
  960. // if we have the focus, let the cursor change as normal
  961. if (GetFocus() == hwnd) 
  962. break;
  963. // if not, set to default system cursor
  964. SetCursor( LoadCursor(NULL, IDC_ARROW));
  965. return 0;
  966. }
  967. case WM_SYSCOMMAND:
  968. {
  969. switch (LOWORD(wParam)) {
  970. case SC_MINIMIZE:
  971. _this->SetDormant(true);
  972. break;
  973. case SC_RESTORE:
  974. _this->SetDormant(false);
  975. break;
  976.             case ID_NEWCONN:
  977. _this->m_pApp->NewConnection();
  978. return 0;
  979. case IDC_OPTIONBUTTON: 
  980. if (_this->m_opts.DoDialog(true)) {
  981. _this->m_pendingFormatChange = true;
  982. // Make the window correspond to the requested state
  983. _this->RealiseFullScreenMode();
  984. };
  985. return 0;
  986. case IDD_APP_ABOUT:
  987. ShowAboutBox();
  988. return 0;
  989. case ID_CONN_ABOUT:
  990. _this->ShowConnInfo();
  991. return 0;
  992. case ID_FULLSCREEN: 
  993. // Toggle full screen mode
  994. _this->SetFullScreenMode(!_this->InFullScreenMode());
  995. return 0;
  996. case ID_REQUEST_REFRESH: 
  997. // Request a full-screen update
  998. _this->SendFullFramebufferUpdateRequest();
  999. return 0;
  1000. case ID_CONN_CTLALTDEL:
  1001. _this->SendKeyEvent(XK_Control_L, true);
  1002. _this->SendKeyEvent(XK_Alt_L,     true);
  1003. _this->SendKeyEvent(XK_Delete,    true);
  1004. _this->SendKeyEvent(XK_Delete,    false);
  1005. _this->SendKeyEvent(XK_Alt_L,     false);
  1006. _this->SendKeyEvent(XK_Control_L, false);
  1007. return 0;
  1008.             case ID_CONN_CTLDOWN:
  1009.                 _this->SendKeyEvent(XK_Control_L, true);
  1010.                 return 0;
  1011.             case ID_CONN_CTLUP:
  1012. _this->SendKeyEvent(XK_Control_L, false);
  1013. return 0;
  1014. case ID_CONN_ALTDOWN:
  1015.                 _this->SendKeyEvent(XK_Alt_L, true);
  1016. return 0;
  1017. case ID_CONN_ALTUP:
  1018.                 _this->SendKeyEvent(XK_Alt_L, false);
  1019.                 return 0;
  1020. case ID_CLOSEDAEMON:
  1021. if (MessageBox(NULL, _T("Are you sure you want to exit?"), 
  1022. _T("Closing VNCviewer"), 
  1023. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
  1024. PostQuitMessage(0);
  1025. return 0;
  1026. }
  1027. break;
  1028. }
  1029. case WM_DRAWCLIPBOARD:
  1030. _this->ProcessLocalClipboardChange();
  1031. return 0;
  1032. case WM_CHANGECBCHAIN:
  1033. {
  1034. // The clipboard chain is changing
  1035. HWND hWndRemove = (HWND) wParam;     // handle of window being removed 
  1036. HWND hWndNext = (HWND) lParam;       // handle of next window in chain 
  1037. // If next window is closing, update our pointer.
  1038. if (hWndRemove == _this->m_hwndNextViewer)  
  1039. _this->m_hwndNextViewer = hWndNext;  
  1040. // Otherwise, pass the message to the next link.  
  1041. else if (_this->m_hwndNextViewer != NULL) 
  1042. ::SendMessage(_this->m_hwndNextViewer, WM_CHANGECBCHAIN, 
  1043. (WPARAM) hWndRemove,  (LPARAM) hWndNext );  
  1044. return 0;
  1045. }
  1046. #endif
  1047. }
  1048. return DefWindowProc(hwnd, iMsg, wParam, lParam);
  1049. // We know about an unused variable here.
  1050. #pragma warning(disable : 4101)
  1051. }
  1052. #pragma warning(default : 4101)
  1053. // ProcessPointerEvent handles the delicate case of emulating 3 buttons
  1054. // on a two button mouse, then passes events off to SubProcessPointerEvent.
  1055. void
  1056. ClientConnection::ProcessPointerEvent(int x, int y, DWORD keyflags, UINT msg) 
  1057. {
  1058. if (m_opts.m_Emul3Buttons) {
  1059. // XXX To be done:
  1060. // If this is a left or right press, the user may be 
  1061. // about to press the other button to emulate a middle press.
  1062. // We need to start a timer, and if it expires without any
  1063. // further presses, then we send the button press. 
  1064. // If a press of the other button, or any release, comes in
  1065. // before timer has expired, we cancel timer & take different action.
  1066.   if (m_waitingOnEmulateTimer)
  1067.     {
  1068.       if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP ||
  1069.   abs(x - m_emulateButtonPressedX) > m_opts.m_Emul3Fuzz ||
  1070.   abs(y - m_emulateButtonPressedY) > m_opts.m_Emul3Fuzz)
  1071. {
  1072.   // if button released or we moved too far then cancel.
  1073.   // First let the remote know where the button was down
  1074.   SubProcessPointerEvent(
  1075.  m_emulateButtonPressedX, 
  1076.  m_emulateButtonPressedY, 
  1077.  m_emulateKeyFlags);
  1078.   // Then tell it where we are now
  1079.   SubProcessPointerEvent(x, y, keyflags);
  1080. }
  1081.       else if (
  1082.        (msg == WM_LBUTTONDOWN && (m_emulateKeyFlags & MK_RBUTTON))
  1083.        || (msg == WM_RBUTTONDOWN && (m_emulateKeyFlags & MK_LBUTTON)))
  1084. {
  1085.   // Triggered an emulate; remove left and right buttons, put
  1086.   // in middle one.
  1087.   DWORD emulatekeys = keyflags & ~(MK_LBUTTON|MK_RBUTTON);
  1088.   emulatekeys |= MK_MBUTTON;
  1089.   SubProcessPointerEvent(x, y, emulatekeys);
  1090.   
  1091.   m_emulatingMiddleButton = true;
  1092. }
  1093.       else
  1094. {
  1095.   // handle movement normally & don't kill timer.
  1096.   // just remove the pressed button from the mask.
  1097.   DWORD keymask = m_emulateKeyFlags & (MK_LBUTTON|MK_RBUTTON);
  1098.   DWORD emulatekeys = keyflags & ~keymask;
  1099.   SubProcessPointerEvent(x, y, emulatekeys);
  1100.   return;
  1101. }
  1102.       
  1103.       // if we reached here, we don't need the timer anymore.
  1104.       KillTimer(m_hwnd, m_emulate3ButtonsTimer);
  1105.       m_waitingOnEmulateTimer = false;
  1106.     }
  1107.   else if (m_emulatingMiddleButton)
  1108.     {
  1109.       if ((keyflags & MK_LBUTTON) == 0 && (keyflags & MK_RBUTTON) == 0)
  1110. {
  1111.   // We finish emulation only when both buttons come back up.
  1112.   m_emulatingMiddleButton = false;
  1113.   SubProcessPointerEvent(x, y, keyflags);
  1114. }
  1115.       else
  1116. {
  1117.   // keep emulating.
  1118.   DWORD emulatekeys = keyflags & ~(MK_LBUTTON|MK_RBUTTON);
  1119.   emulatekeys |= MK_MBUTTON;
  1120.   SubProcessPointerEvent(x, y, emulatekeys);
  1121. }
  1122.     }
  1123.   else
  1124.     {
  1125.       // Start considering emulation if we've pressed a button
  1126.       // and the other isn't pressed.
  1127.       if ( (msg == WM_LBUTTONDOWN && !(keyflags & MK_RBUTTON))
  1128.    || (msg == WM_RBUTTONDOWN && !(keyflags & MK_LBUTTON)))
  1129. {
  1130.   // Start timer for emulation.
  1131.   m_emulate3ButtonsTimer = 
  1132.     SetTimer(
  1133.      m_hwnd, 
  1134.      IDT_EMULATE3BUTTONSTIMER, 
  1135.      m_opts.m_Emul3Timeout, 
  1136.      NULL);
  1137.   
  1138.   if (!m_emulate3ButtonsTimer)
  1139.     {
  1140.       log.Print(0, _T("Failed to create timer for emulating 3 buttons"));
  1141.       PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  1142.       return;
  1143.     }
  1144.   
  1145.   m_waitingOnEmulateTimer = true;
  1146.   
  1147.   // Note that we don't send the event here; we're batching it for
  1148.   // later.
  1149.   m_emulateKeyFlags = keyflags;
  1150.   m_emulateButtonPressedX = x;
  1151.   m_emulateButtonPressedY = y;
  1152. }
  1153.       else
  1154. {
  1155.   // just send event noramlly
  1156.   SubProcessPointerEvent(x, y, keyflags);
  1157. }
  1158.     }
  1159.   }
  1160. else
  1161.   {
  1162.     SubProcessPointerEvent(x, y, keyflags);
  1163.   }
  1164. }
  1165. // SubProcessPointerEvent takes windows positions and flags and converts 
  1166. // them into VNC ones.
  1167. inline void 
  1168. ClientConnection::SubProcessPointerEvent(int x, int y, DWORD keyflags) 
  1169. {
  1170.   int mask;
  1171.   
  1172.   if (m_opts.m_SwapMouse) {
  1173. mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) |
  1174. ((keyflags & MK_MBUTTON) ? rfbButton3Mask : 0) |
  1175. ((keyflags & MK_RBUTTON) ? rfbButton2Mask : 0)  );
  1176. } else {
  1177. mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) |
  1178. ((keyflags & MK_MBUTTON) ? rfbButton2Mask : 0) |
  1179. ((keyflags & MK_RBUTTON) ? rfbButton3Mask : 0)  );
  1180. }
  1181. try {
  1182. SendPointerEvent(x + m_hScrollPos, y + m_vScrollPos, mask);
  1183. } catch (Exception &e) {
  1184. e.Report();
  1185. PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  1186. }
  1187. }
  1188. //
  1189. // SendPointerEvent.
  1190. //
  1191. inline void
  1192. ClientConnection::SendPointerEvent(int x, int y, int buttonMask)
  1193. {
  1194.     rfbPointerEventMsg pe;
  1195.     pe.type = rfbPointerEvent;
  1196.     pe.buttonMask = buttonMask;
  1197.     if (x < 0) x = 0;
  1198.     if (y < 0) y = 0;
  1199.     pe.x = Swap16IfLE(x);
  1200.     pe.y = Swap16IfLE(y);
  1201. WriteExact((char *)&pe, sz_rfbPointerEventMsg);
  1202. }
  1203. //
  1204. // ProcessKeyEvent
  1205. //
  1206. // Normally a single Windows key event will map onto a single RFB
  1207. // key message, but this is not always the case.  Much of the stuff
  1208. // here is to handle AltGr (=Ctrl-Alt) on international keyboards.
  1209. // Example cases:
  1210. //
  1211. //    We want Ctrl-F to be sent as:
  1212. //      Ctrl-Down, F-Down, F-Up, Ctrl-Up.
  1213. //    because there is no keysym for ctrl-f, and because the ctrl
  1214. //    will already have been sent by the time we get the F.
  1215. //
  1216. //    On German keyboards, @ is produced using AltGr-Q, which is
  1217. //    Ctrl-Alt-Q.  But @ is a valid keysym in its own right, and when
  1218. //    a German user types this combination, he doesn't mean Ctrl-@.
  1219. //    So for this we will send, in total:
  1220. //
  1221. //      Ctrl-Down, Alt-Down,   
  1222. //                 (when we get the AltGr pressed)
  1223. //
  1224. //      Alt-Up, Ctrl-Up, @-Down, Ctrl-Down, Alt-Down 
  1225. //                 (when we discover that this is @ being pressed)
  1226. //
  1227. //      Alt-Up, Ctrl-Up, @-Up, Ctrl-Down, Alt-Down
  1228. //                 (when we discover that this is @ being released)
  1229. //
  1230. //      Alt-Up, Ctrl-Up
  1231. //                 (when the AltGr is released)
  1232. inline void ClientConnection::ProcessKeyEvent(int virtkey, DWORD keyData)
  1233. {
  1234.     bool down = ((keyData & 0x80000000l) == 0);
  1235.     // if virtkey found in mapping table, send X equivalent
  1236.     // else
  1237.     //   try to convert directly to ascii
  1238.     //   if result is in range supported by X keysyms,
  1239.     //      raise any modifiers, send it, then restore mods
  1240.     //   else
  1241.     //      calculate what the ascii would be without mods
  1242.     //      send that
  1243. #ifdef _DEBUG
  1244. #ifdef UNDER_CE
  1245. char *keyname="";
  1246. #else
  1247.     char keyname[32];
  1248.     if (GetKeyNameText(  keyData,keyname, 31)) {
  1249.         log.Print(4, _T("Process key: %s (keyData %04x): "), keyname, keyData);
  1250.     };
  1251. #endif
  1252. #endif
  1253. try {
  1254. KeyActionSpec kas = m_keymap.PCtoX(virtkey, keyData);    
  1255. if (kas.releaseModifiers & KEYMAP_LCONTROL) {
  1256. SendKeyEvent(XK_Control_L, false );
  1257. log.Print(5, _T("fake L Ctrl raisedn"));
  1258. }
  1259. if (kas.releaseModifiers & KEYMAP_LALT) {
  1260. SendKeyEvent(XK_Alt_L, false );
  1261. log.Print(5, _T("fake L Alt raisedn"));
  1262. }
  1263. if (kas.releaseModifiers & KEYMAP_RCONTROL) {
  1264. SendKeyEvent(XK_Control_R, false );
  1265. log.Print(5, _T("fake R Ctrl raisedn"));
  1266. }
  1267. if (kas.releaseModifiers & KEYMAP_RALT) {
  1268. SendKeyEvent(XK_Alt_R, false );
  1269. log.Print(5, _T("fake R Alt raisedn"));
  1270. }
  1271. for (int i = 0; kas.keycodes[i] != XK_VoidSymbol && i < MaxKeysPerKey; i++) {
  1272. SendKeyEvent(kas.keycodes[i], down );
  1273. log.Print(4, _T("Sent keysym %04x (%s)n"), 
  1274. kas.keycodes[i], down ? _T("press") : _T("release"));
  1275. }
  1276. if (kas.releaseModifiers & KEYMAP_RALT) {
  1277. SendKeyEvent(XK_Alt_R, true );
  1278. log.Print(5, _T("fake R Alt pressedn"));
  1279. }
  1280. if (kas.releaseModifiers & KEYMAP_RCONTROL) {
  1281. SendKeyEvent(XK_Control_R, true );
  1282. log.Print(5, _T("fake R Ctrl pressedn"));
  1283. }
  1284. if (kas.releaseModifiers & KEYMAP_LALT) {
  1285. SendKeyEvent(XK_Alt_L, false );
  1286. log.Print(5, _T("fake L Alt pressedn"));
  1287. }
  1288. if (kas.releaseModifiers & KEYMAP_LCONTROL) {
  1289. SendKeyEvent(XK_Control_L, false );
  1290. log.Print(5, _T("fake L Ctrl pressedn"));
  1291. }
  1292. } catch (Exception &e) {
  1293. e.Report();
  1294. PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  1295. }
  1296. }
  1297. //
  1298. // SendKeyEvent
  1299. //
  1300. inline void
  1301. ClientConnection::SendKeyEvent(CARD32 key, bool down)
  1302. {
  1303.     rfbKeyEventMsg ke;
  1304.     ke.type = rfbKeyEvent;
  1305.     ke.down = down ? 1 : 0;
  1306.     ke.key = Swap32IfLE(key);
  1307.     WriteExact((char *)&ke, sz_rfbKeyEventMsg);
  1308.     log.Print(6, _T("SendKeyEvent: key = x%04x status = %sn"), key, 
  1309.         down ? _T("down") : _T("up"));
  1310. }
  1311. #ifndef UNDER_CE
  1312. //
  1313. // SendClientCutText
  1314. //
  1315. void ClientConnection::SendClientCutText(char *str, int len)
  1316. {
  1317.     rfbClientCutTextMsg cct;
  1318.     cct.type = rfbClientCutText;
  1319.     cct.length = Swap32IfLE(len);
  1320.     WriteExact((char *)&cct, sz_rfbClientCutTextMsg);
  1321. WriteExact(str, len);
  1322. log.Print(6, _T("Sent %d bytes of clipboardn"), len);
  1323. }
  1324. #endif
  1325. // Copy any updated areas from the bitmap onto the screen.
  1326. inline void ClientConnection::DoBlit() 
  1327. {
  1328. if (m_hBitmap == NULL) return;
  1329. if (!m_running) return;
  1330. omni_mutex_lock l(m_bitmapdcMutex);
  1331. PAINTSTRUCT ps;
  1332. HDC hdc = BeginPaint(m_hwnd, &ps);
  1333. HPALETTE hOldPal = NULL;
  1334. // Select and realize hPalette
  1335. PaletteSelector p(hdc, m_hPalette);
  1336. ObjectSelector b(m_hBitmapDC, m_hBitmap);
  1337. if (m_opts.m_delay) {
  1338. // Display the area to be updated for debugging purposes
  1339. COLORREF oldbgcol = SetBkColor(hdc, RGB(0,0,0));
  1340. ::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &ps.rcPaint, NULL, 0, NULL);
  1341. SetBkColor(hdc,oldbgcol);
  1342. ::Sleep(m_pApp->m_options.m_delay);
  1343. }
  1344. if (!BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, 
  1345. ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top, 
  1346. m_hBitmapDC, ps.rcPaint.left+m_hScrollPos, ps.rcPaint.top+m_vScrollPos, SRCCOPY)) 
  1347. {
  1348. log.Print(0, _T("Blit error %dn"), GetLastError());
  1349. throw ErrorException("Error in blit!n");
  1350. }
  1351. EndPaint(m_hwnd, &ps);
  1352. }
  1353. inline void ClientConnection::UpdateScrollbars() 
  1354. {
  1355. // We don't update the actual scrollbar info in full-screen mode
  1356. // because it causes them to flicker.
  1357. bool setInfo = !InFullScreenMode();
  1358. SCROLLINFO scri;
  1359. scri.cbSize = sizeof(scri);
  1360. scri.fMask = SIF_ALL;
  1361. scri.nMin = 0;
  1362. scri.nMax = m_hScrollMax;     
  1363. scri.nPage= m_cliwidth;
  1364. scri.nPos = m_hScrollPos; 
  1365. if (setInfo) 
  1366. SetScrollInfo(m_hwnd, SB_HORZ, &scri, TRUE);
  1367. scri.cbSize = sizeof(scri);
  1368. scri.fMask = SIF_ALL;
  1369. scri.nMin = 0;
  1370. scri.nMax = m_vScrollMax;     
  1371. scri.nPage= m_cliheight;
  1372. scri.nPos = m_vScrollPos; 
  1373. if (setInfo) 
  1374. SetScrollInfo(m_hwnd, SB_VERT, &scri, TRUE);
  1375. }
  1376. void ClientConnection::ShowConnInfo()
  1377. {
  1378. TCHAR buf[2048];
  1379. #ifndef UNDER_CE
  1380. char kbdname[9];
  1381. GetKeyboardLayoutName(kbdname);
  1382. #else
  1383. TCHAR *kbdname = _T("(n/a)");
  1384. #endif
  1385. _stprintf(
  1386. buf,
  1387. _T("Connected to: %s:nr")
  1388. _T("Host: %s port: %dnrnr")
  1389. _T("Desktop geometry: %d x %d x %dnr")
  1390. _T("Using depth: %dnr")
  1391. _T("Current protocol version: %d.%dnrnr")
  1392. _T("Current keyboard name: %snr"),
  1393. m_desktopName, m_host, m_port,
  1394. m_si.framebufferWidth, m_si.framebufferHeight, m_si.format.depth,
  1395. m_myFormat.depth,
  1396. m_majorVersion, m_minorVersion,
  1397. kbdname);
  1398. MessageBox(NULL, buf, _T("VNC connection info"), MB_ICONINFORMATION | MB_OK);
  1399. }
  1400. // ********************************************************************
  1401. //  Methods after this point are generally called by the worker thread.
  1402. //  They finish the initialisation, then chiefly read data from the server.
  1403. // ********************************************************************
  1404. void* ClientConnection::run_undetached(void* arg) {
  1405. log.Print(9,_T("Update-processing thread startedn"));
  1406. m_threadStarted = true;
  1407. try {
  1408. UpdateWindow(m_hwnd);
  1409. SendFullFramebufferUpdateRequest();
  1410. m_running = true;
  1411. while (!m_bKillThread) {
  1412. // Look at the type of the message, but leave it in the buffer 
  1413. CARD8 msgType;
  1414. {
  1415.   omni_mutex_lock l(m_readMutex);
  1416.   int bytes = recv(m_sock, (char *) &msgType, 1, MSG_PEEK);
  1417.   if (bytes == 0) {
  1418.     log.Print(0, _T("Socket closedn") );
  1419.     throw QuietException(_T("SocketClosed"));
  1420.   }
  1421.   if (bytes < 0) {
  1422.     log.Print(3, _T("Socket error reading message: %dn"), WSAGetLastError() );
  1423.     throw WarningException("Error while waiting for server message");
  1424.   }
  1425. }
  1426. switch (msgType) {
  1427. case rfbFramebufferUpdate:
  1428. ReadScreenUpdate();
  1429. if (m_pendingFormatChange) {
  1430. log.Print(3, _T("Requesting new pixel formatn") );
  1431. rfbPixelFormat oldFormat = m_myFormat;
  1432. SetupPixelFormat();
  1433. SetFormatAndEncodings();
  1434. m_pendingFormatChange = false;
  1435. // If the pixel format has changed, request whole screen
  1436. if (memcmp(&m_myFormat, &oldFormat, sizeof(rfbPixelFormat)) != 0) {
  1437. SendFullFramebufferUpdateRequest();
  1438. } else {
  1439. SendIncrementalFramebufferUpdateRequest();
  1440. }
  1441. } else {
  1442. if (!m_dormant)
  1443. SendIncrementalFramebufferUpdateRequest();
  1444. }
  1445. break;
  1446. case rfbSetColourMapEntries:
  1447.         log.Print(3, _T("rfbSetColourMapEntries read but not supportedn") );
  1448. throw WarningException("Unhandled SetColormap message type received!n");
  1449. break;
  1450. case rfbBell:
  1451. ReadBell();
  1452. break;
  1453. case rfbServerCutText:
  1454. ReadServerCutText();
  1455. break;
  1456. default:
  1457.                 log.Print(3, _T("Unknown message type x%02xn"), msgType );
  1458. throw WarningException("Unhandled message type received!n");
  1459. }
  1460. }
  1461.         
  1462.         log.Print(4, _T("Update-processing thread finishingn") );
  1463. } catch (WarningException) {
  1464. PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  1465. } catch (QuietException &e) {
  1466. e.Report();
  1467. PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  1468. return this;
  1469. }
  1470. //
  1471. // Requesting screen updates from the server
  1472. //
  1473. inline void
  1474. ClientConnection::SendFramebufferUpdateRequest(int x, int y, int w, int h, bool incremental)
  1475. {
  1476.     rfbFramebufferUpdateRequestMsg fur;
  1477.     fur.type = rfbFramebufferUpdateRequest;
  1478.     fur.incremental = incremental ? 1 : 0;
  1479.     fur.x = Swap16IfLE(x);
  1480.     fur.y = Swap16IfLE(y);
  1481.     fur.w = Swap16IfLE(w);
  1482.     fur.h = Swap16IfLE(h);
  1483. log.Print(10, _T("Request %s updaten"), incremental ? _T("incremental") : _T("full"));
  1484.     WriteExact((char *)&fur, sz_rfbFramebufferUpdateRequestMsg);
  1485. }
  1486. inline void ClientConnection::SendIncrementalFramebufferUpdateRequest()
  1487. {
  1488.     SendFramebufferUpdateRequest(0, 0, m_si.framebufferWidth,
  1489. m_si.framebufferHeight, true);
  1490. }
  1491. inline void ClientConnection::SendFullFramebufferUpdateRequest()
  1492. {
  1493.     SendFramebufferUpdateRequest(0, 0, m_si.framebufferWidth,
  1494. m_si.framebufferHeight, false);
  1495. }
  1496. // A ScreenUpdate message has been received
  1497. void ClientConnection::ReadScreenUpdate() {
  1498. rfbFramebufferUpdateMsg sut;
  1499. ReadExact((char *) &sut, sz_rfbFramebufferUpdateMsg);
  1500.     sut.nRects = Swap16IfLE(sut.nRects);
  1501. if (sut.nRects == 0) return;
  1502. // No other threads can use DC
  1503. omni_mutex_lock l(m_bitmapdcMutex);
  1504. ObjectSelector b(m_hBitmapDC, m_hBitmap);
  1505. PaletteSelector p(m_hBitmapDC, m_hPalette);
  1506. // Find the bounding region of this batch of updates
  1507. HRGN fullregion = NULL;
  1508. for (UINT i=0; i < sut.nRects; i++) {
  1509. rfbFramebufferUpdateRectHeader surh;
  1510. ReadExact((char *) &surh, sz_rfbFramebufferUpdateRectHeader);
  1511. surh.r.x = Swap16IfLE(surh.r.x);
  1512. surh.r.y = Swap16IfLE(surh.r.y);
  1513. surh.r.w = Swap16IfLE(surh.r.w);
  1514. surh.r.h = Swap16IfLE(surh.r.h);
  1515. surh.encoding = Swap32IfLE(surh.encoding);
  1516. switch (surh.encoding) {
  1517. case rfbEncodingRaw:
  1518. ReadRawRect(&surh);
  1519. break;
  1520. case rfbEncodingCopyRect:
  1521. ReadCopyRect(&surh);
  1522. break;
  1523. case rfbEncodingRRE:
  1524. ReadRRERect(&surh);
  1525. break;
  1526. case rfbEncodingCoRRE:
  1527. ReadCoRRERect(&surh);
  1528. break;
  1529. case rfbEncodingHextile:
  1530. ReadHextileRect(&surh);
  1531. break;
  1532. default:
  1533. log.Print(0, _T("Unknown encoding %d - not supported!n"), surh.encoding);
  1534. break;
  1535. }
  1536. RECT rect;
  1537. rect.left   = surh.r.x - m_hScrollPos;
  1538. rect.top    = surh.r.y - m_vScrollPos;
  1539. rect.right  = rect.left + surh.r.w;
  1540. rect.bottom = rect.top  + surh.r.h;
  1541. InvalidateRect(m_hwnd, &rect, FALSE);
  1542. }
  1543. }
  1544. void ClientConnection::SetDormant(bool newstate)
  1545. {
  1546. log.Print(5, _T("%s dormant moden"), newstate ? _T("Entering") : _T("Leaving"));
  1547. m_dormant = newstate;
  1548. if (!m_dormant)
  1549. SendIncrementalFramebufferUpdateRequest();
  1550. }
  1551. // The server has copied some text to the clipboard - put it 
  1552. // in the local clipboard too.
  1553. void ClientConnection::ReadServerCutText() {
  1554. rfbServerCutTextMsg sctm;
  1555. log.Print(6, _T("Read remote clipboard changen"));
  1556. ReadExact((char *) &sctm, sz_rfbServerCutTextMsg);
  1557. int len = Swap32IfLE(sctm.length);
  1558. CheckBufferSize(len);
  1559. if (len == 0) {
  1560. m_netbuf[0] = '';
  1561. } else {
  1562. ReadString(m_netbuf, len);
  1563. }
  1564. UpdateLocalClipboard(m_netbuf, len);
  1565. }
  1566. void ClientConnection::ReadBell() {
  1567. rfbBellMsg bm;
  1568. ReadExact((char *) &bm, sz_rfbBellMsg);
  1569. #ifdef UNDER_CE
  1570. MessageBeep( MB_OK );
  1571. #else
  1572. if (! ::PlaySound("VNCViewerBell", NULL, 
  1573. SND_APPLICATION | SND_ALIAS | SND_NODEFAULT | SND_ASYNC) ) {
  1574. ::Beep(440, 125);
  1575. }
  1576. #endif
  1577. if (m_opts.m_DeiconifyOnBell) {
  1578. if (IsIconic(m_hwnd)) {
  1579. SetDormant(false);
  1580. ShowWindow(m_hwnd, SW_SHOWNORMAL);
  1581. }
  1582. }
  1583. log.Print(6, _T("Bell!n"));
  1584. }
  1585. // General utilities -------------------------------------------------
  1586. // Reads the number of bytes specified into the buffer given
  1587. inline void ClientConnection::ReadExact(char *inbuf, int wanted)
  1588. {
  1589. omni_mutex_lock l(m_readMutex);
  1590. // omni_mutex_lock l2(sockMutex);
  1591. int offset = 0;
  1592.     log.Print(10, _T("  reading %d bytesn"), wanted);
  1593. while (wanted > 0) {
  1594. int bytes = recv(m_sock, inbuf+offset, wanted, 0);
  1595. if (bytes == 0) throw WarningException("Connection closed.");
  1596. if (bytes == SOCKET_ERROR) {
  1597. int err = ::GetLastError();
  1598. log.Print(1, _T("Socket error while reading %dn"), err);
  1599. m_running = false;
  1600. throw WarningException("ReadExact: Socket error while reading.");
  1601. }
  1602. wanted -= bytes;
  1603. offset += bytes;
  1604. }
  1605. }
  1606. // Read the number of bytes and return them zero terminated in the buffer 
  1607. inline void ClientConnection::ReadString(char *buf, int length)
  1608. {
  1609. if (length > 0)
  1610. ReadExact(buf, length);
  1611. buf[length] = '';
  1612.     log.Print(10, _T("Read a %d-byte stringn"), length);
  1613. }
  1614. // Sends the number of bytes specified from the buffer
  1615. inline void ClientConnection::WriteExact(char *buf, int bytes)
  1616. {
  1617. if (bytes == 0) return;
  1618. omni_mutex_lock l(m_writeMutex);
  1619. log.Print(10, _T("  writing %d bytesn"), bytes);
  1620. int i = 0;
  1621.     int j;
  1622.     while (i < bytes) {
  1623. j = send(m_sock, buf+i, bytes-i, 0);
  1624. if (j == SOCKET_ERROR || j==0) {
  1625. int err = ::GetLastError();
  1626. log.Print(1, _T("Socket error %dn"), err);
  1627. m_running = false;
  1628. throw WarningException("WriteExact: Socket error while writing.");
  1629. }
  1630. i += j;
  1631.     }
  1632. }
  1633. // Makes sure netbuf is at least as big as the specified size.
  1634. // Note that netbuf itself may change as a result of this call.
  1635. // Throws an exception on failure.
  1636. inline void ClientConnection::CheckBufferSize(int bufsize)
  1637. {
  1638. if (m_netbufsize > bufsize) return;
  1639. omni_mutex_lock l(m_bufferMutex);
  1640. char *newbuf = new char[bufsize+256];;
  1641. if (newbuf == NULL) {
  1642. throw ErrorException("Insufficient memory to allocate network buffer.");
  1643. }
  1644. // Only if we're successful...
  1645. if (m_netbuf != NULL)
  1646. delete [] m_netbuf;
  1647. m_netbuf = newbuf;
  1648. m_netbufsize=bufsize + 256;
  1649. log.Print(4, _T("bufsize expanded to %dn"), m_netbufsize);
  1650. }