远程控制编写之屏幕传输 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 中的坐标单位不是屏幕像素单位,所以如果需要知道某个控件的像素尺寸,以便做一些与屏幕像素尺寸相关 ...
 
随机推荐
- C#+Mapxtreme 实现一些GIS系统基本的功能
			
此程序包括了mapxtreme地图相关基本功能的演示其中包括 鹰眼地图,图层控制,发达,缩小,平移地图,地图模糊查询,中点工具,距离测量工具,面积测量工具,图元信息查看工具.适合于企业级开发,可以为您 ...
 - 熟人UML
			
UML,全名Unified Modeling Language.模语言.它是软件和系统开发的标准建模语言.主要是以图形的方式对系统进行分析.设计. 同一时候,UML不是一个程序设计语言,也不是一个形式 ...
 - ExtJS4 动态生成grid出口excel(纯粹的接待)
			
搜索相当长的时间,寻找一些样本,因为我刚开始学习的原因,大多数人不知道怎么用.. 他曾在源代码.搞到现在终于实现了主下载.. 表的采集格不重复下载一个小BUG,一个使用grid初始化发生的BUG 以下 ...
 - (大数据工程师学习路径)第一步 Linux 基础入门----正则表达式基础
			
介绍 虽然我们这一节的标题是正则表达式,但实际这一节只是介绍grep,sed,awk这三个命令,而正则表达式作为这三个命令的一种使用方式(命令输出中可以包含正则表达式).正则表达式本身的内容很多,要把 ...
 - IP地址和子网掩码
			
A分类IP住址 在第一个领域值规模:0-127 默认子网掩码:255.0.0.0 B分类IP就拿地址的第一个字段值范围:128-191 默认的子网掩码255.255.0.0 C类IP地址的第一个字 ...
 - [MFC]获取一些用户文件夹
			
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请注明出处) 在window7中.进入命令行cmd模式,输入set到多个系统文件夹定义: 比如: Wi ...
 - 查询(Query)和标识(Identify)
			
查询(Query)和标识(Identify) 相关文章:RESTful API URI 设计的一些总结. 问题场景:删除一个资源(Resources),URI 该如何设计? 应用示例:删除名称为 iP ...
 - leetcode 刷道题 70 earch Insert Position  二进制搜索插入位置
			
Given a sorted array and a target value, return the index if the target is found. If not, return the ...
 - seaJs组建库
			
seaJs组建库的使用 原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以 ...
 - Hadoop它——跑start-all.sh时间namenode不启动
			
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46353211 近期遇到了一个问题,运行start-all.sh的时候发现JPS一下 ...