3

I started working on something similar to a remote control application in c++. I wish to transfer a particular window's screenshot to another PC and display it in a window. Both GetDIBits and SetDIBits functions succeed, the connection is established, the data is sent, yet the image does not appear on the other side, just blackness.

Here's my sending code:

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);
    }
  }
}

And here is the receiving side:

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;
      }
    }
  }
}

The code I presented here is a bit long, because I wasn't sure what might be of use. Thank you in advance.

Neo_b
  • 231
  • 5
  • 9
  • 1
    Have you verified your decoding and display code without sending it over the wire first? – Arnold Spence Aug 22 '10 at 02:50
  • 1
    Just did now (somehow I didn't think of that before). It works as expected. Must be something wrong with the transfer itself... – Neo_b Aug 22 '10 at 03:39
  • Good, that eliminates a big part of the problem. Can't promise anything but I'll see if anything jumps out at me with the networking stuff :) – Arnold Spence Aug 22 '10 at 03:50
  • Thanks a lot. ;-) I realized that it might be because with a single recv call, I do not get all the data, but after making a loop that collects data until it gets packetsize bytes, it's still the same. (and I also noticed that after having sent a certain amount of images, it ceases to send them - and every screenshot that I make with printscreen is a negative black & white until I turn the application off... weird stuff) – Neo_b Aug 22 '10 at 04:03
  • This has nothing to do directly with your problem but you should probably get some calls to delete[] in there for your buffers. – Arnold Spence Aug 22 '10 at 04:15
  • In SendImage(), how do you get out of your while loop? – Arnold Spence Aug 22 '10 at 04:35
  • I do not, it's meant to be executing indefinately. It terminates along with the program. Also, I fixed the weird stuff by deleting the created bitmap object in GetScreenData(). Yes, you're right, I've forgotten about using delete[], I was thinking about polishing the code as soon as it's functional. – Neo_b Aug 22 '10 at 05:54
  • Argh, such a stupid mistake... I assigned two bytes for the packet size, which allows max 65535-byte packet size. Now it's changed to three bytes, which should be sufficient. Works perfectly. Thanks for your help though! ;-) – Neo_b Aug 22 '10 at 06:44
  • @Neo_b: If you managed to solve it yourself, either create an answer yourself and accept it or remove the question (I prefer the first one, but it's up to you :)) – default Sep 05 '10 at 14:04

2 Answers2

0

The problem with posted code is that that there were two BYTEs only ([data+1] and [data+2]) allocated for the total transfer data length. Two bytes handle up to 64K of data and images easily go beyond that, i value is not checked for overflows.

To bring the code snippet back to life, one needs to add bits there so that they could hold real length. That is, there should be an additional byte or two to make packet length 24 or 32 bit value.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
0

I assigned an insufficient amount of bytes to store the packetsize, it works now that I increased that number. ;-)

Neo_b
  • 231
  • 5
  • 9