远程控制编写之屏幕传输 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 中的坐标单位不是屏幕像素单位,所以如果需要知道某个控件的像素尺寸,以便做一些与屏幕像素尺寸相关 ...
随机推荐
- android sdk linux 文本 64 位置
android sdk linux 64 之前获得模.现在补上一,然后,小伙伴们下载 版权声明:本文博主原创文章,博客,未经同意不得转载.
- HDU 1195 Open the Lock (双宽搜索)
意甲冠军:给你一个初始4数字和目标4数字,当被问及最初的目标转换为数字后,. 变换规则:每一个数字能够加1(9+1=1)或减1(1-1=9),或交换相邻的数字(最左和最右不是相邻的). 双向广搜:分别 ...
- 原子操作(atomic operation)
深入分析Volatile的实现原理 引言 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共 ...
- 【iOS发展-28】制造业UITabBarController标记控制器、定制UITabBarItem文字图像6途径和More评论
一个.一个简单的制作过程(实际工程中不建议这样的方式,不要只展示所用原理的理解) 在AppDelegate.m在: - (BOOL)application:(UIApplication *)appli ...
- [TroubleShooting] The remote copy of database xx has not been rolled forward to a point in time
Steps: 1. backup database TestMirror on Pricipal server 2. backup database log of TestMirror on Pric ...
- 批处理命令 For循环命令具体解释!
批处理for命令具体解释FOR这条命令基本上都被用来处理文本,但还有其它一些好用的功能!看看他的基本格式(这里我引用的是批处理中的格式,直接在命令行仅仅须要一个%号)FOR 參数 %%变量名 IN ( ...
- from声明
在整个应用程序,只有三行声明.这是最短单WIN32应用,但它的功能是非常有限,简单地显示一个消息框,示出来,其他什么事情也没有做.以下就来分析这三行语句了.别小看这三行语句.其实是隐藏着非常多知识点在 ...
- Object.extend
原文:[转载]Object.extend Object.extend = function (destination, source) { for ( var property in source) ...
- WIN phone 8.1 SDK 坑遇到 Hyper-V
先声明! 仅限WIN操作系统下 ! 事实上 Hyper-V 就是个虚拟机 ,是微软弄出来和 VM 争市场的.(所以Hyper-V中你随便安装什么系统都行,可是 Hyper-V必须 安装在WIN下) ...
- Android_显示器本身被卸载应用程序
1.经jni实现功能 //LOG宏定义 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg) #defi ...