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

📄 vncdesktop.cpp

📁 Web VNC samples delphi
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//  Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
//  Copyright (C) 2001-2004 TightVNC Team. 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.
//
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
//
// 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 "stdhdrs.h"
#include <omnithread.h>

// Custom headers
#include "WinVNC.h"
#include "VNCHooks\VNCHooks.h"
#include "vncServer.h"
#include "vncRegion.h"
#include "rectlist.h"
#include "vncDesktop.h"
#include "vncService.h"
#include "WallpaperUtils.h"
#include "TsSessions.h"

#if (_MSC_VER>= 1300)
#include <fstream>
#else
#include <fstream.h>
#endif

// Constants
const 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");
// Messages for blocking remote input events
const UINT RFB_LOCAL_KEYBOARD = RegisterWindowMessage("WinVNC.Local.Keyboard");
const UINT RFB_LOCAL_MOUSE = RegisterWindowMessage("WinVNC.Local.Mouse");

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

// Atoms
const char *VNC_WINDOWPOS_ATOMNAME = "VNCHooks.CopyRect.WindowPos";
ATOM VNC_WINDOWPOS_ATOM = NULL;

// Static members to use with new polling algorithm
const int vncDesktop::m_pollingOrder[32] = {
	 0, 16,  8, 24,  4, 20, 12, 28,
	10, 26, 18,  2, 22,  6, 30, 14,
	 1, 17,  9, 25,  7, 23, 15, 31,
	19,  3, 27, 11, 29, 13,  5, 21
};
int vncDesktop::m_pollingStep = 0;


BOOL IsWinNT()
{
	return vncService::IsWinNT();
}

BOOL IsWinVerOrHigher(ULONG mj, ULONG mn)
{
	return vncService::VersionMajor() > mj ||
		vncService::VersionMajor() == mj && vncService::VersionMinor() >= mn;
}

BOOL IsNtVer(ULONG mj, ULONG mn)
{
	if (!vncService::IsWinNT())	
		return FALSE;
	return vncService::VersionMajor() == mj && vncService::VersionMinor() == mn;
}

BOOL vncDesktop::IsMultiMonDesktop()
{
	if (!IsWinVerOrHigher(4, 10))
		return FALSE;
	return GetSystemMetrics(SM_CMONITORS) > 1;
}

// The desktop handler thread
// This handles the messages posted by RFBLib to the vncDesktop window

class 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);

protected:
	vncServer *m_server;
	vncDesktop *m_desktop;

	omni_mutex m_returnLock;
	omni_condition *m_returnsig;
	BOOL m_return;
	BOOL m_returnset;
};

BOOL
vncDesktopThread::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;
}

void
vncDesktopThread::ReturnVal(BOOL result)
{
	omni_mutex_lock l(m_returnLock);

	m_returnset = TRUE;
	m_return = result;
	m_returnsig->signal();
}

void *vncDesktopThread::run_undetached(void *arg)
{
	// Save the thread's "home" desktop, under NT (no effect under 9x)
	HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());

	// Try to make session zero the console session
	if (!inConsoleSession())
		setConsoleSession();

	// Attempt to initialise and return success or failure
	if (!m_desktop->Startup())
	{
// vncDesktop::Startup might mave changed video mode in SetupDisplayForConnection.
// it has to be reverted then.
// TODO: review strong guarantee conditions for vncDesktop::Startup
		m_desktop->ResetDisplayToNormal();
		vncService::SelectHDESK(home_desktop);
		ReturnVal(FALSE);
		return NULL;
	}

	RECT rect = m_desktop->GetSourceRect();
	IntersectRect(&rect, &rect, &m_desktop->m_bmrect);
	m_server->SetSharedRect(rect);

	// 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);

	SYSTEMTIME systime;
	FILETIME ftime;
	ULARGE_INTEGER now, droptime;
	droptime.QuadPart = 0;

	MSG msg;
	while (TRUE)
	{
		if (!PeekMessage(&msg, m_desktop->Window(), NULL, NULL, PM_REMOVE))
		{
			// Whenever the message queue becomes empty, we check to see whether
			// there are updates to be passed to clients (first we make sure
			// that scheduled wallpaper removal is complete).
			if (!m_server->WallpaperWait()) {
				if (!m_desktop->CheckUpdates())
					break;
			}

			// 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)
		{
// TODO: suppress this message from hook when driver is active

			// An area of the screen has changed (ignore if we have a driver)
			if (m_desktop->m_videodriver == NULL)
			{
				RECT rect;
				rect.left =	(SHORT)LOWORD(msg.wParam);
				rect.top = (SHORT)HIWORD(msg.wParam);
				rect.right = (SHORT)LOWORD(msg.lParam);
				rect.bottom = (SHORT)HIWORD(msg.lParam);
				m_desktop->m_changed_rgn.AddRect(rect);
			}
		}
		else if (msg.message == RFB_MOUSE_UPDATE)
		{
			// Save the cursor ID
			m_desktop->SetCursor((HCURSOR) msg.wParam);
		}
		else if (msg.message == RFB_LOCAL_KEYBOARD)
		{
			// Block remote input events if necessary
			if (vncService::IsWin95()) {
				m_server->SetKeyboardCounter(-1);
				if (m_server->KeyboardCounter() < 0) {
					GetSystemTime(&systime);
					SystemTimeToFileTime(&systime, &ftime);
					droptime.LowPart = ftime.dwLowDateTime; 
					droptime.HighPart = ftime.dwHighDateTime;
					droptime.QuadPart /= 10000000;	// convert into seconds
					m_server->BlockRemoteInput(true);
				}
			} else {
				GetSystemTime(&systime);
				SystemTimeToFileTime(&systime, &ftime);
				droptime.LowPart = ftime.dwLowDateTime; 
				droptime.HighPart = ftime.dwHighDateTime;
				droptime.QuadPart /= 10000000;	// convert into seconds
				m_server->BlockRemoteInput(true);
			}
		}
		else if (msg.message == RFB_LOCAL_MOUSE)
		{
			// Block remote input events if necessary
			if (vncService::IsWin95()) {
				if (msg.wParam == WM_MOUSEMOVE) {
					m_server->SetMouseCounter(-1, msg.pt, true);
				} else {
					m_server->SetMouseCounter(-1, msg.pt, false);
				}
				if (m_server->MouseCounter() < 0 && droptime.QuadPart == 0) {
					GetSystemTime(&systime);
					SystemTimeToFileTime(&systime, &ftime);
					droptime.LowPart = ftime.dwLowDateTime; 
					droptime.HighPart = ftime.dwHighDateTime;
					droptime.QuadPart /= 10000000;	// convert into seconds
					m_server->BlockRemoteInput(true);
				}
			} else {
				GetSystemTime(&systime);
				SystemTimeToFileTime(&systime, &ftime);
				droptime.LowPart = ftime.dwLowDateTime; 
				droptime.HighPart = ftime.dwHighDateTime;
				droptime.QuadPart /= 10000000;	// convert into seconds
				m_server->BlockRemoteInput(true);
			}
		}
		else if (msg.message == WM_QUIT)
		{
			break;
		}
#ifdef HORIZONLIVE
		else if (msg.message == LS_QUIT)
		{
			// this is our custom quit message
			vnclog.Print(LL_INTINFO, VNCLOG("Received LS_QUIT message.\n"));
			break;
		}
#endif
		else
		{
			// Process any other messages normally
			DispatchMessage(&msg);
		}

		// Check timer to unblock remote input events if necessary
		// FIXME: rewrite this stuff to eliminate code duplication (ses above).
		// FIXME: Use time() instead of GetSystemTime().
		// FIXME: It's not necessary to do this on receiving _each_ message.
		if (m_server->LocalInputPriority() && droptime.QuadPart != 0) {
			GetSystemTime(&systime);
			SystemTimeToFileTime(&systime, &ftime);
			now.LowPart = ftime.dwLowDateTime;
			now.HighPart = ftime.dwHighDateTime;
			now.QuadPart /= 10000000;	// convert into seconds

			if (now.QuadPart - m_server->DisableTime() >= droptime.QuadPart) {
				m_server->BlockRemoteInput(false);
				droptime.QuadPart = 0;
				m_server->SetKeyboardCounter(0);
				m_server->SetMouseCounter(0, msg.pt, false);
			}
		}
	}

	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();
	// Return display settings to previous values.
	m_desktop->ResetDisplayToNormal();
	// Turn on the screen.
	m_desktop->BlankScreen(FALSE);

	// 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;
}

// Implementation of the vncDesktop class

vncDesktop::vncDesktop()
{
	m_thread = NULL;

	m_hwnd = NULL;
	m_polling_flag = FALSE;
	m_timer_polling = 0;
	m_timer_blank_screen = 0;
	m_hnextviewer = NULL;
	m_hcursor = NULL;

	m_displaychanged = FALSE;

	m_hrootdc = NULL;
	m_hmemdc = NULL;
	m_membitmap = NULL;

	m_initialClipBoardSeen = FALSE;

	// Vars for Will Dean's DIBsection patch
	m_DIBbits = NULL;
	m_freemainbuff = FALSE;
	m_formatmunged = FALSE;
	m_mainbuff = NULL;
	m_backbuff = NULL;

	m_clipboard_active = FALSE;
	m_hooks_active = FALSE;
	m_hooks_may_change = FALSE;
	m_lpAlternateDevMode = NULL;
	m_copyrect_set = FALSE;

	m_videodriver = NULL;

	m_timer_blank_screen = 0;
}

vncDesktop::~vncDesktop()
{
	vnclog.Print(LL_INTINFO, VNCLOG("killing desktop 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();
	_ASSERTE(!m_lpAlternateDevMode);
}

// Routine to startup and install all the hooks and stuff
BOOL
vncDesktop::Startup()
{
	// Currently, we just check whether we're in the console session, and
	//   fail if not
	if (!inConsoleSession()) {
		vnclog.Print(LL_INTERR, VNCLOG("Console is not session zero - reconnect to restore Console session"));
		return FALSE;
	}

	// Configure the display for optimal VNC performance.
	SetupDisplayForConnection();

	// Initialise the Desktop object
	if (!InitDesktop())
		return FALSE;

	if (InitVideoDriver())
	{
// this isn't really necessary
//		InvalidateRect(NULL,NULL,TRUE);
	}

	if (!InitBitmap())
		return FALSE;

	if (!ThunkBitmapInfo())
		return FALSE;

	if (!SetPixFormat())
		return FALSE;

	if (!CreateBuffers())
		return FALSE;

	if (!SetPixShifts())
		return FALSE;

	if (!SetPalette())
		return FALSE;

	if (!InitWindow())
		return FALSE;

	// Add the system hook
	ActivateHooks();
	m_hooks_may_change = true;

#ifndef HORIZONLIVE
	// Start up the keyboard and mouse filters
	SetKeyboardFilterHook(m_server->LocalInputsDisabled());
	SetMouseFilterHook(m_server->LocalInputsDisabled());
#endif

	// Start up the keyboard and mouse hooks  for 
	// local event priority over remote impl.
	if (m_server->LocalInputPriority())
		SetLocalInputPriorityHook(true);

	// Start a timer to handle Polling Mode.  The timer will cause
	// an "idle" event, which is necessary if Polling Mode is being used,
	// to cause TriggerUpdate to be called.
	SetPollingFlag(FALSE);
	SetPollingTimer();

	// If necessary, start a separate timer to preserve the diplay turned off.
	UpdateBlankScreenTimer();

	// Get hold of the WindowPos atom!
	if ((VNC_WINDOWPOS_ATOM = GlobalAddAtom(VNC_WINDOWPOS_ATOMNAME)) == 0) {
		vnclog.Print(LL_INTERR, VNCLOG("GlobalAddAtom() failed.\n"));
		return FALSE;
	}

// this member must be initialized: we cant assume the absence
// of clients when desktop is created.
	m_cursorpos.left = 0;
	m_cursorpos.top = 0;
	m_cursorpos.right = 0;
	m_cursorpos.bottom = 0;

	// Everything is ok, so return TRUE
	return TRUE;
}

// Routine to shutdown all the hooks and stuff

⌨️ 快捷键说明

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