远程控制编写之屏幕传输 MFC实现 屏幕截图 发送bmp数据 显示bmp图像
远程控制编写之屏幕传输 MFC实现 屏幕截图 发送bmp数据 显示bmp图像:
一 :
首先要了解bmp图像的结构 详情请看我转载的一篇文章http://blog.csdn.net/hnust_xiehonghao/article/details/37656281
二: 被控端的代码
注意以下代码要放到一个线程中去 由于用到了while死循环 表示一直发送消息 直到对方关闭接收,发送失败后自己主动退出! 一定要放进线程
DWORD __stdcall SendScreen(LPVOID lparam)//线程处理屏幕传输
{ DWORD *pParam = (DWORD *)lparam;
SOCKET MainSocket =*pParam;
DWORD dwLastSend; HWND hWnd = GetDesktopWindow();//获得屏幕的HWND.
HDC hScreenDC = GetDC(hWnd); //获得屏幕的HDC.
HDC MemDC = CreateCompatibleDC(hScreenDC);
RECT rect;
//该函数返回指定窗体的边框矩形的尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出。
GetWindowRect(hWnd,&rect);
SIZE screensize;
screensize.cx=rect.right-rect.left;
screensize.cy=rect.bottom-rect.top;
//CreateCompatibleBitmap该函数创建与指定的设备hScreenDC环境相关的设备兼容的位图。
HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC,screensize.cx,screensize.cy); while(1)
{
dwLastSend = GetTickCount();
HGDIOBJ hOldBMP = ::SelectObject(MemDC,hBitmap);
//该函数对hScreenDc环境区域中的像素进行位块转换,以传送到目标设备MemDC环境。
::BitBlt(MemDC,0,0,screensize.cx,screensize.cy,hScreenDC,rect.left,rect.top,SRCCOPY);
::SelectObject(MemDC,hOldBMP);
/***************************************************************/ HDC hDC =::CreateDC("DISPLAY",NULL,NULL,NULL);
int iBits = ::GetDeviceCaps(hDC, BITSPIXEL) * ::GetDeviceCaps(hDC, PLANES);//当前分辨率下每一个像素所占字节数
::DeleteDC(hDC); WORD wBitCount; //位图中每一个像素所占字节数
if (iBits <= 1)
wBitCount = 1;
else if (iBits <= 4)
wBitCount = 4;
else if (iBits <= 8)
wBitCount = 8;
else if (iBits <= 24)
wBitCount = 24;
else
wBitCount = iBits; DWORD dwPaletteSize=0; //调色板大小, 位图中像素字节大小
if (wBitCount <= 8)
dwPaletteSize = (1 << wBitCount) * sizeof(RGBQUAD); BITMAP bm; //位图属性结构
::GetObject(hBitmap, sizeof(bm), (LPSTR)&bm); BITMAPINFOHEADER bi; //位图信息头结构
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB; //BI_RGB表示位图没有压缩
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0; DWORD dwBmBitsSize = ((bm.bmWidth * wBitCount+31)/32) * 4 * bm.bmHeight;
HANDLE hDib = ::GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); //为位图内容分配内存
//HANDLE hDib = ::GlobalAlloc(GHND,3686440*3); //为位图内容分配内存
//锁定内存中指定的内存块,并返回一个地址值,令其指向内存块的起始处。除非用 GlobalUnlock 函数将内存块解锁,否则地址会一直保持有效。
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi; HANDLE hPal = ::GetStockObject(DEFAULT_PALETTE); // 处理调色板
HANDLE hOldPal=NULL;
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal = SelectPalette(hDC,(HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
//将数据保存在指针(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize指向的位置
::GetDIBits(hDC, hBitmap, 0, (UINT) bm.bmHeight,(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,(BITMAPINFO*)lpbi,DIB_RGB_COLORS);// 获取该调色板下新的像素值
if (hOldPal)//恢复调色板
{
SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
} BITMAPFILEHEADER bmfHdr; //位图文件头结构
bmfHdr.bfType = 0x4D42; // "BM" // 设置位图文件头
DWORD dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; MsgHead MsgSend;
MsgSend.dwCmd = CMD_SCREEN_TO_SHOW;
MsgSend.dwSize = dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER);
MsgSend.dwExtend1 = bmfHdr.bfSize;
MsgSend.dwExtend2 = bmfHdr.bfOffBits; if(!SendMsg(MainSocket, (char*)lpbi, &MsgSend))//自己定义函数 其内进行2次发送数据。一次用send发送MsgHead结构体 一次发送字符buffer此处为lpbi
{//使用本代码时 把SendMsg换成你自己的发送函数 本人的函数先发送一个自己定义结构体再发送lpbi 分2次发送 故以下主控端分2次接受
::DeleteObject(MemDC);
::ReleaseDC(hWnd,hScreenDC);
GlobalUnlock(hDib); //清除
GlobalFree(hDib);
//::MessageBox(NULL, "发送失败","",MB_OK);
return 0;
} /*
//将得到的屏幕截屏保存到E://mybitmap.bmp
char strFilePath[111] = "E://mybitmap.bmp";
HANDLE hFile = CreateFile(strFilePath , GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);//创建位图文件
DWORD dwWritten;
WriteFile(hFile, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); // 写入位图文件头
WriteFile(hFile, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);// 写入位图文件其余内容
*/
GlobalUnlock(hDib); //清除
GlobalFree(hDib);
//CloseHandle(hFile);
if ((GetTickCount() - dwLastSend) < 110)
Sleep(100);
}
return 0;
}
三
主控端的代码:
1 因为主控端也要一个循环进行一直接收屏幕消息 所以以下这个函数的代码一定也要放进一个线程中去!也能够让一个线程去调用处理函数 我採用的是另外一种 用线程去调用此函数!
void CScreenDlg::GetFirstScreen()
{ MsgHead MsgSend;
MsgSend.dwCmd = CMD_GETFIRST_SCREEN;
MsgSend.dwSize = 0;
if(!SendMsg(m_MainSocket, NULL, &MsgSend))//发出请求屏幕传输的要求
{
::MessageBox(NULL, "屏幕传输请求失败", "出错", MB_OK);
closesocket(m_MainSocket);
return ; }
//下面为屏幕的获取, 一直获取并显示 直到接收不到 或设置计时器 一定时间后退出
DWORD dwLastSend;
MsgHead MsgRecv; while(m_MainSocket != INVALID_SOCKET)
{ if(!RecvData(m_MainSocket, (char *)&MsgRecv, sizeof(MsgHead)))//自己定义接受函数 其内是用的recv函数 如使用本代码 替换为recv函数就可以
{
::MessageBox(NULL, "屏幕数据接收,命令接收失败", "出错", MB_OK);
closesocket(m_MainSocket);
m_MainSocket = INVALID_SOCKET;
return ;
} bmfHdr.bfType = 0x4D42; // "BM" // 设置位图文件头 成员变量bmfHdr类型为 BITMAPFILEHEADER
bmfHdr.bfSize = MsgRecv.dwExtend1;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = MsgRecv.dwExtend2;
m_InfoSize = MsgRecv.dwExtend2 - sizeof(BITMAPFILEHEADER);//m_InfoSize为info信息头和调色板的大小的和 if(!RecvData(m_MainSocket,(char *)pData,MsgRecv.dwSize))//自己定义接受函数 使用时换成你自己的函数 或者recv函数就可以
{
::MessageBox(NULL, "屏幕数据接收,数据接收失败", "出错", MB_OK);
closesocket(m_MainSocket);
m_MainSocket = INVALID_SOCKET;
return ;
} /* //将bitmap数据写入文件里 创建一个bmp图像文件
strcpy(strFilePath,"E://hehe.bmp");//strFilePath类型为char strFilePath[111] ;
if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); //HANDLE hFile;
hFile = CreateFile(strFilePath , GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);//创建位图文件
DWORD dwWritten;
WriteFile(hFile, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); // 写入位图文件头
WriteFile(hFile, (LPSTR)pData, bmfHdr.bfSize, &dwWritten, NULL);// 写入位图文件其余内容
CloseHandle(hFile);
*/
Invalidate(TRUE);//发送重绘系统消息 Sleep(10);
}
}
上面的代码收到了bmp图像的信息保存到了pData中!
2 以下利用pData中的信息创建bmp图像的句柄
HBITMAP CScreenDlg::GetBitmapFromData()
{
HBITMAP hBitmap;
PBITMAPINFO lpBmpInfo; //位图信息 lpBmpInfo = PBITMAPINFO(pData); HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
// 创建DDB位图
hBitmap = CreateDIBitmap(
hDC,
&lpBmpInfo->bmiHeader,
CBM_INIT,
pData + m_InfoSize,
lpBmpInfo,
DIB_RGB_COLORS) ; DeleteDC(hDC); return hBitmap;
}
关于DDB DIB 的差别 请參考本人博客MFC分栏 或者百度
3 以下为调用Invalidate后 重画图像 以下使用双缓冲技术 关于此技术參考以下文章中的第五条
http://blog.csdn.net/hnust_xiehonghao/article/details/37741307
以下的函数是在类向导中加入的消息响应函数 用来擦除窗体的
BOOL CScreenDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此加入消息处理程序代码和/或调用默认值 //双缓存防止闪烁
CDC DCmem;
DCmem.CreateCompatibleDC(pDC);
CBitmap bitmap;
//下面也能够从一个文件里加载bitmap图像 如凝视中的语句
bitmap.m_hObject = GetBitmapFromData();//(HBITMAP)LoadImage(AfxGetInstanceHandle(), strFilePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
CRect rect;
GetClientRect(&rect);
CBitmap *pOldBit=DCmem.SelectObject(&bitmap);
//DCmem.FillSolidRect(rect,pDC->GetBkColor());//按原来背景填充客户区,不然会是黑色
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&DCmem,0,0,SRCCOPY);
DCmem.DeleteDC(); //删除DC
bitmap.DeleteObject(); //删除位图
//return CDialog::OnEraseBkgnd(pDC); return TRUE;
}
by hnust_xiehonghao
远程控制编写之屏幕传输 MFC实现 屏幕截图 发送bmp数据 显示bmp图像的更多相关文章
- MFC中在picture control中显示CBitmap图像的方法
CStatic *pStatic1 = (CStatic *)GetDlgItem(IDC__IMAGE_STATIC2); CBitmap cbmp; cbmp.LoadBitmap(MAKEINT ...
- MFC对话框显示BMP图片
1.MFC对话框显示BMP图片我们先从简单的开始吧.先分一个类: (一) 非动态显示图片(即图片先通过资源管理器载入,有一个固定ID) (二) 动态载入图片(即只需要在程序中指定图片的路径即可载入) ...
- MFC对话框中显示BMP,JPG图片
//************************************ // 方法说明: 显示JPG和GIF.BMP图片 // 参数说明: CDC * pDC 设 ...
- MFC中显示 .bmp格式的位图
最近在看VisualC++ 图像处理的书籍,表示一直在从基础做起,今天就记录一个简单功能的实现,显示.bmp格式的位图. 首先需要理解的是窗口创建的过程包括两个步骤:首先擦除窗口的背景,然后在对窗口进 ...
- 程序一 用记事本建立文件src.dat,其中存放若干字符。编写程序,从文件src.dat中读取数据,统计其中的大写字母、小写字母、数字、其它字符的个数,并将这些数据写入到文件test.dat中。
用记事本建立文件src.dat,其中存放若干字符.编写程序,从文件src.dat中读取数据,统计其中的大写字母.小写字母.数字.其它字符的个数,并将这些数据写入到文件test.dat中. #inclu ...
- 解决微信小程序使用wxcharts在屏幕不固定问题-开发工具里也显示好了布局,为啥到真机就是乱的
解决微信小程序使用wxcharts在屏幕不固定问题-开发工具里也显示好了布局,为啥到真机就是乱的 .chart{ width: 100%; text-align: center; } .canvas{ ...
- MFC显示bmp图像
有了bmp文件读写的基础,我们就能够開始用MFC显示BMP图片了. 在这里,事实上微软为我们提供了一个实现bmp文件显示的框架,名叫diblook,我们能够先下载下来看看. 以下上链接:DIBLOOK ...
- 浏览器在一次 HTTP 请求中,需要传输一个 4097 字节的文本数据给服务端,可以采用那些方式?
浏览器在一次 HTTP 请求中,需要传输一个 4097 字节的文本数据给服务端,可以采用那些方式? 存入 IndexdDB 写入 COOKIE 放在 URL 参数 写入 Session 使用 POST ...
- WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片
原文:WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片 我们知道,在 WPF 中的坐标单位不是屏幕像素单位,所以如果需要知道某个控件的像素尺寸,以便做一些与屏幕像素尺寸相关 ...
随机推荐
- 为什么 Linux Mint 比 Ubuntu好?
Linux Mint由Linux Mint Team团队于2006年开始发行,是一份基于Debian和Ubuntu的Linux发行版.其目标是提供一种更完整的即刻可用体验,这包括提供浏览器插件.多媒体 ...
- 五个项目管理学习笔记.沟通技巧II
两.通信模型:沟通的双向过程 沟通模型: 编 码---------------->信息-----------------> 解码&歧义 发送者 ...
- ABP应用层——应用服务(Application services)
ABP应用层——应用服务(Application services) 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之15.ABP应用层——应用服务(Applic ...
- 产品 线上 保持 和 支持 服务 (Support and maintenance solutions)
Maintenance and support are the key factors for the smooth functioning of ERP solutions. ERP mainten ...
- c++指针存储应用程序和释放内存的问题
C++中指针在new和delete操作的时候对内存堆都做了些什么呢.下面解: 1.指针的new操作: 指针在new之后,会在内存堆中分配一个空间.而指针中存放的是这个空间的地址.如: void mai ...
- VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线
VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线 Visual Studio Visual Studio 2015 下载 VS2015新功能列表 ‘ Visual ...
- 使用CNN(convolutional neural nets)关键的一点是检测到的面部教程(四):学习率,学习潜能,dropout
第七部分 让 学习率 和 学习潜能 随时间的变化 光训练就花了一个小时的时间.等结果并非一个令人心情愉快的事情.这一部分.我们将讨论将两个技巧结合让网络训练的更快! 直觉上的解决的方法是,開始训练时取 ...
- MAC 配置--Tomcat服务器
1. 下载tomcat版本(tar.gz) 到 apache官方主页 下载 Mac 版本的完整 tar.gz文件包.(问公司后台,是Tomcat 6.0/7.0/8.0版本?) 解压拷贝到 /Libr ...
- [使用]Git--命令行
如何利用终端命令将文件上传到github远程服务器 (1) git status 命令查看下状态. (2) git pull 更新代码,确保代码是库上最新代码,防止覆盖其他人的提交. (3) git ...
- 算法 & 分析 (收集)
算法一:快速排序算法 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通 ...