📄 vncdesktop.cpp
字号:
}
result = ::GetDIBits(m_hmemdc, m_membitmap, 0, 1, NULL, &m_bminfo.bmi, DIB_RGB_COLORS);
if (result == 0) {
return FALSE;
}
vnclog.Print(LL_INTINFO, VNCLOG("got bitmap format\n"));
vnclog.Print(LL_INTINFO, VNCLOG("DBG:display context has %d planes!\n"), GetDeviceCaps(m_hrootdc, PLANES));
vnclog.Print(LL_INTINFO, VNCLOG("DBG:memory context has %d planes!\n"), GetDeviceCaps(m_hmemdc, PLANES));
if (GetDeviceCaps(m_hmemdc, PLANES) != 1)
{
// FIXME: MessageBox in a service
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;
}
// 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;
return TRUE;
}
BOOL
vncDesktop::ThunkBitmapInfo()
{
// If we leave the pixel format intact, the blits 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 one we can handle
// We can handle 8-bit-palette and 16/32-bit-truecolour modes
switch (m_bminfo.bmi.bmiHeader.biBitCount)
{
case 1:
case 4:
vnclog.Print(LL_INTINFO, VNCLOG("DBG:used/bits/planes/comp/size "
"= %d/%d/%d/%d/%d\n"),
(int)m_bminfo.bmi.bmiHeader.biClrUsed,
(int)m_bminfo.bmi.bmiHeader.biBitCount,
(int)m_bminfo.bmi.bmiHeader.biPlanes,
(int)m_bminfo.bmi.bmiHeader.biCompression,
(int)m_bminfo.bmi.bmiHeader.biSizeImage);
// 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.biClrImportant = 0;
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()
{
// 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.right - m_bmrect.left); // Swap endian before actually sending
m_scrinfo.framebufferHeight = (CARD16) (m_bmrect.bottom - m_bmrect.top); // 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:
if (m_videodriver&& m_videodriver->IsDirectAccessInEffect())
{
// IMPORTANT: Mirage colormask is always 565
redMask = 0xf800;
greenMask = 0x07e0;
blueMask = 0x001f;
}
else if (m_bminfo.bmi.bmiHeader.biCompression == BI_RGB)
{
// Standard 16-bit display
// 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 ||
m_videodriver && m_videodriver->IsDirectAccessInEffect())
{
redMask = 0xff0000;
greenMask = 0xff00;
blueMask = 0x00ff;
// The real color depth is 24 bits in this case. If the depth
// is set to 32, the Tight encoder shows worse performance.
m_scrinfo.format.depth = 24;
}
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 only valid if they're palette-based
if (m_bminfo.truecolour)
{
vnclog.Print(LL_INTERR, "unsupported truecolour pixel format for SetPixShifts()\n");
return FALSE;
}
vnclog.Print(LL_INTINFO, VNCLOG("DBG:palette-based desktop in SetPixShifts()\n"));
return TRUE;
}
// Convert the data we just retrieved
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);
vnclog.Print(LL_INTINFO, VNCLOG("DBG:true-color desktop in SetPixShifts()\n"));
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)
{
LOGPALETTE *palette;
UINT size = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
palette = (LOGPALETTE *) new char[size];
if (palette == NULL) {
vnclog.Print(LL_INTERR, VNCLOG("error allocating palette\n"));
return FALSE;
}
// Initialise the structure
palette->palVersion = 0x300;
palette->palNumEntries = 256;
// Get the system colours
if (GetSystemPaletteEntries(m_hrootdc, 0, 256, palette->palPalEntry) == 0)
{
vnclog.Print(LL_INTERR, VNCLOG("GetSystemPaletteEntries() failed.\n"));
delete [] palette;
return FALSE;
}
// Create a palette from those
HPALETTE pal = CreatePalette(palette);
if (pal == NULL)
{
vnclog.Print(LL_INTERR, VNCLOG("CreatePalette() failed.\n"));
delete [] palette;
return FALSE;
}
// Select the palette into our memory DC
HPALETTE oldpalette = SelectPalette(m_hmemdc, pal, FALSE);
if (oldpalette == NULL)
{
vnclog.Print(LL_INTERR, VNCLOG("SelectPalette() failed.\n"));
delete [] palette;
DeleteObject(pal);
return FALSE;
}
// Worked, so realise the palette
if (RealizePalette(m_hmemdc) == GDI_ERROR)
vnclog.Print(LL_INTWARN, VNCLOG("warning - failed to RealizePalette\n"));
// It worked!
delete [] palette;
DeleteObject(oldpalette);
vnclog.Print(LL_INTINFO, VNCLOG("initialised palette OK\n"));
return TRUE;
}
// Not a palette based local screen - forget it!
vnclog.Print(LL_INTINFO, VNCLOG("no palette data for truecolour display\n"));
return TRUE;
}
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;
// Register it
m_wndClass = RegisterClassEx(&wndclass);
}
// 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) {
vnclog.Print(LL_INTERR, VNCLOG("CreateWindow() failed.\n"));
return FALSE;
}
// Set the "this" pointer for the window
SetWindowLong(m_hwnd, GWL_USERDATA, (long)this);
// Enable clipboard hooking
m_hnextviewer = SetClipboardViewer(m_hwnd);
return TRUE;
}
BOOL
vncDesktop::CreateBuffers()
{
vnclog.Print(LL_INTINFO, VNCLOG("attempting to create main and back buffers\n"));
// Create a new DIB section ***
HBITMAP tempbitmap = NULL;
if (!m_formatmunged)
{
tempbitmap = CreateDIBSection(
m_hmemdc,
&m_bminfo.bmi,
DIB_RGB_COLORS,
&m_DIBbits,
NULL,
0);
if (tempbitmap == NULL)
{
vnclog.Print(LL_INTWARN, VNCLOG("failed to build DIB section - reverting to slow blits\n"));
}
}
m_freemainbuff = false;
// NOTE m_mainbuff and m_backbuff allocation can not be supressed
// even with direct access mirror surface view
if (tempbitmap == NULL)
{
m_DIBbits = NULL;
// create our own buffer to copy blits through
if ((m_mainbuff = new BYTE [ScreenBuffSize()]) == NULL) {
vnclog.Print(LL_INTERR, VNCLOG("unable to allocate main buffer[%d]\n"), ScreenBuffSize());
return FALSE;
}
m_freemainbuff = true;
if ((m_backbuff = new BYTE [ScreenBuffSize()]) == NULL) {
vnclog.Print(LL_INTERR, VNCLOG("unable to allocate back buffer[%d]\n"), ScreenBuffSize());
return FALSE;
}
return TRUE;
}
// Create our own buffer to copy blits through
if ((m_backbuff = new BYTE [ScreenBuffSize()]) == NULL) {
vnclog.Print(LL_INTERR, VNCLOG("unable to allocate back buffer[%d]\n"), ScreenBuffSize());
if (tempbitmap!= NULL)
DeleteObject(tempbitmap);
return FALSE;
}
// Delete the old memory bitmap
if (m_membitmap != NULL) {
DeleteObject(m_membitmap);
m_membitmap = NULL;
}
// Replace old membitmap with DIB section
m_membitmap = tempbitmap;
m_mainbuff = (BYTE *)m_DIBbits;
vnclog.Print(LL_INTINFO, VNCLOG("enabled fast DIBsection blits OK\n"));
return TRUE;
}
BOOL
vncDesktop::Init(vncServer *server)
{
vnclog.Print(LL_INTINFO, VNCLOG("initialising desktop server\n"));
// Save the server pointer
m_server = server;
// Load in the arrow cursor
m_hdefcursor = LoadCursor(NULL, IDC_ARROW);
m_hcursor = m_hdefcursor;
// Spawn a thread to handle that window's message queue
vncDesktopThread *thread = new vncDesktopThread;
if (thread == NULL)
return FALSE;
m_thread = thread;
return thread->Init(this, m_server);
}
void
vncDesktop::RequestUpdate()
{
PostMessage(m_hwnd, WM_TIMER, TIMER_POLL, 0);
}
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);
}
// Function to capture an area of the screen immediately prior to sending
// an update.
void vncDesktop::CaptureScreen(RECT &UpdateArea, BYTE *scrBuff)
{
// ASSUME rect related to virtual desktop
if (m_videodriver && m_videodriver->IsDirectAccessInEffect())
CaptureScreenFromMirage(UpdateArea, scrBuff);
else CaptureScreenFromAdapterGeneral(UpdateArea, scrBuff);
}
void vncDesktop::CaptureScreenFromAdapterGeneral(RECT rect, BYTE *scrBuff)
{
// ASSUME rect related to virtual desktop
// Protect the memory bitmap
omni_mutex_lock l(m_bitbltlock);
// Finish drawing anything in this thread
// Wish we could do this for the whole system - maybe we should
// do something with LockWindowUpdate here.
GdiFlush();
// 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,
// source in m_hrootdc is relative to a virtual desktop,
// whereas dst coordinates of m_hmemdc are relative to its top-left corner (0, 0)
rect.left - m_bmrect.left,
rect.top - m_bmrect.top,
rect.right - rect.left,
rect.bottom - rect.top,
m_hrootdc,
rect.left, rect.top,
SRCCOPY);
// Select the old bitmap back into the memory DC
SelectObject(m_hmemdc, oldbitmap);
if (blitok)
{
// Copy the new data to the screen buffer (CopyToBuffer optimises this if possible)
CopyToBuffer(rect, scrBuff);
}
}
void vncDesktop::CaptureScreenFromMirage(RECT UpdateArea, BYTE *scrBuff)
{
// ASSUME rect related to virtual desktop
_ASSERTE(m_videodriver);
omni_mutex_lock l(m_bitbltlock);
CopyToBuffer(UpdateArea, scrBuff, m_videodriver->GetScreenView());
}
void vncDesktop::CaptureMouseRect()
{
POINT CursorPos;
ICONINFO IconInfo;
// If the mouse cursor handle is invalid then forget it
if (m_hcursor == NULL)
return;
// Get the cursor position
if (!GetCursorPos(&CursorPos))
return;
// Translate position for hotspot
if (GetIconInfo(m_hcursor, &IconInfo))
{
CursorPos.x -= ((int) IconInfo.xHotspot);
CursorPos.y -= ((int) IconInfo.yHotspot);
if (IconInfo.hbmMask != NULL)
DeleteObject(IconInfo.hbmMask);
if (IconInfo.hbmColor != NULL)
DeleteObject(IconInfo.hbmColor);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -