使用 Winsock、GetDIBits 和 SetDiBits 进行位图传输 [关闭]
Posted
技术标签:
【中文标题】使用 Winsock、GetDIBits 和 SetDiBits 进行位图传输 [关闭]【英文标题】:Bitmap transfer using Winsock, GetDIBits and SetDiBits [closed] 【发布时间】:2010-08-22 02:36:25 【问题描述】:我开始研究类似于 C++ 中的远程控制应用程序的东西。我希望将特定窗口的屏幕截图传输到另一台 PC 并在窗口中显示。 GetDIBits 和 SetDIBits 函数都成功了,建立连接,发送数据,但是另一边没有出现图像,只是一片黑。
这是我的发送代码:
void GetScreenData(BITMAPINFO* bi, BYTE* buf) //gets the bitmap data
HBITMAP hBitmap;
BITMAP Bitmap;
RECT r;
HDC ActiveDC = GetDC(hActive);
HDC CopyDC = CreateCompatibleDC(ActiveDC);
GetWindowRect(hActive, &r);
int scrWidth = r.right-r.left;
int scrHeight = r.bottom-r.top;
hBitmap = CreateCompatibleBitmap(ActiveDC, scrWidth, scrHeight);
SelectObject(CopyDC, hBitmap);
BitBlt(CopyDC, 0, 0, scrWidth, scrHeight, ActiveDC, 0, 0, SRCCOPY);
GetObject(hBitmap, sizeof(BITMAP), &Bitmap);
int cClrBits = Bitmap.bmPlanes*Bitmap.bmBitsPixel;
memset(bi, 0, sizeof(BITMAPINFO));
bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi->bmiHeader.biWidth = Bitmap.bmWidth;
bi->bmiHeader.biHeight = Bitmap.bmHeight;
bi->bmiHeader.biPlanes = Bitmap.bmPlanes;
bi->bmiHeader.biBitCount = Bitmap.bmBitsPixel;
if(cClrBits<24)
bi->bmiHeader.biClrUsed = (1<<cClrBits);
bi->bmiHeader.biCompression = BI_RGB;
bi->bmiHeader.biSizeImage = ((bi->bmiHeader.biWidth * cClrBits +31) & ~31)/8*bi->bmiHeader.biHeight;
int i = GetDIBits(CopyDC, hBitmap, 0, scrHeight, buf, bi, DIB_RGB_COLORS);
printf("GetDIBits returned %i\n", i);
ReleaseDC(hActive, ActiveDC);
DeleteDC(CopyDC);
DWORD WINAPI SendImage(LPVOID param) //sends the bitmap data
BITMAPINFO bi;
BYTE* data = new BYTE[256*256*256];
BYTE* buf = new BYTE[256*256*256];
BYTE *packetsize1, *packetsize2;
int biSize = sizeof(BITMAPINFO);
int i, clocks, oldclocks=0;
while(true)
clocks=clock();
if((clocks-oldclocks)*CLOCKS_PER_SEC<0.1)
continue;
oldclocks=clocks;
if(bConnected)
GetScreenData(&bi, buf);
i=0;
data[i++]=3;
packetsize1=&data[i++];
packetsize2=&data[i++];
memcpy(data+i, &bi, biSize);
i+=biSize;
memcpy(data+i, buf, bi.bmiHeader.biSizeImage);
printf("Sending image...\n");
i+=bi.bmiHeader.biSizeImage;
*packetsize1=int(i/256);
*packetsize2=int(i%256);
send(s, (char*)data, i, 0);
这里是接收方:
void DrawScreen(HDC hdc) //called from windows message WM_PAINT
HGDIOBJ hobj;
hobj = SelectObject(RemoteDC, hRemoteBitmap);
BitBlt(hdc, 0, 0, scrWidth, scrHeight, RemoteDC, 0, 0, SRCCOPY);
SelectObject(hdc, hobj);
DWORD WINAPI RecvData(LPVOID param)
BYTE* data = new BYTE[256*256*256];
int packetsize, num;
int newWidth, newHeight;
int recvimgsize=0;
bool bAwaitingImage = false;
while(true)
if(bConnected)
num=recv(s, (char*)data, 3, 0);
if(num>0)
packetsize = data[1]*256+data[2];
num=recv(s, (char*)(data+3), packetsize-3, 0);
if(num>0)
switch(data[0])
case 2: //received information about window size (image size)
newWidth = data[3]*256+data[4];
newHeight = data[5]*256+data[6];
if(newHeight!=scrHeight || newWidth!=scrWidth)
scrWidth = newWidth;
scrHeight = newHeight;
RECT r;
GetWindowRect(hwnd, &r);
SetWindowPos(hwnd, NULL, r.left, r.top, scrWidth, scrHeight, 0);
HDC ThisDC = GetDC(hwnd);
DeleteDC(RemoteDC);
RemoteDC = CreateCompatibleDC(ThisDC);
DeleteObject(hRemoteBitmap);
hRemoteBitmap = CreateCompatibleBitmap(ThisDC, scrWidth, scrHeight);
SelectObject(RemoteDC, hRemoteBitmap);
ReleaseDC(hwnd, ThisDC);
break;
case 3:
BITMAPINFO bi;
HBITMAP hBitmap;
int biSize = sizeof(BITMAPINFO);
memcpy(&bi, data+3, biSize);
SetDIBits(RemoteDC, hRemoteBitmap, 0, scrHeight, data+biSize+3, &bi, DIB_RGB_COLORS);
InvalidateRect(hwnd, NULL, false);
break;
continue;
if(num==0)
//connection closed
bConnected=false;
else
//error
bConnected=false;
我在这里提供的代码有点长,因为我不确定什么可能有用。提前谢谢你。
【问题讨论】:
您是否验证过您的解码和显示代码,而无需先通过网络发送? 刚刚做了(不知何故我以前没有想到)。它按预期工作。一定是转账本身有问题…… 很好,这消除了很大一部分问题。不能保证任何事情,但我会看看网络方面是否有什么让我兴奋的事情:) 非常感谢。 ;-) 我意识到这可能是因为通过一次 recv 调用,我没有获得所有数据,但是在进行了一个循环收集数据直到它获得数据包大小字节之后,它仍然是相同的。 (而且我还注意到,在发送了一定数量的图像后,它就停止发送它们了——而且我用 printscreen 制作的每张截图都是黑白的负片,直到我关闭应用程序......奇怪的东西) 这与您的问题没有直接关系,但您可能应该在那里为您的缓冲区调用 delete[]。 【参考方案1】:我分配的字节数不足来存储数据包大小,现在我增加了这个数字。 ;-)
【讨论】:
【参考方案2】:发布代码的问题在于,只有两个BYTE
s([data+1] 和 [data+2])分配给总传输数据长度。两个字节处理高达 64K 的数据和图像很容易超出此范围,i
值不检查溢出。
要使代码 sn-p 恢复活力,需要在其中添加位,以便它们可以保持真实长度。也就是说,应该有一个或两个额外的字节来使数据包长度为 24 或 32 位值。
【讨论】:
以上是关于使用 Winsock、GetDIBits 和 SetDiBits 进行位图传输 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
处理 GetDIBits() 返回的像素缓冲区的正确方法是啥?