实现远程桌面控制的功能。
实现之前,我们先思考传输速度的问题,它主要由三方面决定:
1.抓屏 2.压缩 3.网络传输
我们先来思考抓屏,也就是截取桌面图片。
在此之前,先了解一些概念:
**DC():**设备上下文
**GetDC():**该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
GetDesktopWindow():返回桌面窗口句柄。
CreateCompatibleDC():创建一个与指定设备兼容的内存设备上下文环境(DC)。通过GetDc()获取的HDC直接与相关设备沟通,而本函数创建的DC,则是与内存中的一个表面相关联。
CreateDIBSection():创建应用程序可以直接写入的、与设备无关的位图(DIB)的函数。
截取桌面图片,就是定时截取windows桌面的图片。
通用的做法就是GetDC(GetDesktokWindow() )获取桌面的DC,
然后使用CreateDIBSection创建一个设备无关位图以及内存DC,
使用BitBlt把桌面DC的翻转到内存DC,这样通过内存DC就能直接获取到原始RGB数据。
这个就是GDI函数实现的通用做法,能在所有windows平台实现。
**但是这种抓屏方式相对比较慢,抓取一帧1080p的桌面需要5~8ms左右的时间。**单纯的从抓屏来说,这个时间还是可以接受的,但是抓屏后往往需要进行很多图像处理,所以这个用时就显得不那么友好了。
使用差异截屏可以稍微加快速度(但是还是很慢,哈哈。)
差异截屏法:
用BitBlt函数将屏幕图像数据从DC拷贝到屏幕DC相兼容的内存DC中,再用XOR运算计算相邻俩幅图像的差异部分。
m_DesktopHwnd = GetDesktopWindow();
m_DesktopDCHandle = GetDC(m_DesktopHwnd);
m_DesktopMemoryDCHandle = CreateCompatibleDC(m_DesktopDCHandle);
m_BitmapHandle = CreateDIBSection(m_DesktopDCHandle, m_BitmapInfo,
DIB_RGB_COLORS, &m_BitmapData, NULL, NULL);
SelectObject(m_DesktopMemoryDCHandle, m_BitmapHandle);
m_DifficultMemoryDCHandle = CreateCompatibleDC(m_DesktopDCHandle);
m_DifficultBitmapHandle = ::CreateDIBSection(m_DesktopDCHandle, m_BitmapInfo,
DIB_RGB_COLORS, &m_DifficultBitmapData, NULL, NULL);
SelectObject(m_DifficultMemoryDCHandle, m_DifficultBitmapHandle);
获得位图信息。
//BitBlt从原设备中复制位图到目标设备
::BitBlt(m_DesktopMemoryDCHandle, 0, 0,
m_FullMetricsWidth, m_FullMetricsHeigth, m_DesktopDCHandle, 0, 0, SRCCOPY);
注意GDI方式,是不带鼠标的,鼠标需要自己写。
//获得客户端鼠标位置
//写入光标位置
POINT CursorPosition;
GetCursorPos(&CursorPosition);
WriteScreenData((LPBYTE)&CursorPosition, sizeof(POINT));
//m_BufferData = [m_Algorithm][CursorPosition]
//获得客户端光标的样子
//写入当前光标类型
BYTE CursorTypeIndex = -1; //可以添加获得函数
WriteScreenData(&CursorTypeIndex, sizeof(BYTE));
//差异比较算法
if (m_Algorithm == ALGORITHM_DIFF)
{
//分段扫描全屏幕,将新的位图放入到m_DiffMemoryDCHandle中
ScanScreenData(m_DifficultMemoryDCHandle, m_DesktopDCHandle, m_BitmapInfo->bmiHeader.biWidth, m_BitmapInfo->bmiHeader.biHeight);
//两个位图进行比较,如果不一样修改
*BufferLength = m_Offset +
CompareScreenData((LPBYTE)m_DifficultBitmapData, (LPBYTE)m_BitmapData,
m_BufferData + m_Offset, m_BitmapInfo->bmiHeader.biSizeImage);
// *v11 *22
//m_BufferData = [m_Algorithm](1)[CursorPosition](4)[CursorTypeIndex](1)[位置(DWORD)](4)[(Count)](4)[不同的数据](4)
return m_BufferData;
}