📄 vncdesktop.cpp
字号:
// Register it m_wndClass = RegisterClassEx(&wndclass); if (!m_wndClass) { vnclog.Print(LL_INTERR, VNCLOG("failed to register window class\n")); 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) { vnclog.Print(LL_INTERR, VNCLOG("failed to create hook window\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;}voidvncDesktop::EnableOptimisedBlits(){ vnclog.Print(LL_INTINFO, VNCLOG("attempting to enable DIBsection blits\n")); // *** not necessary? /* if (m_formatmunged) { vnclog.Print(LL_INTINFO, VNCLOG("unable to enable fast blits\n")); m_DIBbits = NULL; return; } *//* // Prepare the bitmapinfo palette if necessary (*** DOESN'T QUITE WORK!) 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("failed to create temp fast palette - disabling fast blits\n")); return; } // Initialise the structure palette->palVersion = 0x300; palette->palNumEntries = 256; // Get the system colours if (GetSystemPaletteEntries(m_hrootdc, 0, 256, palette->palPalEntry) == 0) { delete [] palette; vnclog.Print(LL_INTERR, VNCLOG("failed to init fast palette - disabling fast blits\n")); return; } // Copy the system palette into the bitmap info for (int i=0; i<256; i++) { m_bminfo.bmi.bmiColors[i].rgbReserved = 0; m_bminfo.bmi.bmiColors[i].rgbRed = palette->palPalEntry[i].peRed; m_bminfo.bmi.bmiColors[i].rgbGreen = palette->palPalEntry[i].peGreen; m_bminfo.bmi.bmiColors[i].rgbBlue = palette->palPalEntry[i].peBlue; } // It worked! delete [] palette; vnclog.Print(LL_INTINFO, VNCLOG("initialised fast palette OK\n")); }*/ // Create a new DIB section HBITMAP tempbitmap = CreateDIBSection(m_hmemdc, &m_bminfo.bmi, DIB_RGB_COLORS, &m_DIBbits, NULL, 0); if (tempbitmap == NULL) { vnclog.Print(LL_INTINFO, VNCLOG("failed to build DIB section - reverting to slow blits\n")); 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; vnclog.Print(LL_INTINFO, VNCLOG("enabled fast DIBsection blits OK\n"));}BOOLvncDesktop::Init(vncServer *server){ vnclog.Print(LL_INTINFO, VNCLOG("initialising desktop handler\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) { vnclog.Print(LL_INTERR, VNCLOG("failed to start hook thread\n")); return FALSE; } m_thread = thread; return thread->Init(this, m_server);}intvncDesktop::ScreenBuffSize(){ return m_scrinfo.format.bitsPerPixel/8 * m_scrinfo.framebufferWidth * m_scrinfo.framebufferHeight;}voidvncDesktop::FillDisplayInfo(rfbServerInitMsg *scrinfo){ memcpy(scrinfo, &m_scrinfo, sz_rfbServerInitMsg);}// Function to capture an area of the screen immediately prior to sending// an update.voidvncDesktop::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, 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, scrBuffSize); }}// Add the mouse pointer to the buffervoidvncDesktop::CaptureMouse(BYTE *scrBuff, UINT scrBuffSize){ 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); } // Select the memory bitmap into the memory DC HBITMAP oldbitmap; if ((oldbitmap = (HBITMAP) SelectObject(m_hmemdc, m_membitmap)) == NULL) return; // Draw the cursor DrawIconEx( m_hmemdc, // handle to device context CursorPos.x, CursorPos.y, m_hcursor, // handle to icon to draw 0,0, // width of the icon 0, // index of frame in animated cursor NULL, // handle to background brush DI_NORMAL | DI_COMPAT // icon-drawing flags ); // Select the old bitmap back into the memory DC SelectObject(m_hmemdc, oldbitmap); // Save the bounding rectangle m_cursorpos.tl = CursorPos; m_cursorpos.br = rfb::Point(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)).translate(CursorPos); // Clip the bounding rect to the screen // Copy the mouse cursor into the screen buffer, if any of it is visible m_cursorpos = m_cursorpos.intersect(m_bmrect); if (!m_cursorpos.is_empty()) { CopyToBuffer(m_cursorpos, scrBuff, scrBuffSize); }}// Return the current mouse pointer positionrfb::RectvncDesktop::MouseRect(){ return m_cursorpos;}voidvncDesktop::SetCursor(HCURSOR cursor){ if (cursor == NULL) m_hcursor = m_hdefcursor; else m_hcursor = cursor;}// Manipulation of the clipboardvoid vncDesktop::SetClipText(char* rfbStr){ int len = strlen(rfbStr); char* winStr = new char[len*2+1]; int j = 0; for (int i = 0; i < len; i++) { if (rfbStr[i] == 10) winStr[j++] = 13; winStr[j++] = rfbStr[i]; } winStr[j++] = 0; // Open the system clipboard if (OpenClipboard(m_hwnd)) { // Empty it if (EmptyClipboard()) { HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, j); if (hMem != NULL) { LPSTR pMem = (char*)GlobalLock(hMem); // Get the data strcpy(pMem, winStr); // Tell the clipboard GlobalUnlock(hMem); SetClipboardData(CF_TEXT, hMem); } } } delete [] winStr; // Now close it CloseClipboard();}// INTERNAL METHODSinline voidvncDesktop::MaskToMaxAndShift(DWORD mask, CARD16 &max, CARD8 &shift){ for (shift = 0; (mask & 1) == 0; shift++) mask >>= 1; max = (CARD16) mask;}// Copy data from the memory bitmap into a buffervoidvncDesktop::CopyToBuffer(const rfb::Rect &rect, BYTE *destbuff, UINT destbuffsize){ // Finish drawing anything in this thread // Wish we could do this for the whole system - maybe we should // do something with LockWindowUpdate here. GdiFlush(); // Are we being asked to blit from the DIBsection to itself? if (destbuff == m_DIBbits) { // Yes. Ignore the request! return; } int y_inv; BYTE * destbuffpos; // Calculate the scanline-ordered y position to copy from y_inv = m_scrinfo.framebufferHeight-rect.tl.y-(rect.br.y-rect.tl.y); // Calculate where in the output buffer to put the data destbuffpos = destbuff + (m_bytesPerRow * rect.tl.y); // Set the number of bytes for GetDIBits to actually write // NOTE : GetDIBits pads the destination buffer if biSizeImage < no. of bytes required m_bminfo.bmi.bmiHeader.biSizeImage = (rect.br.y-rect.tl.y) * m_bytesPerRow; // Get the actual bits from the bitmap into the bit buffer // If fast (DIBsection) blits are disabled then use the old GetDIBits technique if (m_DIBbits == NULL) { if (GetDIBits(m_hmemdc, m_membitmap, y_inv, (rect.br.y-rect.tl.y), destbuffpos, &m_bminfo.bmi, DIB_RGB_COLORS) == 0) { _RPT1(_CRT_WARN, "vncDesktop : [1] GetDIBits failed! %d\n", GetLastError()); _RPT3(_CRT_WARN, "vncDesktop : thread = %d, DC = %d, bitmap = %d\n", omni_thread::self(), m_hmemdc, m_membitmap); _RPT2(_CRT_WARN, "vncDesktop : y = %d, height = %d\n", y_inv, (rect.br.y-rect.tl.y)); } } else { // Fast blits are enabled. [I have a sneaking suspicion this will never get used, unless // something weird goes wrong in the code. It's here to keep the function general, though!] int bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8; BYTE *srcbuffpos = (BYTE*)m_DIBbits; srcbuffpos += (m_bytesPerRow * rect.tl.y) + (bytesPerPixel * rect.tl.x); destbuffpos += bytesPerPixel * rect.tl.x; int widthBytes = (rect.br.x-rect.tl.x) * bytesPerPixel; for(int y = rect.tl.y; y < rect.br.y; y++) { memcpy(destbuffpos, srcbuffpos, widthBytes); srcbuffpos += m_bytesPerRow; destbuffpos += m_bytesPerRow; } }}// Routine to find out which windows have moved// If copyrect detection isn't perfect then this call returns// the copyrect destination region, to allow the caller to check// for mistakesvoidvncDesktop::CalcCopyRects(rfb::UpdateTracker &tracker){ HWND foreground = GetForegroundWindow(); RECT foreground_rect; // Actually, we just compare the new and old foreground window & its position if (foreground != m_foreground_window) { m_foreground_window=foreground; // Is the window invisible or can we not get its rect? if (!IsWindowVisible(foreground) || !GetWindowRect(foreground, &foreground_rect)) { m_foreground_window_rect.clear(); } else { m_foreground_window_rect = foreground_rect; } } else { // Same window is in the foreground - let's see if it's moved RECT destrect; rfb::Rect dest; rfb::Point source; // Get the window rectangle if (IsWindowVisible(foreground) && GetWindowRect(foreground, &destrect)) { rfb::Rect old_foreground_window_rect = m_foreground_window_rect; source = m_foreground_window_rect.tl; m_foreground_window_rect = dest = destrect; if (!dest.is_empty() && !old_foreground_window_rect.is_empty()) { // Got the destination position. Now send to clients! if (!source.equals(dest.tl)) { rfb::Point delta = rfb::Point(dest.tl.x-source.x, dest.tl.y-source.y); // Clip the destination rectangle dest = dest.intersect(m_bmrect); if (dest.is_empty()) return; // Clip the source rectangle dest = dest.translate(delta.negate()).intersect(m_bmrect); dest = dest.translate(delta); if (!dest.is_empty()) { // Tell the buffer about the copyrect m_buffer.CopyRect(dest, delta); // Notify all clients of the copyrect tracker.add_copied(dest, delta); } } } } else { m_foreground_window_rect.clear(); } }}// Window procedure for the Desktop windowLRESULT CALLBACKDesktopWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam){ vncDesktop *_this = (vncDesktop*)GetWindowLong(hwnd, GWL_USERDATA); switch (iMsg) { // GENERAL case WM_DISPLAYCHANGE: // The display resolution is changing // We must kick off any clients since their screen size will be wrong _this->m_displaychanged = TRUE; return 0; case WM_SYSCOLORCHANGE: case WM_PALETTECHANGED: // The palette colours have changed, so tell the server // Get the system palette if (!_this->SetPalette()) PostQuitMessage(0); // Update any palette-based clients, too _this->m_server->UpdatePalette(); return 0; // CLIPBOARD MESSAGES case WM_CHANGECBCHAIN: // The clipboard chain has changed - check our nextviewer handle if ((HWND)wParam == _this->m_hnextviewer) _this->m_hnextviewer = (HWND)lParam; else if (_this->m_hnextviewer != NULL) SendMessage(_this->m_hnextviewer, WM_CHANGECBCHAIN, wParam, lParam); return 0; case WM_DRAWCLIPBOARD: // The clipboard contents have changed if((GetClipboardOwner() != _this->Window()) && _this->m_initialClipBoardSeen && _this->m_clipboard_active) { LPSTR cliptext = NULL; // Open the clipboard if (OpenClipboard(_this->Window())) { // Get the clipboard data HGLOBAL cliphandle = GetClipboardData(CF_TEXT); if (cliphandle != NULL) { LPSTR clipdata = (LPSTR) GlobalLock(cliphandle); // Copy it into a new buffer if (clipdata == NULL) cliptext = NULL; else cliptext = strdup(clipdata); // Release the buffer and close the clipboard GlobalUnlock(cliphandle); } CloseClipboard(); } if (cliptext != NULL) { int cliplen = strlen(cliptext); LPSTR unixtext = (char *)malloc(cliplen+1); // Replace CR-LF with LF - never send CR-LF on the wire, // since Unix won't like it int unixpos=0; for (int x=0; x<cliplen; x++) { if (cliptext[x] != '\x0d') { unixtext[unixpos] = cliptext[x]; unixpos++; } } unixtext[unixpos] = 0; // Free the clip text free(cliptext); cliptext = NULL; // Now send the unix text to the server _this->m_server->UpdateClipText(unixtext); free(unixtext); } } _this->m_initialClipBoardSeen = TRUE; if (_this->m_hnextviewer != NULL) { // Pass the message to the next window in clipboard viewer chain. return SendMessage(_this->m_hnextviewer, WM_DRAWCLIPBOARD, 0,0); } return 0; default: return DefWindowProc(hwnd, iMsg, wParam, lParam); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -