📄 vncdesktop.cpp
字号:
else
SetLastError(0); // last error may be set though the call succeeded, so clear it now;
// 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"));
}
BOOL
vncDesktop::Init(vncServer *server)
{
vnclog.Print(LL_INTINFO, VNCLOG("initialising desktop handler"));
// Save the server pointer
m_server = server;
// 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) {
vnclog.Print(LL_INTERR, VNCLOG("failed to start hook thread"));
return FALSE;
}
m_thread = thread;
//SINGEL WINDOW
SWinit();
// InitHookSettings();
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);
}
// 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 with alpha blending somehow doesn't work on 98
DWORD rop = (OSVersion() == OSVERSION_2000_XP_VISTA && !DisableCaptureBlt ?
CAPTUREBLT|SRCCOPY :
SRCCOPY);
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, rop);
// 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 buffer
void
vncDesktop::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;
//vnclog.Print(LL_INTINFO, VNCLOG("CursorPos %i %i"),CursorPos.x, CursorPos.y);
// Translate position for hotspot
if (GetIconInfo(m_hcursor, &IconInfo))
{
CursorPos.x -= ((int) IconInfo.xHotspot);
CursorPos.y -= ((int) IconInfo.yHotspot);
/// Buffer has (0,0) coordinates, Cursor (screencoordinates)
CursorPos.x -= m_ScreenOffsetx;
CursorPos.y -= m_ScreenOffsety;
///
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);
}
}
// CURSOR HANDLING
// Obtain cursor image data in server's local format.
// The length of databuf[] should be at least (width * height * 4).
BOOL
vncDesktop::GetRichCursorData(BYTE *databuf, HCURSOR hcursor, int width, int height)
{
// Protect the memory bitmap (is it really necessary here?)
omni_mutex_lock l(m_update_lock);
// Create bitmap, select it into memory DC
HBITMAP membitmap = CreateCompatibleBitmap(m_hrootdc, width, height);
if (membitmap == NULL) {
return FALSE;
}
HBITMAP oldbitmap = (HBITMAP) SelectObject(m_hmemdc, membitmap);
if (oldbitmap == NULL) {
DeleteObject(membitmap);
return FALSE;
}
// Draw the cursor
DrawIconEx(m_hmemdc, 0, 0, hcursor, 0, 0, 0, NULL, DI_IMAGE);
SelectObject(m_hmemdc, oldbitmap);
// Prepare BITMAPINFO structure (copy most m_bminfo fields)
int lines = 0;
BITMAPINFO *bmi = (BITMAPINFO *)calloc(1, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
if(!bmi)
{
vnclog.Print(LL_INTERR, VNCLOG("calloc == NULL"));
}
else
{
memcpy(bmi, &m_bminfo.bmi, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
bmi->bmiHeader.biWidth = width;
bmi->bmiHeader.biHeight = -height;
// Clear data buffer and extract RGB data
memset(databuf, 0x00, width * height * 4);
lines = GetDIBits(m_hmemdc, membitmap, 0, height, databuf, bmi, DIB_RGB_COLORS);
// Cleanup
free(bmi);
}
DeleteObject(membitmap);
return (lines != 0);
}
// Return the current mouse pointer position
rfb::Rect
vncDesktop::MouseRect()
{
return m_cursorpos;
}
void
vncDesktop::SetCursor(HCURSOR cursor)
{
if (cursor == NULL)
m_hcursor = m_hdefcursor;
else
{
m_hOldcursor = m_hcursor; // sf@2002
m_hcursor = cursor;
}
}
// Manipulation of the clipboard
void 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 METHODS
inline void
vncDesktop::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 buffer
void
vncDesktop::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)
{
#ifdef _MSC_VER
_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));
#endif
}
} 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 mistakes
bool
vncDesktop::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)) {
//Buffer coordinates
m_foreground_window_rect.clear();
} else {
foreground_rect.left-=m_ScreenOffsetx;
foreground_rect.right-=m_ScreenOffsetx;
foreground_rect.top-=m_ScreenOffsety;
foreground_rect.bottom-=m_ScreenOffsety;
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))
{
//screen to buffer coordinates
destrect.left-=m_ScreenOffsetx;
destrect.right-=m_ScreenOffsetx;
destrect.top-=m_ScreenOffsety;
destrect.bottom-=m_ScreenOffsety;
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;
delta= rfb::Point(dest.tl.x-source.x, dest.tl.y-source.y);
// if (dest.tl.x-source.x==0 || dest.tl.y-source.y==0) return false;
// Clip the destination rectangle
dest = dest.intersect(m_bmrect);
if (dest.is_empty()) return false;
// Clip the source rectangle
dest = dest.translate(delta.negate()).intersect(m_bmrect);
m_buffer.ClearCacheRect(dest);
dest = dest.translate(delta);
m_buffer.ClearCacheRect(dest);
if (!dest.is_empty()) {
tracker.add_copied(dest, delta);
return true;
}
}
}
} else {
m_foreground_window_rect.clear();
}
}
return false;
}
// Window procedure for the Desktop window
LRESULT CALLBACK
DesktopWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
vncDesktop *_this = (vncDesktop*)GetWindowLong(hwnd, GWL_USERDATA);
switch (iMsg)
{
///ddihook
case WM_SYSCOMMAND:
// User has clicked an item on the tray menu
switch (wParam)
{
case SC_MONITORPOWER:
vnclog.Print(LL_INTINFO, VNCLOG("Monitor2 %i"),lParam);
}
vnclog.Print(LL_INTINFO, VNCLOG("Monitor3 %i %i"),wParam,lParam);
return DefWindowProc(hwnd, iMsg, wParam, lParam);
case WM_POWER:
case WM_POWERBROADCAST:
// User has clicked an item on the tray menu
switch (wParam)
{
case SC_MONITORPOWER:
vnclog.Print(LL_INTINFO, VNCLOG("Monitor2 %i"),lParam);
}
vnclog.Print(LL_INTINFO, VNCLOG("Power3 %i %i"),wParam,lParam);
return DefWindowProc(hwnd, iMsg, wParam, lParam);
case WM_COPYDATA:
_this->pMyCDS= (PCOPYDATASTRUCT) lParam;
if (_this->pMyCDS->dwData==112233)
{
DWORD mysize=_this->pMyCDS->cbData;
char mytext[1024];
char *myptr;
char split[4][6];
strcpy(mytext,(LPCSTR)_this->pMyCDS->lpData);
myptr=mytext;
for (int j =0; j<(mysize/20);j++)
{
for (int i=0;i<4;i++)
{
strcpy(split[i]," ");
strncpy(split[i],myptr,4);
myptr=myptr+5;
}
_this->QueueRect(rfb::Rect(atoi(split[0]), atoi(split[1]), atoi(split[2]), atoi(split[3])));
}
}
//vnclog.Print(LL_INTINFO, VNCLOG("copydata"));
return 0;
// GENERAL
case WM_DISPLAYCHANGE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -