远程控制编写之屏幕传输  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图像的更多相关文章

  1. MFC中在picture control中显示CBitmap图像的方法

    CStatic *pStatic1 = (CStatic *)GetDlgItem(IDC__IMAGE_STATIC2); CBitmap cbmp; cbmp.LoadBitmap(MAKEINT ...

  2. MFC对话框显示BMP图片

    1.MFC对话框显示BMP图片我们先从简单的开始吧.先分一个类: (一) 非动态显示图片(即图片先通过资源管理器载入,有一个固定ID) (二) 动态载入图片(即只需要在程序中指定图片的路径即可载入) ...

  3. MFC对话框中显示BMP,JPG图片

    //************************************ // 方法说明:    显示JPG和GIF.BMP图片 // 参数说明:    CDC * pDC           设 ...

  4. MFC中显示 .bmp格式的位图

    最近在看VisualC++ 图像处理的书籍,表示一直在从基础做起,今天就记录一个简单功能的实现,显示.bmp格式的位图. 首先需要理解的是窗口创建的过程包括两个步骤:首先擦除窗口的背景,然后在对窗口进 ...

  5. 程序一 用记事本建立文件src.dat,其中存放若干字符。编写程序,从文件src.dat中读取数据,统计其中的大写字母、小写字母、数字、其它字符的个数,并将这些数据写入到文件test.dat中。

    用记事本建立文件src.dat,其中存放若干字符.编写程序,从文件src.dat中读取数据,统计其中的大写字母.小写字母.数字.其它字符的个数,并将这些数据写入到文件test.dat中. #inclu ...

  6. 解决微信小程序使用wxcharts在屏幕不固定问题-开发工具里也显示好了布局,为啥到真机就是乱的

    解决微信小程序使用wxcharts在屏幕不固定问题-开发工具里也显示好了布局,为啥到真机就是乱的 .chart{ width: 100%; text-align: center; } .canvas{ ...

  7. MFC显示bmp图像

    有了bmp文件读写的基础,我们就能够開始用MFC显示BMP图片了. 在这里,事实上微软为我们提供了一个实现bmp文件显示的框架,名叫diblook,我们能够先下载下来看看. 以下上链接:DIBLOOK ...

  8. 浏览器在一次 HTTP 请求中,需要传输一个 4097 字节的文本数据给服务端,可以采用那些方式?

    浏览器在一次 HTTP 请求中,需要传输一个 4097 字节的文本数据给服务端,可以采用那些方式? 存入 IndexdDB 写入 COOKIE 放在 URL 参数 写入 Session 使用 POST ...

  9. WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片

    原文:WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片 我们知道,在 WPF 中的坐标单位不是屏幕像素单位,所以如果需要知道某个控件的像素尺寸,以便做一些与屏幕像素尺寸相关 ...

随机推荐

  1. 据序和中序序列或者也许为了一个二进制序列,恢复二进制和打印图像(c语言)

    首先要预购和序,以恢复它: 1.首先,我们使用的是递归的方式来完成 2.递归的最小单位:一个空的树和书的前言和第一序.该序列的第一个元素是树的第一序列根,调用这种方法 3.递归的终止条件是.当这棵树的 ...

  2. DWR入门的例子(一个)

    DWR(Direct Web Remoting)是WEB远程调用框架.使用这种框架使AJAX发展至今已成为非常easy.使用DWR能client利用JavaScript直接调用服务端的Java方法并返 ...

  3. 数据库性能监测工具——SQL Server Profiler

    使用SQL Server Profiler 进行sql监控需要一些设置: 其他的就是进行分析了~ 清除SQL SERVER缓存 常用的方法: DBCC DROPCLEANBUFFERS 从缓冲池中删除 ...

  4. react.js 从零开始(二)组件的生命周期

    什么是生命周期? 组件本质上是一个状态机,输入确定,输出一定确定. 当状态改变的时候 会触发不同的钩子函数,可以让开发者做出响应.. 一个组件的生命周期可以概括为 初始化:状态下 可以自定义的函数 g ...

  5. thoughtworks笔试整理

    笔试了,时间1个半小时.没想到居然有7/10是开放性问题.大意例如以下:1.为什么选择增加ThoughtWorks.200字以内,不能用"interesting"."ch ...

  6. HDOJ 3037 Saving Beans

    如果您有n+1树,文章n+1埋不足一棵树m种子,法国隔C[n+m][m] 大量的组合,以取mod使用Lucas定理: Lucas(n,m,p) = C[n%p][m%p] × Lucas(n/p,m/ ...

  7. 写手Remoting测试工具

    基于.NET开发分布式系统.经经常使用到Remoting技术.在測试驱动开发流行的今天.假设针对分布式系统中的每一个Remoting接口的每一个方法都要写具体的測试脚本,无疑很浪费时间.所以,我想写一 ...

  8. C#:winform项目在win7,xp32位和64位都能执行

    vs中项目配置管理器活动解决方式平台选择X86平台.

  9. hdu Hat's Tea

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1288 去买茶,需要正好的钱才行,另外花的钱的个数最多  其实是一个简单的贪心问题,小的多取一点,多的少 ...

  10. 基于Servlet、JSP、JDBC、MySQL登录模块(包括使用的过滤器和配置)

    遇见前文的注冊模块,本篇是登录模块.主要包含登录主界面,和登录相关编写的LoginAction.LoginDao和LoginService.以及配置的Filter.以下按逻辑顺序记录具体过程和代码: ...