使用Winsock,GetDIBits和SetDiBits进行位图传输

时间:2010-08-22 02:36:26

标签: c++ bitmap winsock getdibits

我开始在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;
      }
    }
  }
}

我在这里介绍的代码有点长,因为我不确定可能有什么用处。提前谢谢。

2 个答案:

答案 0 :(得分:0)

我分配的字节数不足以存储数据包大小,现在我增加了这个数字。 ; - )

答案 1 :(得分:0)

发布代码的问题在于,只有两个BYTE s([data + 1]和[data + 2])分配给总传输数据长度。两个字节最多可处理64K数据,图像可以轻松超出,i值不会检查溢出。

要使代码片段恢复生机,需要在那里添加位以便它们可以保持实际长度。也就是说,应该有一个或两个额外的字节来使数据包长度为24或32位。