如何使用“工具提示”捕获屏幕?

28

我正在使用GDI来捕获屏幕,并且发现“工具提示”没有包括在截图中。这是我的基本代码:

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...

这能被修复吗,还是我应该使用其他方法来捕获屏幕(而不是GDI)?


编辑:

这是我拍摄的一张截图,它没有显示工具提示。

enter image description here


4
尝试使用SRCCOPY | CAPTUREBLT? - Alex K.
1
您的程序可能是由鼠标或键盘触发的,这会关闭其他地方的工具提示。 - Barmak Shemirani
1
你需要确保屏幕截图程序不会占据焦点,也不要操作任何输入设备(比如鼠标)。仔细查看屏幕截图程序的各个部分。如果截图软件有定时器功能那就更好了。启动截图软件,弹出工具提示并等待。只要不改变焦点和输入设备,就可以顺利完成截图。 - Csaba Toth
4
这似乎只适用于 Windows XP。在 Windows 8 上工作正常,截图可以获取所有内容。 - Barmak Shemirani
4
当我截屏时,工具提示仍然存在。我相信正如Barmak Shemirani所说,这是一个XP系统的问题。但是有没有人知道为什么这个问题只存在于XP系统中? - paul
显示剩余5条评论
2个回答

10

更新:根据Alex K.、Adrian McCarthy等人的建议添加了CAPTUREBLT

我无法重现同样的问题。如果您成功地捕获了桌面截图,那么所有内容都应该在那里!请尝试使用以下代码。请注意,3秒的等待是为了给手动激活工具提示的时间。

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

3
请尝试使用Alex K.评论中提到的 SRCCOPY | CAPTUREBLT。这对我来说一直有效。 - Adrian McCarthy
虽然现代版的 Windows 更加宽容,但在销毁 bmp 之前选择从 memdc 中清除 bmp 是一个很好的习惯。事实上,在调用 GetDIBits 之前应该将其从 memdc 中选择清除。根据 MSDN,“当应用程序调用此函数时,由 hbmp 参数标识的位图不能被选择到设备上下文中。” - Adrian McCarthy
1
@paul 在Windows 7中也是一样的。这个答案(修改为C语言)没有捕获到工具提示,直到我使用了Adrian McCarthy的评论,现在它可以正常工作了,已经点赞。 - Weather Vane
更多关于不从DC中选择对象的后果:http://blogs.msdn.com/b/oldnewthing/archive/2013/03/06/10399678.aspx - Adrian McCarthy

6
我几年前在Windows XP系统上遇到了完全相同的问题。回答我的问题中的代码解决了这个问题:

在.NET中捕获包括半透明窗口的屏幕截图

对于你来说,你应该只需要将stretchblt行更改为bitblt并添加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...

工具提示,就像透明窗口一样,根据bitblt的规范被跳过。此外,您不需要调整大小,因此使用bitblt。如果这不起作用,可能是您所做的其他操作有问题,正如其他评论者所暗示的那样,因此您可以将答案从C#转换为C,这对我在XP上有效。(当然我现在没有XP来测试,但那绝对是问题所在)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接