如何在C++中将窗口截图转换为位图对象?

20

如何在C++中获取窗口截图并生成位图对象?假设我已经拥有了窗口句柄。 我还想知道是否可能在窗口最小化时获取窗口的截图

C++ 在这里指的是VC++,使用与Windows XP+(win32)相关的所有库。


3
C++语言不提供任何“位图对象”...你是否正在使用任何图形工具包(MFC/WTL/wxWidgets/...)?还是只需要一个 HBITMAP - Matteo Italia
我指的是VC++,以及与Windows相关的那些库。 - jondinham
哦,不,我的意思是只使用Win32API和可能的MFC。 - jondinham
3个回答

33

您应该调用PrintWindow API:

void CScreenShotDlg::OnPaint()
{
    // device context for painting
    CPaintDC dc(this);

    // Get the window handle of calculator application.
    HWND hWnd = ::FindWindow( 0, _T( "Calculator" ));

    // Take screenshot.
    PrintWindow( hWnd,
                 dc.GetSafeHdc(),
                 0 );
}

请看这个问题:获取窗口截图的Windows API

如果您不使用MFC,这里是纯PrintWindow函数的签名:

BOOL PrintWindow(
    HWND hwnd,
    HDC hdcBlt,
    UINT nFlags
);

更多详情请参阅MSDN:http://msdn.microsoft.com/en-us/library/dd162869(v=vs.85).aspx

如Matteo所说,如何将其保存为位图取决于您实际使用的框架...

编辑:

这里是原始C++的完整示例:

#define _WIN32_WINNT    0x0501        //xp
#include <windows.h>

int main()
{ 
    RECT rc;
    HWND hwnd = FindWindow(TEXT("Notepad"), NULL);    //the window can't be min
    if (hwnd == NULL)
    {
        cout << "it can't find any 'note' window" << endl;
        return 0;
    }
    GetClientRect(hwnd, &rc);

    //create
    HDC hdcScreen = GetDC(NULL);
    HDC hdc = CreateCompatibleDC(hdcScreen);
    HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, 
        rc.right - rc.left, rc.bottom - rc.top);
    SelectObject(hdc, hbmp);

    //Print to memory hdc
    PrintWindow(hwnd, hdc, PW_CLIENTONLY);

    //copy to clipboard
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hbmp);
    CloseClipboard();

    //release
    DeleteDC(hdc);
    DeleteObject(hbmp);
    ReleaseDC(NULL, hdcScreen);

    cout << "success copy to clipboard, please paste it to the 'mspaint'" << endl;

    return 0;
}

3
@Paul:只有当一个窗口正确处理了“WM_PRINT”消息时,你才能使用“PrintWindow”截取最小化的窗口截图,否则你就没戏了。 - Matteo Italia
2
我建议使用GetWindowRect而不是GetClientRect,以使其在具有厚边框的Windows7或Vista上更加流畅。 - jondinham
1
好的,这是有区别的,这取决于他是否只想要客户端区域还是整个窗口。感谢指出这一点 :) - Davide Piras
2
@davide:上面的代码可以完整地截取一些窗口(如Chrome、记事本等)的屏幕截图,但是对于其他一些窗口(如Visual Studio IDE窗口等),截图的某些部分完全是黑色的!发生了什么? - jondinham
我不明白何时应该在添加到剪贴板后删除句柄的规则。如果您使用GlobalAlloc()创建句柄,则剪贴板拥有该句柄,您不需要删除它。但是,如果像这个例子一样是一个HBITMAP,那么您需要将其删除? - M Katz
显示剩余3条评论

9

2

看起来PrintWindow正在使用前缓冲区。我试图截取IE的屏幕截图。打开一个新链接,然后尝试获取图片。它将显示前一个链接的图片。


在我看来,这已经足够作为一个答案了,虽然不是非常长的一个。 - peterh

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