#include <assert.h>
#include "stdhdrs.h"
#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"
#include "vncOSVersion.h"
#include "mmSystem.h"
#include "TextChat.h"
#include "vncdesktopthread.h"
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");
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);
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::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 on
// Otherwise we on
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);
}
}
}
// We test on
GridsList::iterator iGrid;
int nIndex = 0;
int nGridPos = (nZone * PIXEL_BLOCK_SIZE / GRID_OFFSET) + m_nGridCycle;
iGrid = m_lGridsList.begin();
while (nIndex != nGridPos)
{
iGrid++;
nIndex++;
}
iPixelColor = ((RGBPixelList*)(*iGrid))->begin();
pThePixelGrid = (RGBPixelList*) *iGrid;
if (nZone == 0 || nZone == 4) fIncCycle = true;
if (pThePixelGrid->empty()) fInitGrid = true;
int nOffset = GRID_OFFSET * m_nGridCycle;
// 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(m_hrootdc, xo, yo);
pThePixelGrid->push_back(PixelColor);
continue;
}
// Read the pixel's color on the screen
COLORREF PixelColor = GetPixel(m_hrootdc, 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);
}
}
}
iPixelColor++; // Next PixelColor in the list
}
}
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_lLastMouseUpdateTime = 0L;
m_lLastSlowClientTestTime = timeGetTime();
// Modif rdv@2002 - v1.1.x - videodriver
m_videodriver=NULL;
m_ScreenOffsetx=0;
m_ScreenOffsety=0;
m_hookdriver=false;
OldPowerOffTimeout=0;
hModule=NULL;
char szCurrentDir[MAX_PATH];
if (GetModuleFileName(NULL, szCurrentDir, MAX_PATH))
{
char* p = strrchr(szCurrentDir, '\\');
if (p == NULL) return;
*p = '\0';
strcat (szCurrentDir,"\\vnchooks.dll");
}
UnSetHooks=NULL;
SetMouseFilterHook=NULL;
SetKeyboardFilterHook=NULL;
SetHooks=NULL;
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;
}
vncDesktop::~vncDesktop()
{
// 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()
{
// Initialise the Desktop object
if (!InitDesktop()) return FALSE;
if (!Temp_Resolution)
{
if (DriverWantedSet==true)
{
m_server->Driver(DriverWanted);
m_server->Hook(HookWanted);
DriverWantedSet=false;
}
if (m_server->Driver())
{
if(OSVersion()==1 )
{
InitVideoDriver();
}
}
if (m_Origpolling) m_server->PollFullScreen(m_Origpolling);
m_OrigpollingSet=false;
}
else
{
m_Origpolling=m_server->PollFullScreen();
m_OrigpollingSet=true;
m_server->PollFullScreen(TRUE);
}
VideoBuffer();
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;
if (VideoBuffer())
{
pchanges_buf=NULL;
GETCHANGESBUF *pcommbuffer=m_videodriver->CreateCommunicationBuffer(m_bminfo.bmi.bmiHeader.biSizeImage);
// we need to check again, communication service can be down In that case driver can not be used
if (VideoBuffer())
{
if (m_membitmap != NULL)
{
DeleteObject(m_membitmap);
m_membitmap = NULL;
}
m_DIBbits=pcommbuffer->UserbufferBegin;
pchanges_buf=pcommbuffer->buffer;
InvalidateRect(NULL,NULL,TRUE);
}
}
// Start a timer to handle Polling Mode. The timer will cause
// an "idle" event on
// Mode is being used, to cause TriggerUpdate to be called.
m_timerid = SetTimer(m_hwnd, 1, 100, NULL);
// Initialise the buffer object
m_buffer.SetDesktop(this);
GetQuarterSize();
// Everything is ok, so return TRUE
return TRUE;
}
// Routine to shutdown all the hooks and stuff
BOOL vncDesktop::Shutdown()
{
// If we created a timer then kill it
if (m_timerid != NULL) KillTimer(NULL, m_timerid);
// If we created a window then kill it and the hooks
if(m_hwnd != NULL)
{
// Remove the system hooks
if (UnSetHooks) UnSetHooks(GetCurrentThreadId());
// The window is being closed - remove it from the viewer list
ChangeClipboardChain(m_hwnd, m_hnextviewer);
// Close the hook window
DestroyWindow(m_hwnd);
m_hwnd = NULL;
m_hnextviewer = NULL;
}
if (m_hrootdc != NULL)
{
DeleteDC(m_hrootdc);
m_hrootdc = NULL;
}
if (m_hmemdc != NULL)
{
DeleteDC(m_hmemdc);
m_hmemdc = NULL;
}
if (m_membitmap != NULL)
{
DeleteObject(m_membitmap);
m_membitmap = NULL;
}
// Modif rdv@2002 - v1.1.x - videodriver
ShutdownVideoDriver();
return TRUE;
}
// Routine to ensure we're on the correct NT desktop
BOOL vncDesktop::InitDesktop()
{
if (vncService::InputDesktopSelected()) return TRUE;
// Ask for the current input desktop
return vncService::SelectDesktop(NULL);
}
// Routine used to close the screen saver, if it's active...
BOOL CALLBACK KillScreenSaverFunc(HWND hwnd, LPARAM lParam)
{
char buffer[256];
if ((GetClassName(hwnd, buffer, 256) != 0) && (strcmp(buffer, "WindowsScreenSaverClass") == 0))
PostMessage(hwnd, WM_CLOSE, 0, 0);
return TRUE;
}
void vncDesktop::KillScreenSaver()
{
OSVERSIONINFO osversioninfo;
osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
if (!GetVersionEx(&osversioninfo)) return;
switch (osversioninfo.dwPlatformId)
{
case VER_PLATFORM_WIN32_WINDOWS:
{
// Fidn the ScreenSaverClass window
HWND hsswnd = FindWindow ("WindowsScreenSaverClass", NULL);
if (hsswnd != NULL) PostMessage(hsswnd, WM_CLOSE, 0, 0);
break;
}
case VER_PLATFORM_WIN32_NT:
{
// Find the screensaver desktop
HDESK hDesk = OpenDesktop("Screen-saver", 0, FALSE, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hDesk != NULL)
{
// Close all windows on the screen saver desktop
EnumDesktopWindows(hDesk, (WNDENUMPROC) &KillScreenSaverFunc, 0);
CloseDesktop(hDesk);
// Reset the screen saver so it can run again
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDWININICHANGE);
}
break;
}
}
}
// Modif sf@2002 - Single Window
BOOL CALLBACK EnumWindowsHnd(HWND hwnd, LPARAM arg)
{
int nRet;
char buffer[128];
char szNameAppli[16];
strcpy(szNameAppli, (LPSTR)(((vncDesktop*)arg)->GetServerPointer()->GetWindowName()));
szNameAppli[15]=0;
nRet = GetWindowText(hwnd, buffer, sizeof(buffer));
if (nRet > 0)
{
if ( !strnicmp(buffer, szNameAppli, lstrlen(szNameAppli)))
{
((vncDesktop*)arg)->m_Single_hWnd = hwnd;
return FALSE;
}
else
return TRUE;
}
return TRUE;
}
BOOL vncDesktop::InitBitmap()
{
// Get the device context for the whole screen and find it's size
DriverType=NONE;
if (OSVersion()==1) //XP W2k
{
if (VideoBuffer())
{
pEnumDisplayDevices pd;
LPSTR driverName = "Winvnc video hook driver";
BOOL DriverFound;
DEVMODE devmode;
FillMemory(&devmode, sizeof(DEVMODE), 0);
devmode.dmSize = sizeof(DEVMODE);
devmode.dmDriverExtra = 0;
BOOL change = EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&devmode);
devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
HMODULE hUser32=LoadLibrary("USER32");
pd = (pEnumDisplayDevices)GetProcAddress( hUser32, "EnumDisplayDevicesA");
if (pd)
{
LPSTR deviceName=NULL;
DISPLAY_DEVICE dd;
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
devmode.dmDeviceName[0] = '\0';
INT devNum = 0;
BOOL result;
DriverFound=false;
while (result = (*pd)(NULL,devNum, &dd,0))
{
if (strcmp((const char *)&dd.DeviceString[0], driverName) == 0)
{
DriverFound=true;
break;
}
devNum++;
}
if (DriverFound)
{
deviceName = (LPSTR)&dd.DeviceName[0];
m_hrootdc = CreateDC("DISPLAY",deviceName,NULL,NULL);
BOOL change = EnumDisplaySettings(deviceName,ENUM_CURRENT_SETTINGS,&devmode);
m_ScreenOffsetx=devmode.dmPosition.x;
m_ScreenOffsety=devmode.dmPosition.y;
if (m_hrootdc) DriverType=MIRROR;
Checkmonitors();
asked_display=m_buffer.GetDisplay();
current_monitor=1;
if (asked_display==2 && nr_monitors>1) current_monitor=2;
if (asked_display==3 && nr_monitors>1) current_monitor=3;
}
}
if (hUser32) FreeLibrary(hUser32);
}//VIDEOBUFFER
}//OS
// RDV SINGLE WINDOW
if (m_server->SingleWindow() && m_Single_hWnd==NULL)
{
EnumWindows((WNDENUMPROC)EnumWindowsHnd, (LPARAM) this);
}
if (m_hrootdc == NULL) {
//Multi-Monitor changes
Checkmonitors();
asked_display=m_buffer.GetDisplay();
current_monitor=1;
if (asked_display==2 && nr_monitors>1) current_monitor=2;
if (asked_display==3 && nr_monitors>1) current_monitor=3;
if (current_monitor==3) current_monitor=1;
if (current_monitor==1)
{
m_hrootdc = CreateDC(("DISPLAY"),mymonitor[0].device,NULL,NULL);
m_ScreenOffsetx=mymonitor[0].offsetx;
m_ScreenOffsety=mymonitor[0].offsety;
}
if (current_monitor==2)
{
m_hrootdc =CreateDC(("DISPLAY"),mymonitor[1].device,NULL,NULL);
m_ScreenOffsetx=mymonitor[1].offsetx;
m_ScreenOffsety=mymonitor[1].offsety;
}
if (current_monitor==3)
{
m_hrootdc = GetDC(NULL);
m_ScreenOffsetx=mymonitor[2].offsetx;
m_ScreenOffsety=mymonitor[2].offsety;;
}
if (m_hrootdc == NULL) return FALSE;
}
m_bmrect = rfb::Rect(0, 0,GetDeviceCaps(m_hrootdc, HORZRES),GetDeviceCaps(m_hrootdc, VERTRES));
// Create a compatible memory DC
m_hmemdc = CreateCompatibleDC(m_hrootdc);
if (m_hmemdc == NULL) return FALSE;
// Check that the device capabilities are ok
if ((GetDeviceCaps(m_hrootdc, RASTERCAPS) & RC_BITBLT) == 0)
{
MessageBox(NULL, "vncDesktop : root device doesn't support BitBlt\n", "WinVNC cannot be used with this graphic device driver", szAppName, MB_ICONSTOP | MB_OK);
return FALSE;
}
if ((GetDeviceCaps(m_hmemdc, RASTERCAPS) & RC_DI_BITMAP) == 0)
{
MessageBox(NULL, "vncDesktop : memory device doesn't support GetDIBits\n","WinVNC cannot be used with this graphics device driver", szAppName, MB_ICONSTOP | MB_OK);
return FALSE;
}
// Create the bitmap to be compatible with the ROOT DC!!!
m_membitmap = CreateCompatibleBitmap(m_hrootdc, m_bmrect.br.x, m_bmrect.br.y);
if (m_membitmap == NULL) return FALSE;
// Get the bitmap's format and colour details
int result;
memset(&m_bminfo, 0, sizeof(m_bminfo));
m_bminfo.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bminfo.bmi.bmiHeader.biBitCount = 0;
result = ::GetDIBits(m_hmemdc, m_membitmap, 0, 1, NULL, &m_bminfo.bmi, DIB_RGB_COLORS);
if (result == 0) return FALSE;
result = ::GetDIBits(m_hmemdc, m_membitmap, 0, 1, NULL, &m_bminfo.bmi, DIB_RGB_COLORS);
if (result == 0) return FALSE;
// Henceforth we want to use a top-down scanning representation
m_bminfo.bmi.bmiHeader.biHeight = - abs(m_bminfo.bmi.bmiHeader.biHeight);
// Is the bitmap palette-based or truecolour?
m_bminfo.truecolour = (GetDeviceCaps(m_hmemdc, RASTERCAPS) & RC_PALETTE) == 0;
InvalidateRect(NULL,NULL,TRUE);
return TRUE;
}
BOOL vncDesktop::ThunkBitmapInfo()
{
// If we leave the pixel format intact, the blist can be optimised (Will Dean's patch)
m_formatmunged = FALSE;
// HACK ***. Optimised blits don't work with palette-based displays, yet
if (!m_bminfo.truecolour) m_formatmunged = TRUE;
// Attempt to force the actual format into on
// We can handle 8-bit-palette and 16/32-bit-truecolour modes
switch (m_bminfo.bmi.bmiHeader.biBitCount)
{
case 1:
case 4:
// Correct the BITMAPINFO header to the format we actually want
m_bminfo.bmi.bmiHeader.biClrUsed = 0;
m_bminfo.bmi.bmiHeader.biPlanes = 1;
m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;
m_bminfo.bmi.bmiHeader.biBitCount = 8;
m_bminfo.bmi.bmiHeader.biSizeImage = abs((m_bminfo.bmi.bmiHeader.biWidth * m_bminfo.bmi.bmiHeader.biHeight * m_bminfo.bmi.bmiHeader.biBitCount)/ 8);
m_bminfo.bmi.bmiHeader.biClrImp
m_bminfo.truecolour = FALSE;
// Display format is non-VNC compatible - use the slow blit method
m_formatmunged = TRUE;
break;
case 24:
// Update the bitmapinfo header
m_bminfo.bmi.bmiHeader.biBitCount = 32;
m_bminfo.bmi.bmiHeader.biPlanes = 1;
m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;
m_bminfo.bmi.bmiHeader.biSizeImage = abs((m_bminfo.bmi.bmiHeader.biWidth * m_bminfo.bmi.bmiHeader.biHeight * m_bminfo.bmi.bmiHeader.biBitCount)/ 8);
// Display format is non-VNC compatible - use the slow blit method
m_formatmunged = TRUE;
break;
}
return TRUE;
}
BOOL vncDesktop::SetPixFormat()
{
// If we are using a memory bitmap then check how many planes it uses
// The VNC co
if (!m_DIBbits)
{
if (GetDeviceCaps(m_hmemdc, PLANES) != 1)
{
MessageBox(NULL, "vncDesktop : current display is PLANAR, not CHUNKY!\n" "WinVNC cannot be used with this graphics device driver", szAppName, MB_ICONSTOP | MB_OK );
return FALSE;
}
}
// Examine the bitmapinfo structure to obtain the current pixel format
m_scrinfo.format.trueColour = m_bminfo.truecolour;
m_scrinfo.format.bigEndian = 0;
// Set up the native buffer width, height and format
m_scrinfo.framebufferWidth = (CARD16) (m_bmrect.br.x - m_bmrect.tl.x); // Swap endian before actually sending
m_scrinfo.framebufferHeight = (CARD16) (m_bmrect.br.y - m_bmrect.tl.y); // Swap endian before actually sending
m_scrinfo.format.bitsPerPixel = (CARD8) m_bminfo.bmi.bmiHeader.biBitCount;
m_scrinfo.format.depth = (CARD8) m_bminfo.bmi.bmiHeader.biBitCount;
// Calculate the number of bytes per row
m_bytesPerRow = m_scrinfo.framebufferWidth * m_scrinfo.format.bitsPerPixel / 8;
return TRUE;
}
BOOL vncDesktop::SetPixShifts()
{
// Sort out the colour shifts, etc.
DWORD redMask=0, blueMask=0, greenMask = 0;
switch (m_bminfo.bmi.bmiHeader.biBitCount)
{
case 16:
// Standard 16-bit display
if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB)
{
// each word single pixel 5-5-5
redMask = 0x7c00; greenMask = 0x03e0; blueMask = 0x001f;
}
else
{
if (m_bminfo.bmi.bmiHeader.biCompression == BI_BITFIELDS)
{
redMask = *(DWORD *) &m_bminfo.bmi.bmiColors[0];
greenMask = *(DWORD *) &m_bminfo.bmi.bmiColors[1];
blueMask = *(DWORD *) &m_bminfo.bmi.bmiColors[2];
}
}
break;
case 32:
// Standard 24/32 bit displays
if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB)
{
redMask = 0xff0000; greenMask = 0xff00; blueMask = 0x00ff;
}
else
{
if (m_bminfo.bmi.bmiHeader.biCompression == BI_BITFIELDS)
{
redMask = *(DWORD *) &m_bminfo.bmi.bmiColors[0];
greenMask = *(DWORD *) &m_bminfo.bmi.bmiColors[1];
blueMask = *(DWORD *) &m_bminfo.bmi.bmiColors[2];
}
}
break;
default:
// Other pixel formats are on
if (m_bminfo.truecolour) return FALSE;
return TRUE;
}
// Convert the da
MaskToMaxAndShift(redMask, m_scrinfo.format.redMax, m_scrinfo.format.redShift);
MaskToMaxAndShift(greenMask, m_scrinfo.format.greenMax, m_scrinfo.format.greenShift);
MaskToMaxAndShift(blueMask, m_scrinfo.format.blueMax, m_scrinfo.format.blueShift);
return TRUE;
}
BOOL vncDesktop::SetPalette()
{
// Lock the current display palette into the memory DC we're holding
// *** CHECK THIS FOR LEAKS!
if (!m_bminfo.truecolour)
{
if (!m_DIBbits)
{
// - Handle the palette for a non DIB-Section
LOGPALETTE *palette;
UINT size = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
palette = (LOGPALETTE *) new char[size];
if (palette == NULL) return FALSE;
// Initialise the structure
palette->palVersion = 0x300;
palette->palNumEntries = 256;
// Get the system colours
if (GetSystemPaletteEntries(m_hrootdc, 0, 256, palette->palPalEntry) == 0)
{
delete [] palette;
return FALSE;
}
// Create a palette from those
HPALETTE pal = CreatePalette(palette);
if (pal == NULL)
{
delete [] palette;
return FALSE;
}
// Select the palette into our memory DC
HPALETTE oldpalette = SelectPalette(m_hmemdc, pal, FALSE);
if (oldpalette == NULL)
{
delete [] palette;
DeleteObject(pal);
return FALSE;
}
// Worked, so realise the palette
RealizePalette(m_hmemdc); //GDI_ERROR
// It worked!
delete []palette;
DeleteObject(oldpalette);
return TRUE;
}
else
{
// - Handle a DIB-Section's palette
// - Fetch the system palette for the framebuffer
PALETTEENTRY syspalette[256];
UINT entries = ::GetSystemPaletteEntries(m_hrootdc, 0, 256, syspalette);
// - Store it and convert it to RGBQUAD format
RGBQUAD dibpalette[256];
unsigned int i;
for (i=0;i<entries;i++)
{
dibpalette[i].rgbRed = syspalette[i].peRed;
dibpalette[i].rgbGreen = syspalette[i].peGreen;
dibpalette[i].rgbBlue = syspalette[i].peBlue;
dibpalette[i].rgbReserved = 0;
}
// - Set the rest of the palette to something nasty but usable
for (i=entries;i<256;i++) {
dibpalette[i].rgbRed = i % 2 ? 255 : 0;
dibpalette[i].rgbGreen = i/2 % 2 ? 255 : 0;
dibpalette[i].rgbBlue = i/4 % 2 ? 255 : 0;
dibpalette[i].rgbReserved = 0;
}
// - Update the DIB section to use the same palette
HDC bitmapDC=::CreateCompatibleDC(m_hrootdc);
if (!bitmapDC) return FALSE;
HBITMAP old_bitmap = (HBITMAP)::SelectObject(bitmapDC, m_membitmap);
if (!old_bitmap) return FALSE;
UINT entries_set = ::SetDIBColorTable(bitmapDC, 0, 256, dibpalette);
if (entries_set == 0) return FALSE;
if (!::SelectObject(bitmapDC, old_bitmap)) return FALSE;
}
}
// Not a palette based local screen - forget it!
return TRUE;
}
DWORD WINAPI Driverwatch(LPVOID lpParam)
{
//Mouse shape changed
if(OSVersion()==1)
{
HANDLE event;
HWND hwnd=(HWND)lpParam;
event=NULL;
while (event==NULL)
{
event = OpenEvent (SYNCHRONIZE, FALSE, "VncEvent") ;
Sleep(900);
if (!IsWindow(hwnd))
{
if (event) CloseHandle(event);
return 0;
}
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
for (;;)
{
if (WaitForSingleObject(event, 2000) == WAIT_OBJECT_0)
{
PostMessage(hwnd, WM_USER, 0, 0);
}
if (!IsWindow(hwnd) || !g_Desktop_running)
{
if (event) CloseHandle(event);
break;
}
}
}
return 0;
}
DWORD WINAPI Driverwatch2(LPVOID lpParam)
{
//new screen update
if(OSVersion()==1)
{
HANDLE event;
HWND hwnd=(HWND)lpParam;
event=NULL;
while (event==NULL)
{
event = OpenEvent (SYNCHRONIZE, FALSE, "VncEvent2") ;
Sleep(900);
if (!IsWindow(hwnd))
{
if (event) CloseHandle(event);
return 0;
}
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
counterwatch=0;
for (;;)
{
if (WaitForSingleObject(event, 50) == WAIT_OBJECT_0)
{
PostMessage(hwnd, WM_TIMER, 0, 0);
Sleep(100);
}
else
{
counterwatch++;
if (counterwatch==100)
{
PostMessage(hwnd, WM_USER+2, 0, 0);
counterwatch=0;
}
}
if (!IsWindow(hwnd) || !g_Desktop_running)
{
if (event) CloseHandle(event);
break;
}
}
}
return 0;
}
LRESULT CALLBACK DesktopWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
ATOM m_wndClass = 0;
BOOL vncDesktop::InitWindow()
{
if (m_wndClass == 0)
{
// Create the window class
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = &DesktopWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hAppInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = (const char *) NULL;
wndclass.lpszClassName = szDesktopSink;
wndclass.hIconSm = NULL;
m_wndClass = RegisterClassEx(&wndclass);
if (!m_wndClass) return FALSE;
}
// And create a window
m_hwnd = CreateWindow(szDesktopSink, "WinVNC", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, hAppInstance, NULL);
if (m_hwnd == NULL) return FALSE;
// Set the "this" pointer for the window
SetWindowLong(m_hwnd, GWL_USERDATA, (long)this);
// Enable clipboard hooking
m_hnextviewer = SetClipboardViewer(m_hwnd);
StopDriverWatches=false;
DrvWatch mywatch;
mywatch.stop=&StopDriverWatches;
mywatch.hwnd=m_hwnd;
if (VideoBuffer())
{
DWORD myword;
HANDLE T1=CreateThread(NULL,0,Driverwatch,m_hwnd,0,&myword);
CloseHandle(T1);
}
return TRUE;
}
void vncDesktop::EnableOptimisedBlits()
{
// Create a new DIB section
HBITMAP tempbitmap = CreateDIBSection(m_hmemdc, &m_bminfo.bmi, DIB_RGB_COLORS, &m_DIBbits, NULL, 0);
if (tempbitmap == NULL)
{
m_DIBbits = NULL;
return;
}
// Delete the old memory bitmap
if (m_membitmap != NULL)
{
DeleteObject(m_membitmap);
m_membitmap = NULL;
}
// Replace old membitmap with DIB section
m_membitmap = tempbitmap;
}
BOOL vncDesktop::Init(vncServer *server)
{
// Save the server pointer
m_server = server;
if (OSVersion()==1)
m_fCaptureAlphaBlending = m_server->CaptureAlphaBlending();
else
m_fCaptureAlphaBlending = false;
// Load in the arrow cursor
m_hdefcursor = LoadCursor(NULL, IDC_ARROW);
m_hcursor = m_hdefcursor;
m_hOldcursor = m_hdefcursor; //sf@2002
// Spawn a thread to handle that window's message queue
vncDesktopThread *thread = new vncDesktopThread;
if (thread == NULL) return FALSE;
m_thread = thread;
//SINGEL WINDOW
SWinit();
return thread->Init(this, m_server);
}
int vncDesktop::ScreenBuffSize()
{
return m_scrinfo.format.bitsPerPixel/8 * m_scrinfo.framebufferWidth * m_scrinfo.framebufferHeight;
}
void vncDesktop::FillDisplayInfo(rfbServerInitMsg *scrinfo)
{
memcpy(scrinfo, &m_scrinfo, sz_rfbServerInitMsg);
}
#define CAPTUREBLT 0x40000000
// Function to capture an area of the screen immediately prior to sending an update.
void vncDesktop::CaptureScreen(const rfb::Rect &rect, BYTE *scrBuff, UINT scrBuffSize)
{
assert(rect.enclosed_by(m_bmrect));
// Select the memory bitmap into the memory DC
HBITMAP oldbitmap;
if ((oldbitmap = (HBITMAP) SelectObject(m_hmemdc, m_membitmap)) == NULL) return;
// Capture screen into bitmap
BOOL blitok = BitBlt(m_hmemdc, rect.tl.x, rect.tl.y, (rect.br.x-rect.tl.x), (rect.br.y-rect.tl.y), m_hrootdc, rect.tl.x, rect.tl.y, m_fCaptureAlphaBlending ? (CAPTUREBLT | SRCCOPY) : SRCCOPY);
// Select the old bitmap back into the memory DC
SelectObject(m_hmemdc, oldbitmap);
// Copy the new da
if (blitok) CopyToBuffer(rect, scrBuff, scrBuffSize);
}
评论