-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathScreenManage.cpp
More file actions
375 lines (317 loc) · 10.7 KB
/
ScreenManage.cpp
File metadata and controls
375 lines (317 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#include "ScreenManage.h"
#include <stdio.h>
#include "ConnectInfo.h"
#include "./zlib.h"
#pragma comment(lib,"./zlib.lib") //图象无损数据压缩使用zlib库函数
int g_ScreenBits;//图像的位数
int end = 0;
CScreenManage::CScreenManage(void)
{
g_ScreenBits = 8;
}
CScreenManage::~CScreenManage(void)
{
}
DWORD __stdcall ScreenManageThread(LPVOID lparam)//线程处理屏幕传输
{
/* DWORD *pParam = (DWORD *)lparam;
CScreenManage Screen;
Screen.m_MainSocket = *pParam;
SOCKET MainSocket = Screen.m_MainSocket;
*/
end = 0;
struct sockaddr_in LocalAddr;
LocalAddr.sin_family=AF_INET;
LocalAddr.sin_port = htons(ConnectInfo::getConnectInfo()->port);
LocalAddr.sin_addr.S_un.S_addr= inet_addr(ConnectInfo::getConnectInfo()->ipAddress);
SOCKET MainSocket = socket(AF_INET, SOCK_STREAM, 0);//重新建立一个专门的socket和客户端进行交互
if(connect(MainSocket,(PSOCKADDR)&LocalAddr,sizeof(LocalAddr)) == SOCKET_ERROR)
{
closesocket(MainSocket);
return 0;//connect error
}
//================================================================================
MsgHead msgHead;
char *chBuffer = new char[1536 * 1024]; //数据交换区 1.5MB
//send socket type
msgHead.dwCmd = CMD_SCREENDLG_SHOW;
msgHead.dwSize = 0;
if(!SendMsg(MainSocket, NULL, &msgHead))
{
if(chBuffer != NULL)
{
delete []chBuffer;
chBuffer = NULL;
}
return 0;
}
// ::MessageBox(NULL, "第一个while(1)前没有崩溃", "DD", MB_OK);
while(1)
{
//接收命令
if(!RecvMsg(MainSocket, chBuffer, &msgHead))
break;
//解析命令
switch(msgHead.dwCmd)
{
case CMD_GETFIRST_SCREEN://请求获取屏幕信息
{
//::MessageBox(NULL, "正在创建bmp图像","",MB_OK);
//以下为屏幕信息的获取 ,一直获取并发送。
DWORD *pDWORD = new DWORD;
*pDWORD = MainSocket;
g_ScreenBits = msgHead.dwExtend1;
CreateThread(NULL, NULL, SendScreen, pDWORD, NULL, NULL);
//delete pDWORD;
break;
}
case CMD_CHANGE_SCREEN_BITS:
{
g_ScreenBits = msgHead.dwExtend1;
break;
}
case 88:
{
end = 1;
if(chBuffer != NULL)
delete[] chBuffer;
closesocket(MainSocket);
return 0;
break;
}
default:
{
::MessageBox(NULL, "不好意思,screen收到不能理解消息","", MB_OK);
break;
}
}
//char str[111];
//if(!SendMsg(MainSocket, chBuffer, &msgHead))//MSGHEAD 为7
// break;
}
end = 1;
if(chBuffer != NULL)
delete[] chBuffer;
closesocket(MainSocket);
return 0;
}
DWORD __stdcall SendScreen(LPVOID lparam)//线程处理屏幕传输
{
DWORD *pParam = (DWORD *)lparam;
SOCKET MainSocket =*pParam;
DWORD dwLastSend;
int ScreenBits = 0;
BYTE * pLastData = new BYTE [2048 * 1536 *3 * 2];//为分辨率2048 * 1536 且位为24位即3个字节的大小的 2倍
BYTE * pChanged = new BYTE [2048 *1536 * 3 * 2];
HWND hWnd = GetDesktopWindow();//获得屏幕的HWND.
HDC hScreenDC = GetDC(hWnd); //获得屏幕的HDC.
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);
HDC MemDC = CreateCompatibleDC(hScreenDC);//当前屏幕的DC
BOOL IsFirst = TRUE;
memset(pLastData, 0, 2048 * 1536 *3 * 2);
while(1)
{
if( end == 1) break;
if(ScreenBits != g_ScreenBits)
{
ScreenBits = g_ScreenBits;
IsFirst = TRUE;
}
HWND hWnd = GetDesktopWindow();
GetWindowRect(hWnd,&rect);
int ChangedSize = 0;//改变了的数据的大小
//将屏幕图像传送到MemDC中的位图。
HGDIOBJ hOldBMP = ::SelectObject(MemDC,hBitmap);
::BitBlt(MemDC,0,0,screensize.cx,screensize.cy,hScreenDC,rect.left,rect.top,SRCCOPY);
::SelectObject(MemDC,hOldBMP);
/*********将位图INFOHEADER ,(调色板),图像数据 放入pData***********************/
dwLastSend = GetTickCount();
HDC hDC =::CreateDC("DISPLAY",NULL,NULL,NULL);
int iBits = ::GetDeviceCaps(hDC, BITSPIXEL) * ::GetDeviceCaps(hDC, PLANES);//当前分辨率下每个像素所占字节数
::DeleteDC(hDC);
DWORD dwPaletteSize=0; //调色板大小, 位图中像素字节大小
if (ScreenBits<= 8)
dwPaletteSize = (1 << ScreenBits) * 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 = ScreenBits;
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 * ScreenBits+31)/32) * 4 * bm.bmHeight;//位图数据的大小
int DataPalInfoSize = dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER);//位图除了FILEHDEAR外 其它3部分大小的和
// HANDLE hDib = ::GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); //1为位图内容分配内存
LPBITMAPINFOHEADER pData = (LPBITMAPINFOHEADER)new BYTE [DataPalInfoSize]; //2
//LPBITMAPINFOHEADER pData = (LPBITMAPINFOHEADER)GlobalLock(hDib); //new BYTE [DataPalInfoSize];//3
*pData = bi;//2
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)pData + sizeof(BITMAPINFOHEADER)+dwPaletteSize,(LPBITMAPINFO)&bi,DIB_RGB_COLORS);// 获取该调色板下新的像素值
::GetDIBits(hDC, hBitmap, 0, (UINT) bm.bmHeight,(LPSTR)pData + sizeof(BITMAPINFOHEADER)+dwPaletteSize,(BITMAPINFO*)pData,DIB_RGB_COLORS);// 获取该调色板下新的像素值
//将文件信息头保存到bi
bi = *pData;
int DataSize = bi.biSizeImage;//位图中数据的字节数 仅仅是数据
//memcpy(pData, &bi, sizeof(bi));
if (hOldPal)//恢复调色板
{
SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
//(BITMAPINFO*)pData
/****************************比较得到变化的数据***********************************/
BYTE *p1, *p2;
int OneLineByte = DataSize / bm.bmHeight; //一行的字节数
BYTE *NowScreenOff = (BYTE*)pData + sizeof(BITMAPINFOHEADER)+dwPaletteSize;
BYTE *LastScreenOff = pLastData + sizeof(BITMAPINFOHEADER)+dwPaletteSize;
if(!IsFirst)
{
rect.top = 99999; rect.left = 99999; rect.bottom = -99999; rect.right = -99999;
for(int i = 0; i< bm.bmHeight ; i += 5)//没相隔5行 检测一行数据 注意这里单位是像素
{
for(int j = 0; j < OneLineByte; j += 2)//bm.bmWidthBytes一行的字节数
{
p1 = (BYTE*)(NowScreenOff + i * OneLineByte + j);
p2 = (BYTE*)(LastScreenOff + i * OneLineByte + j);
if(*p1 != *p2)
{
if(rect.top > i)
{
rect.top = i;
rect.top = rect.top > 5 ? (rect.top - 5) : 0;
}
if(rect.bottom < i)
{
rect.bottom = i;
if( i+ 5 >= bm.bmHeight) rect.bottom = bm.bmHeight -1;
}
//j / (g_ScreenBits/8) 为j字节所在的像素点的编号 left应稍微靠前些 让差异矩阵稍微大点更精确 所以-2
if(rect.left > (j-2) * 8 /ScreenBits )//其实是(j-2) / (ScreenBits/8))
{
rect.left = (j-2) * 8 /ScreenBits;
if(rect.left < 0) rect.left = 0;
}
//left稍微靠后些好 所以不减2 而且加1个像素 注意是像素 rect里存的是像素
if(rect.right < j * 8 /ScreenBits + 1)//其实是j/(ScreenBits/8) +1)
{
rect.right = j * 8 /ScreenBits + 1;
if(rect.right >= bm.bmWidth) rect.right = bm.bmWidth - 1;
}
}
}
}
//上面计算的不是很精准 在下面这几句稍微扩大下范围
rect.top = rect.top - 5;
if(rect.top < 0) rect.top =0;
rect.bottom += 5;
if(rect.bottom >= bm.bmHeight) rect.bottom = bm.bmHeight -1;
rect.left -= 5;
if(rect.left < 0) rect.left =0;
rect.right += 5;
if(rect.right >= bm.bmWidth) rect.right = bm.bmWidth - 1;
//保存bmp信息头 调色板 以及 变化区域的大小和数据到pChanged
memcpy(pChanged, pData, sizeof(BITMAPINFOHEADER)+dwPaletteSize);
ChangedSize = sizeof(BITMAPINFOHEADER)+dwPaletteSize;
memcpy(pChanged + ChangedSize, &rect, sizeof(rect));
ChangedSize += sizeof(rect);
BYTE *Dst, *Src;
int BitSz;
BitSz = (rect.right - rect.left + 1) * ScreenBits / 8;
for(int i = rect.top; i <= rect.bottom ; i++)
{
Dst = pChanged + ChangedSize;
Src = NowScreenOff + i * OneLineByte + rect.left * ScreenBits / 8;
memcpy(Dst, Src, BitSz);//保存每一行变化的数据
ChangedSize += BitSz;
}
//一切处理完毕后 保存此帧的图像用于与下一帧进行比较
memcpy(pLastData, pData, DataPalInfoSize); //将数据保存到pLastData
}
/*************************发送信息******************************/
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;
//压缩到pDataCompressd
DWORD CompressdSize;
BYTE* pDataCompressd;
if(!IsFirst)
{
CompressdSize = compressBound(ChangedSize); // 压缩后的长度是不会超过CompressdSize
pDataCompressd = new BYTE [CompressdSize];
pDataCompressd[0] = IsFirst;
compress(pDataCompressd + 1, &CompressdSize, (BYTE*)pChanged, ChangedSize);
}
else
{
CompressdSize = compressBound(DataPalInfoSize); // 压缩后的长度是不会超过CompressdSize
pDataCompressd = new BYTE [CompressdSize];
pDataCompressd[0] = IsFirst;
compress(pDataCompressd + 1, &CompressdSize, (BYTE*)pData, DataPalInfoSize);
}
MsgHead MsgSend;
MsgSend.dwCmd = CMD_SCREEN_TO_SHOW;
MsgSend.dwSize = CompressdSize + 1;
MsgSend.dwExtend1 = bmfHdr.bfSize;
MsgSend.dwExtend2 = bmfHdr.bfOffBits;
if(!SendMsg(MainSocket, (char*)pDataCompressd, &MsgSend))
{
::DeleteObject(MemDC);
::ReleaseDC(hWnd,hScreenDC);
DeleteObject(hBitmap);
if(pLastData != NULL)
{
delete [] pLastData; pLastData = NULL;
}
if(pDataCompressd != NULL){
delete [] pDataCompressd; pDataCompressd = NULL;
}
if(pData != NULL){
delete [] pData; pData = NULL;
}
if(pChanged != NULL){
delete[] pChanged; pChanged = NULL;
}
return 0;
}
IsFirst = FALSE;
if(pDataCompressd != NULL){
delete [] pDataCompressd; pDataCompressd = NULL;
}
if(pData != NULL){
delete[] pData; pData = NULL;
}
if ((GetTickCount() - dwLastSend) < 110)
Sleep(100);
}
if(pLastData != NULL)
delete [] pLastData;
if(pChanged != NULL)
delete [] pChanged;
return 0;
}