捕获包含 BaloonTip 的屏幕截图

Capture screenshot that includes BaloonTip

我想自动创建使用我的气球提示从通知图标截取的屏幕截图,这样可以轻松验证我的应用程序支持的不同语言的外观。问题是屏幕截图中没有气球提示,尽管它显示在 Windows 7.

的屏幕上

我已经尝试过 Capture screenshot of active window? 的解决方案,例如

// From http://www.developerfusion.com/code/4630/capture-a-screen-shot/
var sc = new ScreenCapture();
trayIcon.ShowBalloonTip(10000, "My Title", "My message", ToolTipIcon.Info);
Thread.Sleep(2000); // Just to make sure that the balloon tip is shown
sc.CaptureScreenToFile("MyScreenshot.png", ImageFormat.Png);

Rectangle bounds = Screen.GetBounds(Point.Empty);
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
    using(Graphics g = Graphics.FromImage(bitmap))
    {
        trayIcon.ShowBalloonTip(10000, "My Title", "My message", ToolTipIcon.Info);
        Thread.Sleep(2000); // Just to make sure that the balloon tip is shown
        g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }
    bitmap.Save("MyScreenshot.png", ImageFormat.Png);
}

但是两者都截取了屏幕截图而没有显示气球提示。那么,有没有办法以编程方式截取包含气球提示的屏幕截图?

奖励信息:在 Windows 10,气球提示被强制进入正常的通知系统,并按预期截取此作品的屏幕截图。

正如 Hans Passant 在对该问题的评论中提到的那样,使用 CopyPixelOperation.CaptureBlt 是解决方案的关键。

由于它不适用于我已经尝试过的解决方案,我发现了一个类似的问题 Capture screenshot Including Semitransparent windows in .NET,它涉及半透明 windows。

使我能够截取包含通知图标气球提示的屏幕截图的所有解决方案如下所示:

class ScreenCapture
{
    public void CaptureScreenToFile(string fileName)
    {
        Size sz = Screen.PrimaryScreen.Bounds.Size;
        IntPtr hDesk = GetDesktopWindow();
        IntPtr hSrce = GetWindowDC(hDesk);
        IntPtr hDest = CreateCompatibleDC(hSrce);
        IntPtr hBmp = CreateCompatibleBitmap(hSrce, sz.Width, sz.Height);
        IntPtr hOldBmp = SelectObject(hDest, hBmp);
        bool b = BitBlt(hDest, 0, 0, sz.Width, sz.Height, hSrce, 0, 0, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
        Bitmap bmp = Bitmap.FromHbitmap(hBmp);
        SelectObject(hDest, hOldBmp);
        DeleteObject(hBmp);
        DeleteDC(hDest);
        ReleaseDC(hDesk, hSrce);
        bmp.Save(fileName);
        bmp.Dispose();
    }

    // P/Invoke declarations
    [DllImport("gdi32.dll")]
    static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int
        wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
    [DllImport("user32.dll")]
    static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr DeleteDC(IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr DeleteObject(IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
    [DllImport("gdi32.dll")]
    static extern IntPtr CreateCompatibleDC(IntPtr hdc);
    [DllImport("gdi32.dll")]
    static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
    [DllImport("user32.dll")]
    public static extern IntPtr GetDesktopWindow();
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr ptr);
}