Tore Østergaard
Tore Østergaard

Reputation: 4602

Capture screenshot that includes BaloonTip

I wanted to automate the creation of screenshots taken with my balloon tip from a notification icon, so that could easily validate the look of the different languages my application supports. Problem is that the balloon tip is absent from the screenshot although it is shown on the screen on Windows 7.

I have tried with the solutions from Capture screenshot of active window?, e.g.

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

and

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

But both take screenshots without showing the balloon tip. So, is there a way to programmatically take a screenshot that includes balloon tips?

Bonus information: On Windows 10 the balloon tip is forced into the normal notification system and taking screenshots of this works as expected.

Upvotes: 0

Views: 144

Answers (1)

Tore Østergaard
Tore Østergaard

Reputation: 4602

As Hans Passant mentions in a commet to the question, using CopyPixelOperation.CaptureBlt is the key to the solution.

As it did not work with the solutions I already tried I found a similar question Capture screenshot Including Semitransparent windows in .NET, that deals with semi-transparent windows.

All-in-all the solutions that enables me to take a screenshot that includes the balloon tip from a notification icon looks like this:

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

Upvotes: 1

Related Questions