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

500 lines
13 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.

// ScreenSpy.cpp: implementation of the CScreenSpy class.
//
//////////////////////////////////////////////////////////////////////
#include "ScreenSpy.h"
#define RGB2GRAY(r,g,b) (((b)*117 + (g)*601 + (r)*306) >> 10)
#define DEF_STEP 13
#define OFF_SET 16
LONG CScreenSpy::nOldCursorPosX = 0;
LONG CScreenSpy::nOldCursorPosY = 0;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifdef _CONSOLE
#include <stdio.h>
#endif
CScreenSpy::CScreenSpy(int biBitCount, bool bIsGray, UINT nMaxFrameRate)
{
switch (biBitCount)
{
case 1:
case 4:
case 8:
case 16:
case 32:
m_biBitCount = biBitCount;
break;
default:
m_biBitCount = 8;
}
if (!SelectInputWinStation0())
{
m_hDeskTopWnd = GetDesktopWindow();
m_hFullDC = GetDC(m_hDeskTopWnd);
}
m_dwBitBltRop = SRCCOPY;
m_bAlgorithm = ALGORITHM_SCAN; // ĬÈÏʹÓøôÐÐɨÃèËã·¨
m_dwLastCapture = GetTickCount();
m_nMaxFrameRate = nMaxFrameRate;
m_dwSleep = 1000 / nMaxFrameRate;
m_bIsGray = bIsGray;
m_nFullWidth = ::GetSystemMetrics(SM_CXSCREEN);
m_nFullHeight = ::GetSystemMetrics(SM_CYSCREEN);
m_nIncSize = 32 / m_biBitCount;
m_nStartLine = 0;
m_hFullMemDC = ::CreateCompatibleDC(m_hFullDC);
m_hDiffMemDC = ::CreateCompatibleDC(m_hFullDC);
m_hLineMemDC = ::CreateCompatibleDC(NULL);
m_hRectMemDC = ::CreateCompatibleDC(NULL);
m_lpvLineBits = NULL;
m_lpvFullBits = NULL;
m_lpbmi_line = ConstructBI(m_biBitCount, m_nFullWidth, 1);
m_lpbmi_full = ConstructBI(m_biBitCount, m_nFullWidth, m_nFullHeight);
m_lpbmi_rect = ConstructBI(m_biBitCount, m_nFullWidth, 1);
m_hLineBitmap = ::CreateDIBSection(m_hFullDC, m_lpbmi_line, DIB_RGB_COLORS, &m_lpvLineBits, NULL, NULL);
m_hFullBitmap = ::CreateDIBSection(m_hFullDC, m_lpbmi_full, DIB_RGB_COLORS, &m_lpvFullBits, NULL, NULL);
m_hDiffBitmap = ::CreateDIBSection(m_hFullDC, m_lpbmi_full, DIB_RGB_COLORS, &m_lpvDiffBits, NULL, NULL);
::SelectObject(m_hFullMemDC, m_hFullBitmap);
::SelectObject(m_hLineMemDC, m_hLineBitmap);
::SelectObject(m_hDiffMemDC, m_hDiffBitmap);
::SetRect(&m_changeRect, 0, 0, m_nFullWidth, m_nFullHeight);
// ×ã¹»ÁË
m_rectBuffer = new BYTE[m_lpbmi_full->bmiHeader.biSizeImage * 2];
m_nDataSizePerLine = m_lpbmi_full->bmiHeader.biSizeImage / m_nFullHeight;
m_rectBufferOffset = 0;
}
CScreenSpy::~CScreenSpy()
{
::ReleaseDC(m_hDeskTopWnd, m_hFullDC);
::DeleteDC(m_hLineMemDC);
::DeleteDC(m_hFullMemDC);
::DeleteDC(m_hRectMemDC);
::DeleteDC(m_hDiffMemDC);
::DeleteObject(m_hLineBitmap);
::DeleteObject(m_hFullBitmap);
::DeleteObject(m_hDiffBitmap);
if (m_rectBuffer)
delete[] m_rectBuffer;
delete[] m_lpbmi_full;
delete[] m_lpbmi_line;
delete[] m_lpbmi_rect;
}
bool SwitchInputDesktop0()
{
BOOL bRet = false;
DWORD dwLengthNeeded;
HDESK hOldDesktop, hNewDesktop;
TCHAR strCurrentDesktop[256], strInputDesktop[256];
hOldDesktop = GetThreadDesktop(GetCurrentThreadId());
memset(strCurrentDesktop, 0, sizeof(strCurrentDesktop));
GetUserObjectInformation(hOldDesktop, UOI_NAME, &strCurrentDesktop, sizeof(strCurrentDesktop), &dwLengthNeeded);
hNewDesktop = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
memset(strInputDesktop, 0, sizeof(strInputDesktop));
GetUserObjectInformation(hNewDesktop, UOI_NAME, &strInputDesktop, sizeof(strInputDesktop), &dwLengthNeeded);
if (lstrcmpi(strInputDesktop, strCurrentDesktop) != 0)
{
SetThreadDesktop(hNewDesktop);
bRet = true;
}
CloseDesktop(hOldDesktop);
CloseDesktop(hNewDesktop);
return bRet;
}
bool CScreenSpy::SelectInputWinStation0()
{
bool bRet = ::SwitchInputDesktop0();
if (bRet)
{
ReleaseDC(m_hDeskTopWnd, m_hFullDC);
m_hDeskTopWnd = GetDesktopWindow();
m_hFullDC = GetDC(m_hDeskTopWnd);
}
return bRet;
}
LPVOID CScreenSpy::getNextScreen(LPDWORD lpdwBytes)
{
if (lpdwBytes == NULL || m_rectBuffer == NULL)
return NULL;
SelectInputWinStation0();
// ÖØÖÃrect»º³åÇøÖ¸Õë
m_rectBufferOffset = 0;
// дÈëʹÓÃÁËÄÄÖÖËã·¨
WriteRectBuffer((LPBYTE)&m_bAlgorithm, sizeof(m_bAlgorithm));
// дÈë¹â±êλÖÃ
POINT CursorPos;
GetCursorPos(&CursorPos);
WriteRectBuffer((LPBYTE)&CursorPos, sizeof(POINT));
// дÈ뵱ǰ¹â±êÀàÐÍ
BYTE bCursorIndex = m_CursorInfo.getCurrentCursorIndex();
WriteRectBuffer(&bCursorIndex, sizeof(BYTE));
// ²îÒì±È½ÏËã·¨
if (m_bAlgorithm == ALGORITHM_DIFF)
{
// ·Ö¶ÎɨÃèÈ«ÆÁÄ»
ScanScreen(m_hDiffMemDC, m_hFullDC, m_lpbmi_full->bmiHeader.biWidth, m_lpbmi_full->bmiHeader.biHeight);
*lpdwBytes = m_rectBufferOffset +
Compare((LPBYTE)m_lpvDiffBits, (LPBYTE)m_lpvFullBits, m_rectBuffer + m_rectBufferOffset, m_lpbmi_full->bmiHeader.biSizeImage);
return m_rectBuffer;
}
// Êó±êλÖ÷¢±ä»¯²¢ÇÒÈȵãÇøÓòÈç¹û·¢Éú±ä»¯£¬ÒÔ(·¢Éú±ä»¯µÄÐÐ + DEF_STEP)ÏòÏÂɨÃè
// ÏòÉÏÌá
for (int i = m_nStartLine; i < m_nFullHeight; i += DEF_STEP+1)
ScanChangedRect(i);
*lpdwBytes = m_rectBufferOffset;
m_nStartLine = (m_nStartLine + 3) % (DEF_STEP+1);
if ( nOldCursorPosX != CursorPos.x || nOldCursorPosY != CursorPos.y || *lpdwBytes != 10)
{
nOldCursorPosX = CursorPos.x;
nOldCursorPosY = CursorPos.y;
}
else
{
*lpdwBytes = 0;
}
// ÏÞÖÆ·¢ËÍÖ¡µÄËÙ¶È
while (GetTickCount() - m_dwLastCapture < m_dwSleep)
Sleep(50);
InterlockedExchange((LPLONG)&m_dwLastCapture, GetTickCount());
return m_rectBuffer;
}
bool CScreenSpy::ScanChangedRect(int nStartLine)
{
bool bRet = false;
LPDWORD p1, p2;
::BitBlt(m_hLineMemDC, 0, 0, m_nFullWidth, 1, m_hFullDC, 0, nStartLine, m_dwBitBltRop);
// 0 ÊÇ×îºóÒ»ÐÐ
p1 = (PDWORD)((DWORD)m_lpvFullBits + ((m_nFullHeight - 1 - nStartLine) * m_nDataSizePerLine));
p2 = (PDWORD)m_lpvLineBits;
::SetRect(&m_changeRect, -1, nStartLine - DEF_STEP, -1, nStartLine + DEF_STEP);
int nTotal_BitWidth = m_nFullWidth * m_biBitCount;
int nchBitWidth = (((nTotal_BitWidth & 7) + nTotal_BitWidth) >> 3) >> 2;
for (int i = 0; i < nchBitWidth; ++i)
{
if ( *(p1+i) != *(p2+i) )
{
if (m_changeRect.right < 0)
m_changeRect.left = 32 * i / m_biBitCount - OFF_SET;
m_changeRect.right = 32 * i / m_biBitCount + OFF_SET;
if (m_biBitCount > 2)
i = i + m_biBitCount / 2 - 1;
}
}
if (m_changeRect.right > -1)
{
m_changeRect.left = max(m_changeRect.left, 0);
m_changeRect.top = max(m_changeRect.top, 0);
m_changeRect.right = min(m_changeRect.right, m_nFullWidth);
m_changeRect.bottom = min(m_changeRect.bottom, m_nFullHeight);
// ¸´ÖƸıäµÄÇøÓò
CopyRect(&m_changeRect);
bRet = true;
}
return bRet;
}
void CScreenSpy::setAlgorithm(UINT nAlgorithm)
{
InterlockedExchange((LPLONG)&m_bAlgorithm, nAlgorithm);
}
LPBITMAPINFO CScreenSpy::ConstructBI(int biBitCount, int biWidth, int biHeight)
{
/*
biBitCount Ϊ1 (ºÚ°×¶þɫͼ) ¡¢4 (16 ɫͼ) ¡¢8 (256 ɫͼ) ʱÓÉÑÕÉ«±íÏîÊýÖ¸³öÑÕÉ«±í´óС
biBitCount Ϊ16 (16 λɫͼ) ¡¢24 (Õæ²Êɫͼ, ²»Ö§³Ö) ¡¢32 (32 λɫͼ) ʱûÓÐÑÕÉ«±í
*/
int color_num = biBitCount <= 8 ? 1 << biBitCount : 0;
int nBISize = sizeof(BITMAPINFOHEADER) + (color_num * sizeof(RGBQUAD));
BITMAPINFO *lpbmi = (BITMAPINFO *) new BYTE[nBISize];
BITMAPINFOHEADER *lpbmih = &(lpbmi->bmiHeader);
lpbmih->biSize = sizeof(BITMAPINFOHEADER);
lpbmih->biWidth = biWidth;
lpbmih->biHeight = biHeight;
lpbmih->biPlanes = 1;
lpbmih->biBitCount = biBitCount;
lpbmih->biCompression = BI_RGB;
lpbmih->biXPelsPerMeter = 0;
lpbmih->biYPelsPerMeter = 0;
lpbmih->biClrUsed = 0;
lpbmih->biClrImportant = 0;
lpbmih->biSizeImage = (((lpbmih->biWidth * lpbmih->biBitCount + 31) & ~31) >> 3) * lpbmih->biHeight;
// 16λºÍÒÔºóµÄûÓÐÑÕÉ«±í£¬Ö±½Ó·µ»Ø
if (biBitCount >= 16)
return lpbmi;
/*
Windows 95ºÍWindows 98£ºÈç¹ûlpvBits²ÎÊýΪNULL²¢ÇÒGetDIBits³É¹¦µØÌî³äÁËBITMAPINFO½á¹¹£¬ÄÇô·µ»ØÖµÎªÎ»Í¼ÖÐ×ܹ²µÄɨÃèÏßÊý¡£
Windows NT£ºÈç¹ûlpvBits²ÎÊýΪNULL²¢ÇÒGetDIBits³É¹¦µØÌî³äÁËBITMAPINFO½á¹¹£¬ÄÇô·µ»ØÖµÎª·Ç0¡£Èç¹ûº¯ÊýÖ´ÐÐʧ°Ü£¬ÄÇô½«·µ»Ø0Öµ¡£Windows NT£ºÈôÏë»ñµÃ¸ü¶à´íÎóÐÅÏ¢£¬Çëµ÷ÓÃcallGetLastErrorº¯Êý¡£
*/
HDC hDC = GetDC(NULL);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, 1, 1); // ¸ß¿í²»ÄÜΪ0
GetDIBits(hDC, hBmp, 0, 0, NULL, lpbmi, DIB_RGB_COLORS);
ReleaseDC(NULL, hDC);
DeleteObject(hBmp);
if (m_bIsGray)
{
for (int i = 0; i < color_num; i++)
{
int color = RGB2GRAY(lpbmi->bmiColors[i].rgbRed, lpbmi->bmiColors[i].rgbGreen, lpbmi->bmiColors[i].rgbBlue);
lpbmi->bmiColors[i].rgbRed = lpbmi->bmiColors[i].rgbGreen = lpbmi->bmiColors[i].rgbBlue = color;
}
}
return lpbmi;
}
void CScreenSpy::WriteRectBuffer(LPBYTE lpData, int nCount)
{
memcpy(m_rectBuffer + m_rectBufferOffset, lpData, nCount);
m_rectBufferOffset += nCount;
}
LPVOID CScreenSpy::getFirstScreen()
{
::BitBlt(m_hFullMemDC, 0, 0, m_nFullWidth, m_nFullHeight, m_hFullDC, 0, 0, m_dwBitBltRop);
return m_lpvFullBits;
}
void CScreenSpy::CopyRect( LPRECT lpRect )
{
int nRectWidth = lpRect->right - lpRect->left;
int nRectHeight = lpRect->bottom - lpRect->top;
LPVOID lpvRectBits = NULL;
// µ÷Õûm_lpbmi_rect
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;
HBITMAP hRectBitmap = ::CreateDIBSection(m_hFullDC, m_lpbmi_rect, DIB_RGB_COLORS, &lpvRectBits, NULL, NULL);
::SelectObject(m_hRectMemDC, hRectBitmap);
::BitBlt(m_hFullMemDC, lpRect->left, lpRect->top, nRectWidth, nRectHeight, m_hFullDC, lpRect->left, lpRect->top, m_dwBitBltRop);
::BitBlt(m_hRectMemDC, 0, 0, nRectWidth, nRectHeight, m_hFullMemDC, lpRect->left, lpRect->top, SRCCOPY);
WriteRectBuffer((LPBYTE)lpRect, sizeof(RECT));
WriteRectBuffer((LPBYTE)lpvRectBits, m_lpbmi_rect->bmiHeader.biSizeImage);
DeleteObject(hRectBitmap);
}
UINT CScreenSpy::getFirstImageSize()
{
return m_lpbmi_full->bmiHeader.biSizeImage;
}
void CScreenSpy::setCaptureLayer(bool bIsCaptureLayer)
{
DWORD dwRop = SRCCOPY;
if (bIsCaptureLayer)
dwRop |= CAPTUREBLT;
InterlockedExchange((LPLONG)&m_dwBitBltRop, dwRop);
}
LPBITMAPINFO CScreenSpy::getBI()
{
return m_lpbmi_full;
}
UINT CScreenSpy::getBISize()
{
int color_num = m_biBitCount <= 8 ? 1 << m_biBitCount : 0;
return sizeof(BITMAPINFOHEADER) + (color_num * sizeof(RGBQUAD));
}
void CScreenSpy::ScanScreen( HDC hdcDest, HDC hdcSrc, int nWidth, int nHeight)
{
int nJumpLine = 50;
int nJumpSleep = nJumpLine / 10; // ɨÃè¼ä¸ô
// ɨÃèÆÁÄ»
for (int i = 0, nToJump = 0; i < nHeight; i += nToJump)
{
int nOther = nHeight - i;
if (nOther > nJumpLine)
nToJump = nJumpLine;
else
nToJump = nOther;
BitBlt(hdcDest, 0, i, nWidth, nToJump, hdcSrc, 0, i, m_dwBitBltRop);
Sleep(nJumpSleep);
}
}
// ²îÒì±È½ÏËã·¨¿éµÄº¯Êý
int CScreenSpy::Compare( LPBYTE lpSource, LPBYTE lpDest, LPBYTE lpBuffer, DWORD dwSize )
{
// Windows¹æ¶¨Ò»¸öɨÃèÐÐËùÕ¼µÄ×Ö½ÚÊý±ØÐëÊÇ4µÄ±¶Êý, ËùÒÔÓÃDWORD±È½Ï
// LPDWORD p1, p2;
// p1 = (LPDWORD)lpDest;
// p2 = (LPDWORD)lpSource;
//
// // Æ«ÒÆµÄÆ«ÒÆ£¬²»Í¬³¤¶ÈµÄÆ«ÒÆ
// int nOffsetOffset = 0, nBytesOffset = 0, nDataOffset = 0;
// int nCount = 0; // Êý¾Ý¼ÆÊýÆ÷
// // p1++ʵ¼ÊÉÏÊǵÝÔöÁËÒ»¸öDWORD
// for (DWORD i = 0; i < dwSize; i += 4, p1++, p2++)
// {
// if (*p1 == *p2)
// continue;
// // Ò»¸öÐÂÊý¾Ý¿é¿ªÊ¼
// // дÈëÆ«ÒÆµØÖ·
// *(LPDWORD)(lpBuffer + nOffsetOffset) = i;
// // ¼Ç¼Êý¾Ý´óСµÄ´æ·ÅλÖÃ
// nBytesOffset = nOffsetOffset + sizeof(int);
// nDataOffset = nBytesOffset + sizeof(int);
// nCount = 0; // Êý¾Ý¼ÆÊýÆ÷¹éÁã
//
// // ¸üÐÂDestÖеÄÊý¾Ý
// *p1 = *p2;
// *(LPDWORD)(lpBuffer + nDataOffset + nCount) = *p2;
//
// nCount += 4;
// i += 4, p1++, p2++;
//
// for (DWORD j = i; j < dwSize; j += 4, i += 4, p1++, p2++)
// {
// if (*p1 == *p2)
// break;
//
// // ¸üÐÂDestÖеÄÊý¾Ý
// *p1 = *p2;
// *(LPDWORD)(lpBuffer + nDataOffset + nCount) = *p2;
// nCount += 4;
// }
// // дÈëÊý¾Ý³¤¶È
// *(LPDWORD)(lpBuffer + nBytesOffset) = nCount;
// nOffsetOffset = nDataOffset + nCount;
// }
//
// // nOffsetOffset ¾ÍÊÇдÈëµÄ×Ü´óС
// return nOffsetOffset;
//¸Ð¾õ»ã±àËÙ¶È»¹Ã»ÓÐCËã·¨¿ì£¬ÓôÃÆÀ´×Å
int Bytes = 0;
__asm
{
mov esi, [lpSource]
mov edi, [lpDest]
mov ebx, [lpBuffer]
xor ecx, ecx
jmp short Loop_Compare // ¿ªÊ¼½øÐбȽÏ
Loop_Compare_Continue:
mov eax, dword ptr [esi]
cmp eax, dword ptr [edi]
je short Loop_Compare_Equal // Èç¹ûÏàµÈ, ¼ÌÐø±È½Ï
mov [edi], eax // дÈ벻ͬµÄÊý¾Ýµ½Ä¿±êÖÐ
mov edx, ebx // edx ¼Ç¼µÚÒ»¸ö²»Í¬ÇøÓò¿éµÄÆðʼλÖÃ
mov dword ptr [ebx], ecx
add ebx, 8
mov dword ptr [ebx], eax
add ebx, 4
add esi, 4
add edi, 4
add ecx, 4
jmp short Loop_Block_Compare // Êý¾Ý²»Í¬£¬²úÉúÒ»¸öÇø¿é£¬¶ÔÕâ¸öÇø¿é½øÐбȽÏ
Loop_Block_Compare_Continue:
mov eax, dword ptr [esi]
cmp eax, dword ptr [edi]
jnz short Loop_Block_Compare_Not_Equal // Êý¾Ý²»ÏàµÈ£¬Ð´Èë
mov eax, ecx
sub eax, dword ptr [edx]
add edx, 4
mov dword ptr [edx], eax
add eax, 8
add [Bytes], eax
add esi, 4
add edi, 4
add ecx, 4
jmp short Loop_Block_Compare_Finish
Loop_Block_Compare_Not_Equal:
mov dword ptr [ebx], eax
mov [edi], eax // дÈ벻ͬµÄÊý¾Ýµ½Ä¿±êÖÐ
add ebx, 4
add esi, 4
add edi, 4
add ecx, 4
Loop_Block_Compare:
cmp ecx, [dwSize]
jb short Loop_Block_Compare_Continue
Loop_Block_Compare_Finish:
cmp ecx, [dwSize]
jnz short Loop_Compare
mov eax, ecx
sub eax, dword ptr [edx]
add edx, 4
mov dword ptr [edx], eax
add eax, 8
add [Bytes], eax
jmp short Loop_Compare
Loop_Compare_Equal:
add esi, 4
add edi, 4
add ecx, 4
Loop_Compare:
cmp ecx, [dwSize]
jb short Loop_Compare_Continue
}
return Bytes;
}