📄 vncdesktopthread.cpp
字号:
#include "stdhdrs.h"
#include "vncdesktopthread.h"
#include "Global.h"
int counterwatch;//global var for driverwatch
bool g_DesktopThread_running;
bool g_update_triggered;
inline bool
ClipRect(int *x, int *y, int *w, int *h,
int cx, int cy, int cw, int ch) {
if (*x < cx) {
*w -= (cx-*x);
*x = cx;
}
if (*y < cy) {
*h -= (cy-*y);
*y = cy;
}
if (*x+*w > cx+cw) {
*w = (cx+cw)-*x;
}
if (*y+*h > cy+ch) {
*h = (cy+ch)-*y;
}
return (*w>0) && (*h>0);
}
////////////////////////////////////////////////////////////////////////////////////
// Modif rdv@2002 - v1.1.x - videodriver
void
vncDesktopThread::copy_bitmaps_to_buffer(ULONG i,rfb::Region2D &rgncache,rfb::UpdateTracker &tracker)
{
rfb::Rect rect;
int x = m_desktop->pchanges_buf->pointrect[i].rect.left;
int w = m_desktop->pchanges_buf->pointrect[i].rect.right-m_desktop->pchanges_buf->pointrect[i].rect.left;
int y = m_desktop->pchanges_buf->pointrect[i].rect.top;
int h = m_desktop->pchanges_buf->pointrect[i].rect.bottom-m_desktop->pchanges_buf->pointrect[i].rect.top;
//vnclog.Print(LL_INTINFO, VNCLOG("Driver ************* %i %i %i %i "),x,y,w,h);
if (!ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y,
m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) return;
//vnclog.Print(LL_INTINFO, VNCLOG("Driver ************* %i %i %i %i "),x,y,w,h);
rect.tl.x = x;
rect.br.x = x+w;
rect.tl.y = y;
rect.br.y = y+h;
switch(m_desktop->pchanges_buf->pointrect[i].type)
{
case SCREEN_SCREEN:
{
int dx=m_desktop->pchanges_buf->pointrect[i].point.x;
int dy=m_desktop->pchanges_buf->pointrect[i].point.y;
if (!m_screen_moved && (dx==0 || dy==0) )
{
x=x-dx;;
y=y-dy;;
if (!ClipRect(&x,&y,&w,&h,m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y,
m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y)) return;
rect.tl.x=x+dx;
rect.tl.y=y+dy;
rect.br.x=x+w+dx;
rect.br.y=y+h+dy;
rfb::Point delta = rfb::Point(-dx,-dy);
rgncache=rgncache.union_(rect);
tracker.add_copied(rect, delta);
// vnclog.Print(LL_INTINFO, VNCLOG("Copyrect "));
}
else
{
rgncache=rgncache.union_(rect);
}
break;
}
case SOLIDFILL:
case TEXTOUT:
case BLEND:
case TRANS:
case PLG:
case BLIT:;
rgncache=rgncache.union_(rect);
break;
default:
break;
}
}
// Modif rdv@2002 - v1.1.x - videodriver
BOOL
vncDesktopThread::handle_driver_changes(rfb::Region2D &rgncache,rfb::UpdateTracker &tracker)
{
omni_mutex_lock l(m_desktop->m_videodriver_lock);
int oldaantal=m_desktop->m_videodriver->oldaantal;
int counter=m_desktop->pchanges_buf->counter;
int nr_updates=m_desktop->pchanges_buf->pointrect[0].type;
vnclog.Print(LL_INTERR, VNCLOG("updates, rects %i %i"),m_desktop->pchanges_buf->pointrect[0].type,oldaantal-counter);
m_desktop->pchanges_buf->pointrect[0].type=0;
if (oldaantal==counter) return FALSE;
if (counter<1 || counter >1999) return FALSE;
if (!m_server->SingleWindow()) m_screen_moved=m_desktop->CalcCopyRects(tracker);
else m_screen_moved=true;
/// HEITE01E
// buffer was overloaded, so we use the bounding rect
if (nr_updates>2000)
{
rfb::Rect rect;
int x = m_desktop->pchanges_buf->pointrect[0].rect.left;
int w = m_desktop->pchanges_buf->pointrect[0].rect.right-m_desktop->pchanges_buf->pointrect[0].rect.left;
int y = m_desktop->pchanges_buf->pointrect[0].rect.top;
int h = m_desktop->pchanges_buf->pointrect[0].rect.bottom-m_desktop->pchanges_buf->pointrect[0].rect.top;
if (ClipRect(&x, &y, &w, &h, m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.tl.y,
m_desktop->m_bmrect.br.x-m_desktop->m_bmrect.tl.x, m_desktop->m_bmrect.br.y-m_desktop->m_bmrect.tl.y))
{
rect.tl.x = x;
rect.br.x = x+w;
rect.tl.y = y;
rect.br.y = y+h;
rgncache=rgncache.union_(rect);
m_desktop->m_videodriver->oldaantal=counter;
}
return TRUE;
}
if (m_server->SingleWindow()) m_screen_moved=true;
if (oldaantal<counter)
{
for (ULONG i =oldaantal+1; i<=counter;i++)
{
copy_bitmaps_to_buffer(i,rgncache,tracker);
}
}
else
{
ULONG i = 0;
for (i =oldaantal+1;i<MAXCHANGES_BUF;i++)
{
copy_bitmaps_to_buffer(i,rgncache,tracker);
}
for (i=1;i<=counter;i++)
{
copy_bitmaps_to_buffer(i,rgncache,tracker);
}
}
vnclog.Print(LL_INTINFO, VNCLOG("Nr rects %i "),rgncache.Numrects());
m_desktop->m_videodriver->oldaantal=counter;
// A lot updates left after combining
// This generates an overflow
// We expand each single update to minimum 32x32
if (rgncache.Numrects()>150)
{
rfb::Region2D rgntemp;
rfb::RectVector rects;
rfb::RectVector::iterator i;
rgncache.get_rects(rects, 1, 1);
for (i = rects.begin(); i != rects.end(); i++)
{
rfb::Rect rect = *i;
rect.tl.x=rect.tl.x/32*32;
rect.tl.y=rect.tl.y/32*32;
rect.br.x=rect.br.x/32*32+32;
rect.br.y=rect.br.y/32*32+32;
if (rect.br.x>m_desktop->m_bmrect.br.x) rect.br.x=m_desktop->m_bmrect.br.x;
if (rect.br.y>m_desktop->m_bmrect.br.y) rect.br.y=m_desktop->m_bmrect.br.y;
rgntemp=rgntemp.union_(rect);
}
//Still to many little updates
//Use the bounding rectangle for updates
if (rgntemp.Numrects()>50)
{
Rect brect=rgntemp.get_bounding_rect();
rgncache.clear();
rgncache=rgncache.union_(brect);
}
else
{
rgncache.clear();
rgncache=rgncache.union_(rgntemp);
}
}
return TRUE;
}
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();
}
}
if (m_return==0) g_DesktopThread_running=false;
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::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)) {
//Buffer coordinates
rect.left-=m_desktop->m_ScreenOffsetx;
rect.right-=m_desktop->m_ScreenOffsetx;
rect.top-=m_desktop->m_ScreenOffsety;
rect.bottom-=m_desktop->m_ScreenOffsety;
rfb::Rect wrect = rfb::Rect(rect).intersect(m_desktop->m_Cliprect);
if (!wrect.is_empty()) {
rgn = rgn.union_(wrect);
}
}
}
void
vncDesktopThread::SessionFix() {
if (!vncService::RunningAsService()) return;
DWORD dwSessionId = 0;
DWORD dwCurrentSessionId = 0;
typedef DWORD (WINAPI* pWTSGetActiveConsoleSessionId)(VOID);
typedef BOOL (WINAPI * pProcessIdToSessionId) (DWORD, DWORD*);
typedef BOOLEAN (WINAPI * pWinStationConnect) (HANDLE,ULONG,ULONG,PCWSTR,ULONG);
typedef BOOL (WINAPI * pLockWorkStation)();
HMODULE hlibkernel = LoadLibrary("kernel32.dll");
HMODULE hlibwinsta = LoadLibrary("winsta.dll");
HMODULE hlibuser32 = LoadLibrary("user32.dll");
pWTSGetActiveConsoleSessionId WTSGetActiveConsoleSessionIdF=NULL;
pProcessIdToSessionId ProcessIdToSessionIdF=NULL;
pWinStationConnect WinStationConnectF=NULL;
pLockWorkStation LockWorkStationF=NULL;
if (hlibkernel)
{
WTSGetActiveConsoleSessionIdF=(pWTSGetActiveConsoleSessionId)GetProcAddress(hlibkernel, "WTSGetActiveConsoleSessionId");
ProcessIdToSessionIdF=(pProcessIdToSessionId)GetProcAddress(hlibkernel, "ProcessIdToSessionId");
}
if (hlibwinsta)
{
WinStationConnectF=(pWinStationConnect)GetProcAddress(hlibwinsta, "WinStationConnectW");
}
if (hlibuser32)
{
LockWorkStationF=(pLockWorkStation)GetProcAddress(hlibuser32, "LockWorkStation");
}
if (WTSGetActiveConsoleSessionIdF!=NULL)
dwSessionId =WTSGetActiveConsoleSessionIdF();
if (ProcessIdToSessionIdF!=NULL)
ProcessIdToSessionIdF(GetCurrentProcessId(), &dwCurrentSessionId);
if (WTSGetActiveConsoleSessionIdF!=NULL) if (dwSessionId!=dwCurrentSessionId)
{
//Black screen only session 0 can be handled from a service
if (WinStationConnectF!=NULL)
{
WinStationConnectF(0, dwCurrentSessionId, dwSessionId, L"", 0);
if (LockWorkStationF!=NULL) LockWorkStationF();
}
}
if (hlibkernel) FreeLibrary(hlibkernel);
if (hlibwinsta) FreeLibrary(hlibwinsta);
if (hlibuser32) FreeLibrary(hlibuser32);
}
void *
vncDesktopThread::run_undetached(void *arg)
{
//*******************************************************
// INIT
//*******************************************************
SessionFix();
vnclog.Print(LL_INTERR, VNCLOG("Hook changed 1"));
// Save the thread's "home" desktop, under NT (no effect under 9x)
HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());
vnclog.Print(LL_INTERR, VNCLOG("Hook changed 2"));
// Attempt to initialise and return success or failure
m_desktop->KillScreenSaver();
{
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
Sleep(500); //Give screen some time to kill screensaver
}
if (!m_desktop->Startup())
{
if(vncService::IsWSLocked())
TeamviewerInfo::setLocalInfo(tvError, "WORKSTATION_LOCKED");
vncService::SelectHDESK(home_desktop);
ReturnVal(FALSE);
return NULL;
}
// Succeeded to initialise ok
ReturnVal(TRUE);
// sf@2003 - Done here to take into account if the driver is actually activated
m_desktop->InitHookSettings();
// 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_Cliprect);
clipped_updates.enable_copyrect(true);
rfb::Region2D rgncache;
// 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
rgncache = m_desktop->m_Cliprect;
m_server->SetScreenOffset(m_desktop->m_ScreenOffsetx,m_desktop->m_ScreenOffsety,m_desktop->nr_monitors);
// The previous cursor position is stored, to allow us to erase the
// old instance whenever it moves.
rfb::Point oldcursorpos;
// The driver gives smaller rectangles to check
// if Accuracy is 4 you eliminate pointer updates
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -