-
Win32 Screenshot bits
I'm not sure if it's the transfer that's causing the problem but I am trying to take a screen capture and send the bits across a socket. I am... confident I have the bits correctly but... perhaps not since I'm still having a problem. Is there anything wrong that I may have missed here while getting the bits?
Code:
HDC hdc = GetDC(NULL);
HDC dskt = GetDC(GetDesktopWindow());
HDC hDest = CreateCompatibleDC(dskt);
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
cout << "Creating compatible bitmap" << endl;
HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height);
cout << "Done" << endl;
SelectObject(hDest, hbDesktop);
cout << "Blitting" << endl;
BitBlt(hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY);
cout << "Done" << endl;
BITMAP bt;
GetObject(hbDesktop,sizeof(BITMAP),&bt);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD bmpSize = ((width*bi.biBitCount+31)/32)*4*height;
cout << "Needed size: " << bmpSize << endl;
HANDLE hDIB = GlobalAlloc(GHND,bmpSize);
char* bits = (char*)GlobalLock(hDIB);
GetDIBits(dskt,hbDesktop,0,
height,bits,
(BITMAPINFO*)&bi,
DIB_RGB_COLORS);
s.Send(RKL_WIDTH_SND);
if (s.Receive().compare(RKL_WIDTH_RECVD) != 0)
{
cout << "Failed to receive the width data confirmation" << endl;
continue;
}
char width_c[65]; //64 bit compatible
char height_c[65];
itoa(width,width_c,10);
s.Send(width_c);
s.Receive();
s.Send(RKL_HEIGHT_SND);
if (s.Receive().compare(RKL_HEIGHT_RECVD) != 0)
{
cout << "Failed to receive the height data confirmation" << endl;
continue;
}
itoa(height,height_c,10);
s.Send(height_c);
s.Receive();
cout << "Sending bits" << endl;
s.Send(bits);
cout << "Done" << endl;
s.Receive();
GlobalUnlock(hDIB);
GlobalFree(hDIB);
DeleteObject(hbDesktop);
DeleteObject(hDest);
ReleaseDC(NULL,hdc);
ReleaseDC(GetDesktopWindow(),dskt);
s is an instance of a "home-made" socket class. Send and Receive are just as they are. Send() sends an std::string. When I try a reinterpret_cast to a char* from getting bits, the application crashes. I suppose that's why I'm a little sceptical.
-
Just how does your s.Send() actually figure out how much data to send?
s.Send(RKL_HEIGHT_SND);
s.Send(height_c);
s.Send(bits);
I've no idea what RKL_HEIGHT_SND is, perhaps it's a std::string as you say in your description.
height_c would work OK, since it is a nul-terminated string. Conversion to a std::string would be easy enough.
bits on the other hand is totally screwed, since there is no way to work out how much data there is, simply by examining the data it points to.
Overload your send function as follows
Code:
Send(std::string s);
Send(const char *s, size_t len = 0);
In the last case, send 'len' chars if len is greater than 0, otherwise send up to the first nul character (it's a normal C string).
Sending bits would be
s.Send(bits,bmpSize);
-
That's true. Same for the Receive() function that adds all data received to an std::string. Thank you. I forgot about that. So that does mean that I am getting the bits right? Perhaps I'm setting them wrong then...
Yes RKL_WIDTH_SEND is a basic little numeric string. Basically a packet ID so the server knows what it is receiving.
-
Are you really going to send an uncompressed bitmap across a socket? Wow. I would look into compressing it or at least run-length encoding it. If this is a 24-bit image RLE probably will not do much but it's better than nothing. Also it looks like your send is blocking which is also bad news since an uncompressed bitmap can be gigantic which means the rest of your program will just sit there while it waits for the send to complete.