📄 clientconnection.cpp
字号:
m_minorVersion = rfbProtocolMinorVersion;#else if (sscanf(pv,rfbProtocolVersionFormat,&m_majorVersion,&m_minorVersion) != 2) { throw WarningException(_T("Invalid protocol")); } log.Print(0, _T("RFB server supports protocol version %d.%d\n"), m_majorVersion,m_minorVersion); if ((m_majorVersion == 3) && (m_minorVersion < 3)) { /* if server is 3.2 we can't use the new authentication */ log.Print(0, _T("Can't use IDEA authentication\n")); /* This will be reported later if authentication is requested*/ } else { /* any other server version, just tell the server what we want */ m_majorVersion = rfbProtocolMajorVersion; m_minorVersion = rfbProtocolMinorVersion; } sprintf(pv,rfbProtocolVersionFormat,m_majorVersion,m_minorVersion);#endif WriteExact(pv, sz_rfbProtocolVersionMsg); log.Print(0, _T("Connected to RFB server, using protocol version %d.%d\n"), rfbProtocolMajorVersion, rfbProtocolMinorVersion);}void ClientConnection::Authenticate(){ CARD32 authScheme, reasonLen, authResult; CARD8 challenge[CHALLENGESIZE]; ReadExact((char *)&authScheme, 4); authScheme = Swap32IfLE(authScheme); switch (authScheme) { case rfbConnFailed: ReadExact((char *)&reasonLen, 4); reasonLen = Swap32IfLE(reasonLen); CheckBufferSize(reasonLen+1); ReadString(m_netbuf, reasonLen); log.Print(0, _T("RFB connection failed, reason: %s\n"), m_netbuf); throw WarningException(m_netbuf); break; case rfbNoAuth: log.Print(0, _T("No authentication needed\n")); break; case rfbVncAuth: { if ((m_majorVersion == 3) && (m_minorVersion < 3)) { /* if server is 3.2 we can't use the new authentication */ log.Print(0, _T("Can't use IDEA authentication\n")); MessageBox(NULL, _T("Sorry - this server uses an older authentication scheme\n\r") _T("which is no longer supported."), _T("Protocol Version error"), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST); throw WarningException("Can't use IDEA authentication any more!"); } ReadExact((char *)challenge, CHALLENGESIZE); char passwd[256]; // Was the password already specified in a config file? if (strlen((const char *) m_encPasswd)>0) { char *pw = vncDecryptPasswd(m_encPasswd); strcpy(passwd, pw); free(pw); } else { AuthDialog ad; if (ad.DoDialog()) { #ifndef UNDER_CE strcpy(passwd, ad.m_passwd);#else int origlen = _tcslen(ad.m_passwd); int newlen = WideCharToMultiByte( CP_ACP, // code page 0, // performance and mapping flags ad.m_passwd, // address of wide-character string origlen, // number of characters in string passwd, // address of buffer for new string 255, // size of buffer NULL, NULL ); passwd[newlen]= '\0';#endif if (strlen(passwd) == 0) { log.Print(0, _T("Password had zero length\n")); throw WarningException("Empty password"); } if (strlen(passwd) > 8) { passwd[8] = '\0'; } vncEncryptPasswd(m_encPasswd, passwd); } else { throw QuietException("Authentication cancelled"); } } vncEncryptBytes(challenge, passwd); /* Lose the plain-text password from memory */ for (int i=0; i< (int) strlen(passwd); i++) { passwd[i] = '\0'; } WriteExact((char *) challenge, CHALLENGESIZE); ReadExact((char *) &authResult, 4); authResult = Swap32IfLE(authResult); switch (authResult) { case rfbVncAuthOK: log.Print(0, _T("VNC authentication succeeded\n")); break; case rfbVncAuthFailed: log.Print(0, _T("VNC authentication failed!")); throw WarningException("VNC authentication failed!"); case rfbVncAuthTooMany: throw WarningException( "VNC authentication failed - too many tries!"); default: log.Print(0, _T("Unknown VNC authentication result: %d\n"), (int)authResult); throw ErrorException("Unknown VNC authentication result!"); } break; } default: log.Print(0, _T("Unknown authentication scheme from RFB server: %d\n"), (int)authScheme); throw ErrorException("Unknown authentication scheme!"); }}void ClientConnection::SendClientInit(){ rfbClientInitMsg ci; ci.shared = m_opts.m_Shared; WriteExact((char *)&ci, sz_rfbClientInitMsg);}void ClientConnection::ReadServerInit(){ ReadExact((char *)&m_si, sz_rfbServerInitMsg); m_si.framebufferWidth = Swap16IfLE(m_si.framebufferWidth); m_si.framebufferHeight = Swap16IfLE(m_si.framebufferHeight); m_si.format.redMax = Swap16IfLE(m_si.format.redMax); m_si.format.greenMax = Swap16IfLE(m_si.format.greenMax); m_si.format.blueMax = Swap16IfLE(m_si.format.blueMax); m_si.nameLength = Swap32IfLE(m_si.nameLength); m_desktopName = new TCHAR[m_si.nameLength + 2];#ifdef UNDER_CE char *deskNameBuf = new char[m_si.nameLength + 2]; ReadString(deskNameBuf, m_si.nameLength); MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, deskNameBuf, m_si.nameLength, m_desktopName, m_si.nameLength+1); delete deskNameBuf;#else ReadString(m_desktopName, m_si.nameLength);#endif SetWindowText(m_hwnd, m_desktopName); log.Print(0, _T("Desktop name \"%s\"\n"),m_desktopName); log.Print(1, _T("Geometry %d x %d depth %d\n"), m_si.framebufferWidth, m_si.framebufferHeight, m_si.format.depth ); SetWindowText(m_hwnd, m_desktopName); SizeWindow();}void ClientConnection::SizeWindow(){ // Find how large the desktop work area is RECT workrect; SystemParametersInfo(SPI_GETWORKAREA, 0, &workrect, 0); int workwidth = workrect.right - workrect.left; int workheight = workrect.bottom - workrect.top; log.Print(2, _T("Screen work area is %d x %d\n"), workwidth, workheight); // Size the window. // Let's find out how big a window would be needed to display the // whole desktop (assuming no scrollbars). RECT fullwinrect; SetRect(&fullwinrect, 0, 0, m_si.framebufferWidth * m_opts.m_scale_num / m_opts.m_scale_den, m_si.framebufferHeight* m_opts.m_scale_num / m_opts.m_scale_den); AdjustWindowRectEx(&fullwinrect, GetWindowLong(m_hwnd, GWL_STYLE) & ~WS_VSCROLL & ~WS_HSCROLL, FALSE, GetWindowLong(m_hwnd, GWL_EXSTYLE)); m_fullwinwidth = fullwinrect.right - fullwinrect.left; m_fullwinheight = fullwinrect.bottom - fullwinrect.top; m_winwidth = min(m_fullwinwidth, workwidth); m_winheight = min(m_fullwinheight, workheight); SetWindowPos(m_hwnd, HWND_TOP, workrect.left + (workwidth-m_winwidth) / 2, workrect.top + (workheight-m_winheight) / 2, m_winwidth, m_winheight, SWP_SHOWWINDOW); SetForegroundWindow(m_hwnd);}// We keep a local copy of the whole screen. This is not strictly necessary// for VNC, but makes scrolling & deiconifying much smoother.void ClientConnection::CreateLocalFramebuffer() { omni_mutex_lock l(m_bitmapdcMutex); // We create a bitmap which has the same pixel characteristics as // the local display, in the hope that blitting will be faster. TempDC hdc(m_hwnd); m_hBitmap = ::CreateCompatibleBitmap(hdc, m_si.framebufferWidth, m_si.framebufferHeight); if (m_hBitmap == NULL) throw WarningException("Error creating local image of screen."); // Select this bitmap into the DC with an appropriate palette ObjectSelector b(m_hBitmapDC, m_hBitmap); PaletteSelector p(m_hBitmapDC, m_hPalette); // Put a "please wait" message up initially RECT rect; SetRect(&rect, 0,0, m_si.framebufferWidth, m_si.framebufferHeight); COLORREF bgcol = RGB(0xcc, 0xcc, 0xcc); FillSolidRect(&rect, bgcol); COLORREF oldbgcol = SetBkColor( m_hBitmapDC, bgcol); COLORREF oldtxtcol = SetTextColor(m_hBitmapDC, RGB(0,0,64)); rect.right = m_si.framebufferWidth / 2; rect.bottom = m_si.framebufferHeight / 2; DrawText (m_hBitmapDC, _T("Please wait - initial screen loading"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); SetBkColor( m_hBitmapDC, oldbgcol); SetTextColor(m_hBitmapDC, oldtxtcol); InvalidateRect(m_hwnd, NULL, FALSE);}void ClientConnection::SetupPixelFormat() { // Have we requested a reduction to 8-bit? if (m_opts.m_Use8Bit) { log.Print(2, _T("Requesting 8-bit truecolour\n")); m_myFormat = vnc8bitFormat; // We don't support colormaps so we'll ask the server to convert } else if (!m_si.format.trueColour) { // We'll just request a standard 16-bit truecolor log.Print(2, _T("Requesting 16-bit truecolour\n")); m_myFormat = vnc16bitFormat; } else { // Normally we just use the sever's format suggestion m_myFormat = m_si.format; m_myFormat.bigEndian = 0; // except always little endian // It's silly requesting more bits than our current display has, but // in fact it doesn't usually amount to much on the network. // Windows doesn't support 8-bit truecolour. // If our display is palette-based, we want more than 8 bit anyway, // unless we're going to start doing palette stuff at the server. // So the main use would be a 24-bit true-colour desktop being viewed // on a 16-bit true-colour display, and unless you have lots of images // and hence lots of raw-encoded stuff, the size of the pixel is not // going to make much difference. // We therefore don't bother with any restrictions, but here's the // start of the code if we wanted to do it. if (false) { // Get a DC for the root window TempDC hrootdc(NULL); int localBitsPerPixel = GetDeviceCaps(hrootdc, BITSPIXEL); int localRasterCaps = GetDeviceCaps(hrootdc, RASTERCAPS); log.Print(2, _T("Memory DC has depth of %d and %s pallete-based.\n"), localBitsPerPixel, (localRasterCaps & RC_PALETTE) ? "is" : "is not"); // If we're using truecolor, and the server has more bits than we do if ( (localBitsPerPixel > m_myFormat.depth) && ! (localRasterCaps & RC_PALETTE)) { m_myFormat.depth = localBitsPerPixel; // create a bitmap compatible with the current display // call GetDIBits twice to get the colour info. // set colour masks and shifts } } } // The endian will be set before sending}void ClientConnection::SetFormatAndEncodings(){ // Set pixel format to myFormat rfbSetPixelFormatMsg spf; spf.type = rfbSetPixelFormat; spf.format = m_myFormat; spf.format.redMax = Swap16IfLE(spf.format.redMax); spf.format.greenMax = Swap16IfLE(spf.format.greenMax); spf.format.blueMax = Swap16IfLE(spf.format.blueMax); WriteExact((char *)&spf, sz_rfbSetPixelFormatMsg); // The number of bytes required to hold at least one pixel. m_minPixelBytes = (m_myFormat.bitsPerPixel + 7) >> 3; // Set encodings char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4]; rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf; CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]); int len = 0; se->type = rfbSetEncodings; se->nEncodings = 0; // Put the preferred encoding first, and change it if the // preferred encoding is not actually usable. for (int i = LASTENCODING; i >= rfbEncodingRaw; i--) { if (m_opts.m_PreferredEncoding == i) { if (m_opts.m_UseEnc[i]) { encs[se->nEncodings++] = Swap32IfLE(i); } else { m_opts.m_PreferredEncoding--; } } } // Now we go through and put in all the other encodings in order. // We do rather assume that the most recent encoding is the most // desirable! for (i = LASTENCODING; i >= rfbEncodingRaw; i--) { if ( (m_opts.m_PreferredEncoding != i) && (m_opts.m_UseEnc[i])) { encs[se->nEncodings++] = Swap32IfLE(i); } } len = sz_rfbSetEncodingsMsg + se->nEncodings * 4; se->nEncodings = Swap16IfLE(se->nEncodings); WriteExact((char *) buf, len);}// Closing down the connection.// Close the socket, kill the thread.void ClientConnection::KillThread(){ m_bKillThread = true; m_running = false; if (m_sock != INVALID_SOCKET) { shutdown(m_sock, SD_BOTH); closesocket(m_sock); m_sock = INVALID_SOCKET; }}ClientConnection::~ClientConnection(){ if (m_hwnd != 0) DestroyWindow(m_hwnd); if (zis) delete zis; if (fis) delete fis; if (m_sock != INVALID_SOCKET) { shutdown(m_sock, SD_BOTH); closesocket(m_sock); m_sock = INVALID_SOCKET; } if (m_desktopName != NULL) delete [] m_desktopName; delete [] m_netbuf; DeleteDC(m_hBitmapDC); if (m_hBitmap != NULL) DeleteObject(m_hBitmap); if (m_hBitmapDC != NULL) DeleteObject(m_hBitmapDC); if (m_hPalette != NULL) DeleteObject(m_hPalette); m_pApp->DeregisterConnection(this);}// You can specify a dx & dy outside the limits; the return value will// tell you whether it actually scrolled.bool ClientConnection::ScrollScreen(int dx, int dy) { dx = max(dx, -m_hScrollPos); //dx = min(dx, m_hScrollMax-(m_cliwidth-1)-m_hScrollPos); dx = min(dx, m_hScrollMax-(m_cliwidth)-m_hScrollPos); dy = max(dy, -m_vScrollPos); //dy = min(dy, m_vScrollMax-(m_cliheight-1)-m_vScrollPos); dy = min(dy, m_vScrollMax-(m_cliheight)-m_vScrollPos); if (dx || dy) { m_hScrollPos += dx;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -