28

I am using GDI to capture the screen, and I have noticed that the "Tool Tips" are not included in the screenshot. This is my basic code:

HDC hdcDesk = GetDC(0);

HDC hdcMem = CreateCompatibleDC(hdcDesk);
HBITMAP hbmMem = CreateCompatibleBitmap(hdcDesk, 1920, 1080);
SelectObject(hdcMem, hbmMem);

StretchBlt(hdcMem, 0, 0, 1920, 1080, hdcDesk, 0, 0, 1920, 1080, SRCCOPY);

// Now save the bitmap...

Can this be fixed, or should I use another approach to capture the screen (other than GDI)?


Edit:

This is a screenshot that I took that does not display the Tool Tip.

enter image description here

paul
  • 695
  • 7
  • 17
  • 4
    Try SRCCOPY | CAPTUREBLT ? – Alex K. May 07 '15 at 11:20
  • 1
    Your program is probably activated by mouse or keyboard which closes tooltip elsewhere. – Barmak Shemirani May 07 '15 at 14:53
  • @Barmak Shemirani No, the Tool Tip is not closed. – paul May 07 '15 at 19:50
  • You could use DirectX instead of GDI: http://stackoverflow.com/questions/30021274/capture-screen-using-directx/30138664#30138664 as it should capture tooltip. – Simon Mourier May 09 '15 at 14:47
  • 1
    You need to be sure that the screen capture program won't take over the focus, don't fiddle with any inputs (like the mouse). Look over all the parts of the screen capture program. Probably the best shot if the capture software uses a timer. You activate your capture software, bring up the tooltip and wait. If the focus and inputs are left alone, you should be golden. – Csaba Toth May 11 '15 at 05:57
  • 4
    This seems to be Window XP specific. I works fine on Windows 8, screen shot grabs everything. – Barmak Shemirani May 13 '15 at 01:12
  • 4
    @Csaba Toth The Tool Tip is still there when I capture the screen. I believe as Barmak Shemirani has said that this is an XP issue. But does anyone knows why this problem only exists in XP? – paul May 17 '15 at 16:09
  • Have you tried this with some different tooltip? –  May 17 '15 at 16:51
  • Also, have you tried replacing `GetDC(0)` with `CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL)`? –  May 17 '15 at 17:00
  • oops, it's the other way around. The function I posted is Windows 8 specific. You need to add `CAPTUREBLT` noted by @AlexK. and others, it should then work on all platforms. – Barmak Shemirani May 19 '15 at 23:16

2 Answers2

10

Update: added CAPTUREBLT as suggested by Alex K., Adrian McCarthy et al.

I can't reproduce the same problem. If you succeed in taking screen shot of desktop then everything should be there! Try this code instead. Note the 3 second wait is supposed to give time to manually activate a tool tip.

SetProcessDPIAware();
HDC hdc = GetDC(HWND_DESKTOP);
RECT rc; GetWindowRect(GetDesktopWindow(), &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;

HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, width, height, hdc, 0, 0, CAPTUREBLT | SRCCOPY);

WORD bpp = 24; //save 24-bit bitmap
DWORD size = ((width * bpp + 31) / 32) * 4 * height;
BITMAPFILEHEADER filehdr = { 'MB', 54 + size, 0, 0, 54 };
BITMAPINFOHEADER infohdr = { 40, width, height, 1, bpp };
BYTE* pix = malloc(size); 
GetDIBits(hdc, hbitmap, 0, height, pix, (BITMAPINFO*)&infohdr, DIB_RGB_COLORS);

FILE* fout = fopen("c:\\test\\_bmp.bmp", "wb"); 
if (fout) //save to file
{
    fwrite(&filehdr, sizeof(filehdr), 1, fout);
    fwrite(&infohdr, sizeof(infohdr), 1, fout);
    fwrite(pix, 1, size, fout);
    fclose(fout);
}

//cleanup
free(pix);
SelectObject(memdc, oldbmp);
DeleteObject(memdc);
DeleteObject(hbitmap);
ReleaseDC(HWND_DESKTOP, hdc);
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • 3
    Try `SRCCOPY | CAPTUREBLT` per Alex K.'s comment. That's always worked for me – Adrian McCarthy May 19 '15 at 16:25
  • Although modern versions of Windows are more tolerant, it's still good practice to select bmp out of memdc before destroying bmp. In fact, it should be selected out of memdc before you call GetDIBits. Per MSDN, "The bitmap identified by the hbmp parameter must not be selected into a device context when the application calls this function." – Adrian McCarthy May 19 '15 at 16:28
  • 1
    @paul same in Windows 7. This answer (modified for C) did not capture the tooltip until I used Adrian McCarthy's comment, now it works, upvoted. – Weather Vane May 19 '15 at 16:37
  • More on the consequences of not selecting objects out of DCs: http://blogs.msdn.com/b/oldnewthing/archive/2013/03/06/10399678.aspx – Adrian McCarthy May 19 '15 at 16:44
6

I had the exact problem a few years ago with a windows XP system. The code in the answer to my question solved the problem:

Capture screenshot Including Semitransparent windows in .NET

For you, you should be able to just change your stretchblt line to bitblt and add captureblt:

HDC hdcDesk = GetDC(0);

HDC hdcMem = CreateCompatibleDC(hdcDesk);
HBITMAP hbmMem = CreateCompatibleBitmap(hdcDesk, 1920, 1080);
SelectObject(hdcMem, hbmMem);

BitBlt(hdcMem, 0, 0, 1920, 1080, hdcDesk, 0, 0, SRCCOPY | CAPTUREBLT);

// Now save the bitmap...

Tooltips, like transparent windows, are skipped by spec of bitblt. Plus, you're not resizing, so use bitblt. If that doesn't work, there might be something else wrong with what you are doing as the other commenters hint, so you can convert the answer to my question from C# to C, that did work for me on XP. (of course I don't have XP any more to test but that was definitely the issue).

Community
  • 1
  • 1
FastAl
  • 6,194
  • 2
  • 36
  • 60