⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vncdesktop.cpp

📁 realvnc是一个非常流行的远程控制程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//  Copyright (C) 2002-2003 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.// vncDesktop implementation// System headers#include <assert.h>#include "stdhdrs.h"// Custom headers#include <omnithread.h>#include "WinVNC.h"#include "VNCHooks\VNCHooks.h"#include "vncServer.h"#include "vncKeymap.h"#include "rfbRegion.h"#include "rfbRect.h"#include "vncDesktop.h"#include "vncService.h"// Constantsconst UINT RFB_SCREEN_UPDATE = RegisterWindowMessage("WinVNC.Update.DrawRect");const UINT RFB_COPYRECT_UPDATE = RegisterWindowMessage("WinVNC.Update.CopyRect");const UINT RFB_MOUSE_UPDATE = RegisterWindowMessage("WinVNC.Update.Mouse");const char szDesktopSink[] = "WinVNC desktop sink";// The desktop handler thread// This handles the messages posted by RFBLib to the vncDesktop windowclass vncDesktopThread : public omni_thread{public:	vncDesktopThread() {m_returnsig = NULL;};protected:	~vncDesktopThread() {if (m_returnsig != NULL) delete m_returnsig;};public:	virtual BOOL Init(vncDesktop *desktop, vncServer *server);	virtual void *run_undetached(void *arg);	virtual void ReturnVal(BOOL result);	void PollWindow(rfb::Region2D &rgn, HWND hwnd);protected:	vncServer *m_server;	vncDesktop *m_desktop;	omni_mutex m_returnLock;	omni_condition *m_returnsig;	BOOL m_return;	BOOL m_returnset;};BOOLvncDesktopThread::Init(vncDesktop *desktop, vncServer *server){	// Save the server pointer	m_server = server;	m_desktop = desktop;	m_returnset = FALSE;	m_returnsig = new omni_condition(&m_returnLock);	// Start the thread	start_undetached();	// Wait for the thread to let us know if it failed to init	{	omni_mutex_lock l(m_returnLock);		while (!m_returnset)		{			m_returnsig->wait();		}	}	return m_return;}voidvncDesktopThread::ReturnVal(BOOL result){	omni_mutex_lock l(m_returnLock);	m_returnset = TRUE;	m_return = result;	m_returnsig->signal();}voidvncDesktopThread::PollWindow(rfb::Region2D &rgn, HWND hwnd){	// Are we set to low-load polling?	if (m_server->PollOnEventOnly())	{		// Yes, so only poll if the remote user has done something		if (!m_server->RemoteEventReceived()) {			return;		}	}	// Does the client want us to poll only console windows?	if (m_desktop->m_server->PollConsoleOnly())	{		char classname[20];		// Yes, so check that this is a console window...		if (GetClassName(hwnd, classname, sizeof(classname))) {			if ((strcmp(classname, "tty") != 0) &&				(strcmp(classname, "ConsoleWindowClass") != 0)) {				return;			}		}	}	RECT rect;	// Get the rectangle	if (GetWindowRect(hwnd, &rect)) {		rfb::Rect wrect = rfb::Rect(rect).intersect(m_desktop->m_bmrect);		if (!wrect.is_empty()) {			rgn = rgn.union_(rfb::Region2D(wrect));		}	}}void *vncDesktopThread::run_undetached(void *arg){	// Save the thread's "home" desktop, under NT (no effect under 9x)	HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());	// Attempt to initialise and return success or failure	if (!m_desktop->Startup())	{		vncService::SelectHDESK(home_desktop);		ReturnVal(FALSE);		return NULL;	}  // Grab the initial display contents  // *** m_desktop->m_buffer.GrabRegion(m_desktop->m_bmrect);  // *** m_desktop->m_buffer.Clear(m_desktop->m_bmrect);	// Succeeded to initialise ok	ReturnVal(TRUE);	// START PROCESSING DESKTOP MESSAGES	// We set a flag inside the desktop handler here, to indicate it's now safe	// to handle clipboard messages	m_desktop->SetClipboardActive(TRUE);	// All changes in the state of the display are stored in a local	// UpdateTracker object, and are flushed to the vncServer whenever	// client updates are about to be triggered	rfb::SimpleUpdateTracker clipped_updates;	rfb::ClippedUpdateTracker updates(clipped_updates, m_desktop->m_bmrect);	clipped_updates.enable_copyrect(true);	// Incoming update messages are collated into a single region cache	// The region cache areas are checked for changes before an update	// is triggered, and the changed areas are passed to the UpdateTracker	rfb::Region2D rgncache = m_desktop->m_bmrect;	// The previous cursor position is stored, to allow us to erase the	// old instance whenever it moves.	rfb::Point oldcursorpos;	// Set the hook thread to a high priority	// *** set_priority(omni_thread::PRIORITY_HIGH);	BOOL idle_skip = TRUE;	ULONG idle_skip_count = 0;	MSG msg;	while (TRUE)	{		if (!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {			//			// - MESSAGE QUEUE EMPTY			// Whenever the message queue becomes empty, we check to see whether			// there are updates to be passed to clients.			if (idle_skip) {				idle_skip = FALSE;				if (idle_skip_count++ < 4) {					Sleep(5);					continue;				}			}			idle_skip_count = 0;			// Clear the triggered flag			m_desktop->m_update_triggered = FALSE;			//			// CHECK SCREEN FORMAT			// First, we must check that the screen hasnt changed too much.			if (m_desktop->m_displaychanged || !vncService::InputDesktopSelected())			{				rfbServerInitMsg oldscrinfo = m_desktop->m_scrinfo;				m_desktop->m_displaychanged = FALSE;				// Attempt to close the old hooks				if (!m_desktop->Shutdown())				{					m_server->KillAuthClients();					break;				}				// Now attempt to re-install them!				if (!m_desktop->Startup())				{					m_server->KillAuthClients();					break;				}				// Check that the screen info hasn't changed				vnclog.Print(LL_INTINFO, VNCLOG("SCR: old screen format %dx%dx%d\n"),					oldscrinfo.framebufferWidth,					oldscrinfo.framebufferHeight,					oldscrinfo.format.bitsPerPixel);				vnclog.Print(LL_INTINFO, VNCLOG("SCR: new screen format %dx%dx%d\n"),					m_desktop->m_scrinfo.framebufferWidth,					m_desktop->m_scrinfo.framebufferHeight,					m_desktop->m_scrinfo.format.bitsPerPixel);				if ((m_desktop->m_scrinfo.framebufferWidth != oldscrinfo.framebufferWidth) ||					(m_desktop->m_scrinfo.framebufferHeight != oldscrinfo.framebufferHeight))				{					m_server->KillAuthClients();					break;				} else if (memcmp(&m_desktop->m_scrinfo.format, &oldscrinfo.format, sizeof(rfbPixelFormat)) != 0)				{					m_server->UpdateLocalFormat();				}				// Adjust the UpdateTracker clip region				updates.set_clip_region(m_desktop->m_bmrect);				// Add a full screen update to all the clients				rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_bmrect));				m_server->UpdatePalette();			}				//			// CALCULATE CHANGES			//			if (m_desktop->m_server->UpdateWanted())			{				// POLL PROBLEM AREAS				// We add specific areas of the screen to the region cache,				// causing them to be fetched for processing.				if (m_desktop->m_server->PollFullScreen())				{					rfb::Rect rect = m_desktop->m_qtrscreen;					rect = rect.translate(rfb::Point(0, m_desktop->m_pollingcycle * m_desktop->m_qtrscreen.br.y));					rgncache = rgncache.union_(rfb::Region2D(rect));					m_desktop->m_pollingcycle = (m_desktop->m_pollingcycle + 1) % 4;				}				if (m_desktop->m_server->PollForeground())				{					// Get the window rectangle for the currently selected window					HWND hwnd = GetForegroundWindow();					if (hwnd != NULL)						PollWindow(rgncache, hwnd);				}				if (m_desktop->m_server->PollUnderCursor())				{					// Find the mouse position					POINT mousepos;					if (GetCursorPos(&mousepos))					{						// Find the window under the mouse						HWND hwnd = WindowFromPoint(mousepos);						if (hwnd != NULL)							PollWindow(rgncache, hwnd);					}				}				// PROCESS THE MOUSE POINTER				// Some of the hard work is done in clients, some here				// This code fetches the desktop under the old pointer position				// but the client is responsible for actually encoding and sending				// it when required.				// This code also renders the pointer and saves the rendered position				// Clients include this when rendering updates.				// The code is complicated in this way because we wish to avoid 				// rendering parts of the screen the mouse moved through between				// client updates, since in practice they will probably not have changed.				// Re-render the mouse's old location if it's moved				BOOL cursormoved = FALSE;				POINT cursorpos;				if (GetCursorPos(&cursorpos) && 					((cursorpos.x != oldcursorpos.x) ||					(cursorpos.y != oldcursorpos.y))) {					cursormoved = TRUE;					oldcursorpos = rfb::Point(cursorpos);				}				if (cursormoved) {					if (!m_desktop->m_cursorpos.is_empty())						rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos));				}				{					// Prevent any clients from accessing the Buffer					omni_mutex_lock l(m_desktop->m_update_lock);					// CHECK FOR COPYRECTS					// This actually just checks where the Foreground window is					m_desktop->CalcCopyRects(updates);					// GRAB THE DISPLAY					// Fetch data from the display to our display cache.					m_desktop->m_buffer.GrabRegion(rgncache);				  // Render the mouse				  m_desktop->m_buffer.GrabMouse();					if (cursormoved) {						// Inform clients that it has moved						m_desktop->m_server->UpdateMouse();						// Get the buffer to fetch the pointer bitmap						if (!m_desktop->m_cursorpos.is_empty())							rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos));					}					// SCAN THE CHANGED REGION FOR ACTUAL CHANGES					// The hooks return hints as to areas that may have changed.					// We check the suggested areas, and just send the ones that					// have actually changed.					// Note that we deliberately don't check the copyrect destination					// here, to reduce the overhead & the likelihood of corrupting the					// backbuffer contents.					rfb::Region2D checkrgn = rgncache.subtract(clipped_updates.get_copied_region());					rgncache = clipped_updates.get_copied_region();					rfb::Region2D changedrgn;					m_desktop->m_buffer.CheckRegion(changedrgn, checkrgn);					// FLUSH UPDATES TO CLIENTS					// Add the bits that have really changed to their update regions					// Note that the cursor is NOT included - they must do that					// themselves, for the reasons above.					// This call implicitly kicks clients to update themselves					updates.add_changed(changedrgn);					clipped_updates.get_update(m_server->GetUpdateTracker());				}				// Clear the update tracker and region cache				clipped_updates.clear();			}			// Now wait for more messages to be queued			if (!WaitMessage()) {				vnclog.Print(LL_INTERR, VNCLOG("WaitMessage() failed\n"));				break;			}		} else if (msg.message == RFB_SCREEN_UPDATE) {			// Process an incoming update event			// An area of the screen has changed			rfb::Rect rect;			rect.tl = rfb::Point((SHORT)LOWORD(msg.wParam), (SHORT)HIWORD(msg.wParam));			rect.br = rfb::Point((SHORT)LOWORD(msg.lParam), (SHORT)HIWORD(msg.lParam));			rect = rect.intersect(m_desktop->m_bmrect);			if (!rect.is_empty()) {				rgncache = rgncache.union_(rfb::Region2D(rect));			}			idle_skip = TRUE;		} else if (msg.message == RFB_MOUSE_UPDATE) {			// Process an incoming mouse event			// Save the cursor ID			m_desktop->SetCursor((HCURSOR) msg.wParam);			idle_skip = TRUE;		} else if (msg.message == WM_QUIT) {			break;		} else {			// Process any other messages normally			DispatchMessage(&msg);			idle_skip = TRUE;		}	}	m_desktop->SetClipboardActive(FALSE);		vnclog.Print(LL_INTINFO, VNCLOG("quitting desktop server thread\n"));	// Clear all the hooks and close windows, etc.	m_desktop->Shutdown();	// Clear the shift modifier keys, now that there are no remote clients	vncKeymap::ClearShiftKeys();	// Switch back into our home desktop, under NT (no effect under 9x)	vncService::SelectHDESK(home_desktop);	return NULL;}// ImplementationvncDesktop::vncDesktop(){	m_thread = NULL;	m_hwnd = NULL;	m_timerid = 0;	m_hnextviewer = NULL;	m_hcursor = NULL;	m_displaychanged = FALSE;	m_update_triggered = FALSE;	m_hrootdc = NULL;	m_hmemdc = NULL;	m_membitmap = NULL;	m_initialClipBoardSeen = FALSE;	m_foreground_window = NULL;	// Vars for Will Dean's DIBsection patch	m_DIBbits = NULL;	m_formatmunged = FALSE;	m_clipboard_active = FALSE;	m_pollingcycle = 0;}vncDesktop::~vncDesktop(){	vnclog.Print(LL_INTINFO, VNCLOG("killing screen server\n"));	// If we created a thread then here we delete it	// The thread itself does most of the cleanup	if(m_thread != NULL)	{		// Post a close message to quit our message handler thread		PostMessage(Window(), WM_QUIT, 0, 0);		// Join with the desktop handler thread		void *returnval;		m_thread->join(&returnval);		m_thread = NULL;	}	// Let's call Shutdown just in case something went wrong...	Shutdown();}// Tell the desktop hooks to grab & update a particular rectanglevoidvncDesktop::QueueRect(const rfb::Rect &rect){	ULONG vwParam = MAKELONG(rect.tl.x, rect.tl.y);	ULONG vlParam = MAKELONG(rect.br.x, rect.br.y);	PostMessage(Window(), RFB_SCREEN_UPDATE, vwParam, vlParam);}	// Kick the desktop hooks to perform an updatevoidvncDesktop::TriggerUpdate(){	// Note that we should really lock the update lock here,	// but there are periodic timer updates anyway, so	// we don't actually need to.  Something to think about.	if (!m_update_triggered) {		m_update_triggered = TRUE;		PostMessage(Window(), WM_TIMER, 0, 0);	}}// Routine to startup and install all the hooks and stuffBOOLvncDesktop::Startup(){	// Initialise the Desktop object	// ***	// vncService::SelectInputWinStation();	KillScreenSaver();	if (!InitDesktop())		return FALSE;	if (!InitBitmap())		return FALSE;	if (!ThunkBitmapInfo())		return FALSE;	EnableOptimisedBlits();	if (!SetPixFormat())		return FALSE;  if (!SetPixShifts())		return FALSE;	if (!SetPalette())		return FALSE;	if (!InitWindow())		return FALSE;	// Add the system hook	if (!SetHooks(		GetCurrentThreadId(),		RFB_SCREEN_UPDATE,		RFB_COPYRECT_UPDATE,		RFB_MOUSE_UPDATE		))	{		vnclog.Print(LL_INTERR, VNCLOG("failed to set system hooks\n"));		// Switch on full screen polling, so they can see something, at least...

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -