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

📄 vncdesktop.cpp

📁 teamviewer source code vc++
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//  Copyright (C) 2006 Teamviewer GmbH. All Rights Reserved.
//  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 TeamViewer.
//
//  TeamViewer 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 TeamViewer is not available from the place 
//  whence you received this file, check http://www.teamviewer.com
//  for information on obtaining it.

// vncDesktop implementation

// System headers
#include "stdhdrs.h"

// Custom headers
#include "VNCHooks\VNCHooks.h"
#include "vncServer.h"
#include "vncKeymap.h"
#include "vncDesktop.h"
#include "vncService.h"
#include "vncOSVersion.h"
#include "TextChat.h" // sf@2002
#include "vncdesktopthread.h"

// Constants
const UINT RFB_SCREEN_UPDATE = RegisterWindowMessage("TeamViewer.Update.DrawRect");
const UINT RFB_COPYRECT_UPDATE = RegisterWindowMessage("TeamViewer.Update.CopyRect");
const UINT RFB_MOUSE_UPDATE = RegisterWindowMessage("TeamViewer.Update.Mouse");
const UINT RFB_KEY = RegisterWindowMessage("TeamViewer.Keypressed");

const char szDesktopSink[] = "WinVNC desktop sink";

extern int counterwatch;//global var for driverwatch
bool g_Desktop_running;
extern bool g_DesktopThread_running;
extern bool g_update_triggered;
DWORD WINAPI BlackWindow(LPVOID lpParam);

// OS Version Info from vncService
extern DWORD	g_platform_id;
extern DWORD	g_version_major;
extern DWORD	g_version_minor;


//
// // Modif sf@2002 - v1.1.0 - Optimization
//
// Here we try to speed up the Poll FullScreen function.
// Instead of adding the entire Rect to cached region,
// we divide it in 32/32 pixels blocks and only scan the top-left
// pixel of each block.
// If a pixel has changed, we find the smallest window containing this pixel
// and add the Window rect to the cached region
//
// This function is supposed to be a good compromise between
// speed and efficiency.
// The accuracy has been greatly improved and it now detects very
// small changes on screen that are not detected by the Hooks.
// This new accuracy is obtained by shifting the detection grid 
// in diagonale (the function works with several grids that are tested 
// alternatively). There's probably still room for improvements...
//
// NB: Changes generated by applications using hardware acceleration 
// won't be detected (In order to see a video played on the server using
// Media Player, the vncviewer user must desactivate "Hardware accelation"
// in the Media Player options). 
// 
// 
//
void
vncDesktop::FastDetectChanges(rfb::Region2D &rgn, rfb::Rect &rect, int nZone, bool fTurbo)
{
	RGBPixelList::iterator iPixelColor;
	RGBPixelList *pThePixelGrid;
	bool fInitGrid = false;
	bool fIncCycle = false;
	// For more accuracy, we could use 24 or even 16
	const int PIXEL_BLOCK_SIZE  = 32; // Pixels Grid definition
	const int GRID_OFFSET = 4;  // Pixels Grid shifting during cycle (in pixels)
								// The number of grid per zone is PIXEL_BLOCK_SIZE/GRID_OFFSET (must be int !)
	int x, y;
	int xo, yo;
	// WindowsList lWList;
	WindowsList::iterator iWindow;

	// In turbo mode, we clear the list of windows at each iteration -> Lot of updates because 
	//  the same windows can be detected several times during a complete cycle
	// (To avoid this pb, we must update all the grids at the same coordinate when a pixel of 
	// one grid has changed -> later)
	// Otherwise we only clear it each time the Grid cycle loops -> Less updates, less framerate,
	// less CPU, less bandwidth
	if (fTurbo)
		m_lWList.clear();
	else if (m_nGridCycle == 0)
		m_lWList.clear();

	// Create all the Grids (for all the 5 zones (4 quarter screens + 1 full screen)
	// Actually, the quarter screens are not utilized in v1.1.0 but it does not
	// generate any overhead neither additionnal memory consumption (see below)
	if (m_lGridsList.empty())
	{
		for (int i = 0; i < (5 * PIXEL_BLOCK_SIZE / GRID_OFFSET); i++)
		{
			RGBPixelList *pList = new RGBPixelList;
			if (pList != NULL)
			{
				m_lGridsList.push_back(pList);
			}
		}
	    vnclog.Print(LL_INTINFO, VNCLOG("%d PixelsGrids created"), 5 * PIXEL_BLOCK_SIZE / GRID_OFFSET);
	}

	// We test one zone at a time 
	// vnclog.Print(LL_INTINFO, VNCLOG("### Polling Grid %d - SubGrid %d"), nZone, m_nGridCycle); 
	GridsList::iterator iGrid;
	int nIndex = 0;
	int nGridPos = (nZone * PIXEL_BLOCK_SIZE / GRID_OFFSET) + m_nGridCycle;

	iGrid = m_lGridsList.begin();
	while (nIndex != nGridPos)
	{
		if(iGrid == m_lGridsList.end())		// shouldn't happen, but better check paranoid
		{
			vnclog.Print(LL_INTERR, VNCLOG("m_lGridsList.end()"));
			return;
		}
		iGrid++;
		nIndex++;
	}

	iPixelColor = ((RGBPixelList*)(*iGrid))->begin();
	pThePixelGrid = (RGBPixelList*) *iGrid;

	if (nZone == 0 || nZone == 4)
	{
	   // vnclog.Print(LL_INTINFO, VNCLOG("### IncCycle Please !")); 
	   fIncCycle = true;
	}

	if (pThePixelGrid->empty())
	{
		// vnclog.Print(LL_INTINFO, VNCLOG("### PixelsGrid Init"));
		fInitGrid = true;
	}

	int nOffset = GRID_OFFSET * m_nGridCycle;

	// Vista with DWM: read operations on the desktop DC (e.g. GetPixel(m_hrootDC,...) are _very_ slow because 
	//				   of high overhead of synchronization (see http://blogs.msdn.com/greg_schechter/archive/2006/05/02/588934.aspx)
	//				   Therefore it's better to make just one call and copy the complete screen to a memory
	//				   bitmap to get the pixel data
	HDC grabDC = NULL;
	HBITMAP membmp = NULL;
	HBITMAP oldbmp = NULL;
	bool vista = (g_platform_id==VER_PLATFORM_WIN32_NT && g_version_major>=6);
	if(vista)					
	{
		grabDC = CreateCompatibleDC(m_hrootdc);
		membmp = CreateCompatibleBitmap(m_hrootdc, rect.br.x, rect.br.y);
		oldbmp = (HBITMAP)SelectObject(grabDC, membmp);
		BitBlt(grabDC, 0, 0, rect.br.x, rect.br.y, m_hrootdc, 0, 0, SRCCOPY);
	}
	else
		grabDC = m_hrootdc;

	// We walk our way through the Grids
	for (y = rect.tl.y; y < rect.br.y; y += PIXEL_BLOCK_SIZE)
	{
		yo = y + nOffset;

		for (x = rect.tl.x; x < rect.br.x; x += PIXEL_BLOCK_SIZE)
		{
			xo = x + nOffset;

			// If init list
			if (fInitGrid)
			{
			   COLORREF PixelColor = GetPixel(grabDC, xo, yo);
			   pThePixelGrid->push_back(PixelColor);
			   // vnclog.Print(LL_INTINFO, VNCLOG("### PixelsGrid Init : Pixel xo=%d - yo=%d - C=%ld"), xo, yo, (long)PixelColor); 
			   continue;
			}

			// Read the pixel's color on the screen
			COLORREF PixelColor = GetPixel(grabDC, xo, yo);

			// If the pixel has changed
			if (*iPixelColor != PixelColor)
			{
				// Save the new Pixel in the list
				*iPixelColor = PixelColor;

				// Then find the corresponding Window
				POINT point;
				RECT rect;

				point.x = xo;
				point.y = yo;

				// Find the smallest, non-hidden, non-disabled Window containing this pixel
				// REM: We don't use ChildWindowFromPoint because we don't want of hidden windows
				HWND hDeskWnd = GetDesktopWindow();
				HWND hwnd = WindowFromPoint(point);
				bool fAlready = false;

				// Look if we've already detected this window
				for (iWindow = m_lWList.begin(); iWindow != m_lWList.end(); iWindow++)
				{
					if (*iWindow == hwnd)
					{
						fAlready = true;
						break;
					}
				}
				
				// Add the corresponding rect to the cache region 
				if (!fAlready && (hwnd != hDeskWnd) && GetWindowRect(hwnd, &rect))
				{
					//Buffer coordinates
					rect.left-=m_ScreenOffsetx;
					rect.right-=m_ScreenOffsetx;
					rect.top-=m_ScreenOffsety;
					rect.bottom-=m_ScreenOffsety;
					rfb::Rect wrect = rfb::Rect(rect).intersect(m_Cliprect);
					if (!wrect.is_empty())
					{
						rgn = rgn.union_(wrect);
						m_lWList.push_back(hwnd);
					}
					// char szName[64];
					// GetWindowText(hwnd, szName, 64);
					// vnclog.Print(LL_INTINFO, VNCLOG("### Changed Window : %s (at x=%d - y=%d)"), szName, x, y); 
					// return;
				}
			}

			iPixelColor++; // Next PixelColor in the list
		}
	}

	if(vista)
	{
		SelectObject(grabDC, oldbmp);
		DeleteObject(membmp);
		DeleteDC(grabDC);
	}
	if (fIncCycle)
	{
	   m_nGridCycle = (m_nGridCycle + 1) % (PIXEL_BLOCK_SIZE / GRID_OFFSET);
	}

}




// Implementation

vncDesktop::vncDesktop()
{
	m_thread = NULL;

	m_hwnd = NULL;
	m_timerid = 0;
	m_hnextviewer = NULL;
	m_hcursor = NULL;
	m_hOldcursor = NULL; // sf@2002

	m_displaychanged = FALSE;
	m_update_triggered = FALSE;
	g_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;

	// Modif sf@2002 - v1.1.0 
	m_lWList.clear();
    m_lGridsList.clear();
	m_nGridCycle = 0;

	// Modif sf@2002 - v1.1.0
	// m_lLastTempo = 0L;
	m_lLastMouseUpdateTime = 0L;
	m_lLastSlowClientTestTime = timeGetTime();

	// sf@2002 - TextChat - No more used for now
	// m_fTextChatRunning = false;
	// m_pCurrentTextChat = NULL;

	// Modif rdv@2002 - v1.1.x - videodriver
	m_videodriver=NULL;
	m_ScreenOffsetx=0;
	m_ScreenOffsety=0;
	m_hookdriver=false;

	OldPowerOffTimeout=0;

	UnSetHooks=NULL;
	SetMouseFilterHook=NULL;
	SetKeyboardFilterHook=NULL;
	SetHooks=NULL;
	hModule=NULL;
	char szCurrentDir[MAX_PATH];
	if (vncService::IsWinNT() && GetModuleFileName(NULL, szCurrentDir, MAX_PATH))	// Win98: don't use vncHooks
	{
		char* p = strrchr(szCurrentDir, '\\');
		if (p != NULL)
		{
			*p = '\0';
			strcat (szCurrentDir,"\\vnchooks.dll");
			hModule = LoadLibrary(szCurrentDir);
		}
	}
	if (hModule)
	{
		UnSetHooks = (UnSetHooksFn) GetProcAddress( hModule, "UnSetHooks" );
		SetMouseFilterHook  = (SetMouseFilterHookFn) GetProcAddress( hModule, "SetMouseFilterHook" );
		SetKeyboardFilterHook  = (SetKeyboardFilterHookFn) GetProcAddress( hModule, "SetKeyboardFilterHook" );
		SetHooks  = (SetHooksFn) GetProcAddress( hModule, "SetHooks" );
	}
	On_Off_hookdll=false;
	g_Desktop_running=true;
	hUser32=LoadLibrary("USER32");
	pbi = (pBlockInput)GetProcAddress( hUser32, "BlockInput");
	Temp_Resolution=false;
	m_OrigpollingSet=false;
	m_Origpolling=false;
	DriverWantedSet=false;

	current_monitor=3;
	ddihook = false;

	memset(&m_scrinfo, 0, sizeof(m_scrinfo));
	m_stop_input_while_sw = false;
}

vncDesktop::~vncDesktop()
{
	vnclog.Print(LL_INTINFO, VNCLOG("killing screen server"));

	// 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);
		vncDesktopThread *thread=(vncDesktopThread*)m_thread;
		while (g_DesktopThread_running!=false)
		{
			PostMessage(Window(), WM_QUIT, 0, 0);
			Sleep(200);
		}
		// Join with the desktop handler thread
		void *returnval;
		m_thread->join(&returnval);
		m_thread = NULL;
	}
	SetDisableInput(false);
	// Let's call Shutdown just in case something went wrong...
	Shutdown();

	// Modif sf@2002
	m_lWList.clear();
	GridsList::iterator iGrid;
	for (iGrid = m_lGridsList.begin(); iGrid != m_lGridsList.end(); iGrid++)
	{
		if (*iGrid)
		{
			// Since we've replaced this:
			// "typedef std::list<RGBPixelList*> GridsList;"
			// with this:
			// "typedef std::list<void*> GridsList;"
			// we must be carefull to avoid memory leaks...
			((RGBPixelList*)(*iGrid))->clear();
			delete ((RGBPixelList*)(*iGrid));
		}
	}
	m_lGridsList.clear();
	if (hModule)FreeLibrary(hModule);
	if (hUser32) FreeLibrary(hUser32);
	g_Desktop_running=false;
}


// Tell the desktop hooks to grab & update a particular rectangle
void
vncDesktop::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 update
void
vncDesktop::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;
		g_update_triggered = TRUE;
		if (m_timerid != NULL)
		KillTimer(NULL, m_timerid);
		m_timerid = NULL;
		PostMessage(Window(), WM_TIMER, 0, 0);
	}
}

// Routine to startup and install all the hooks and stuff
BOOL
vncDesktop::Startup(BOOL silent)
{
	// Initialise the Desktop object

	// ***
	// vncService::SelectInputWinStation()

	if (!InitDesktop(silent))
	{
		if(!silent)
			vnclog.Print(LL_INTINFO, VNCLOG("InitDesktop Failed"));
		return FALSE;
	}

	// Modif rdv@2002 - v1.1.x - videodriver
	if (!Temp_Resolution)
	{

⌨️ 快捷键说明

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