Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Capturing Minimized Window: A Kid’s Trick

0.00/5 (No votes)
5 Oct 2007 2  
Capture a window even if it is minimized or fully hidden by other windows
Screenshot - minimizedCapture.jpg

Background

I needed to capture from the minimized window for one of my projects. After several tries of using ordinary methods and failing; I searched the Web a lot (OK, not a lot) but couldn't find a solution, so I decided to work on a new one.

First Words

First of all, thank God for saving my head from blowing out, because I needed to do that really.

Maybe this method is not such a reliable one, but it solved my problem and may be useful for some others, so I thought putting it on The Code Project is better than not doing so.

By the way, this is my first CodeProject article, so forgive me if you see any flaws in it, and please help me with your suggestions for my further actions.

The Problem

OK, the core of this method is the PrintWindow API which draws the face of the window on the specific Device Context.

This method can be used to capture a window regardless of its order and transparency level (it can capture from a partially or fully hidden window), but the main problem is, it cannot capture the minimized window, actually when the window is minimized, it won't be drawn anymore, so if we use PrintWindow it only gives the title of the window back to us.

I tried several methods for capturing a minimized window but I failed, except this one.

How to Capture

I assumed there is no way to capture from the minimized window, so this assumption changed the approach.

I tried to make the window back to normal and capture it then, and then minimize it again; for having a hidden capture, before we pop-up the window from minimized, it must be transparent and it can be done using the SetLayeredWindowAttributes API, but there was another problem. Again the animation of popping up window was shown, even if the window was fully transparent.

By using SPY++, I monitored the messages for explorer and then unchecked "Animate Windows when minimizing and maximizing" and found this message SPI_SETANIMATION then, with a few searches, I found that it can be changed through the SystemParametersInfo API.

This effect can be disabled through the registry, but it's not real-time.

HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\MinAnimate

If the value is 0, the effect is disabled, and for 1 it is enabled.

So here are the steps I followed to capture a minimized window:

  1. Disable MinAnimate effect
  2. Transparent the window (PrintWindow can take a snap from such a window)
  3. Restore the Window
  4. Capture
  5. Minimize it again
  6. Remove transparency
  7. Enable MinAnimate effect

Now let's check the codes.

1 & 7 - Disable/Enable MinAnimate Effect

I forgot to mention, I say MinAnimate because it's the name in the Registry.

As I mentioned before, it can be done by using SystemParametersInfo, here it is:

(This snippet is in XPAppearance.cs)

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfo(SPI uiAction, uint uiParam,
 ref ANIMATIONINFO pvParam, SPIF fWinIni);

SPI is an enumeration of SPI messages, we want to disable/enable the MinAnimate so we must set uiAction to SPI_SETANIMATION.

We can get/set the effect status in ANIMATIONINFO structure.

As a note, cbsize member of ANIMATIONINFO must be set to the size of the structure, and pvParam must also be equal to cbSize.

Here is the structure:

(This snippet is in XPAppearance.cs)

[StructLayout(LayoutKind.Sequential)]
private struct ANIMATIONINFO
{

   public ANIMATIONINFO(bool iMinAnimate)
   {
      this.cbSize = GetSize();
      if (iMinAnimate) this.iMinAnimate = 1;
      else this.iMinAnimate = 0;
   }

   public uint cbSize;
   private int iMinAnimate;

   public bool IMinAnimate
   {
      get
      {
         if (this.iMinAnimate == 0) return false;
         else return true;
      }
      set
      {
         if (value == true) this.iMinAnimate = 1;
         else this.iMinAnimate = 0;
      }
   }

   public static uint GetSize()
   {
      return (uint)Marshal.SizeOf(typeof(ANIMATIONINFO));
   }
}

And here is the method I used for disable/enable MinAnimate:

(This snippet is in XPAppearance.cs)

public static void SetMinimizeMaximizeAnimation(bool status)
{
   ANIMATIONINFO animationInfo=new ANIMATIONINFO(status);
   SystemParametersInfo(SPI.SPI_GETANIMATION, ANIMATIONINFO.GetSize(),
    ref animationInfo, SPIF.None);

   if (animationInfo.IMinAnimate != status)
   {
      animationInfo.IMinAnimate = status;
      SystemParametersInfo(SPI.SPI_SETANIMATION, ANIMATIONINFO.GetSize(),
       ref animationInfo, SPIF.SPIF_SENDCHANGE);
   }
}

I think there is nothing to explain with the code above.

2 & 6 - Add/Remove Transparency

For making the window invisible but with capturing ability, we can make it transparent.

It can be done somewhat like this:

(This snippet is in WindowSnap.cs)

[DllImport("user32")]
private static extern int GetWindowLong(IntPtr hWnd, int index);

[DllImport("user32")]
private static extern int SetWindowLong(IntPtr hWnd, int index, int dwNewLong);

[DllImport("user32")]
private static extern int SetLayeredWindowAttributes(IntPtr hWnd, byte crey,
 byte alpha, int flags);

(This snippet is in EnterSpecialCapturing method in WindowSnap.cs)

winLong = GetWindowLong(hWnd, GWL_EXSTYLE);
SetWindowLong(hWnd, GWL_EXSTYLE, winLong | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, 0, 1, LWA_ALPHA);

For removing applied transparency, we can do it by setting the old winLong again.

(This snippet is in the ExitSpecialCapturing method in WindowSnap.cs)

SetWindowLong(hWnd, GWL_EXSTYLE, winLong);

3 & 5 - Restore/Minimize The Window

This part is fairly easy, it can be done using the ShowWindow API.

(This snippet is in WindowSnap.cs)

[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);

private enum ShowWindowEnum{Hide = 0,
ShowNormal = 1,ShowMinimized = 2,ShowMaximized = 3,
Maximize = 3,ShowNormalNoActivate = 4,Show = 5,
Minimize = 6,ShowMinNoActivate = 7,ShowNoActivate = 8,
Restore = 9,ShowDefault = 10,ForceMinimized = 11};

(This snippet is in EnterSpecialCapturing method in WindowSnap.cs)

ShowWindow(hWnd, ShowWindowEnum.Restore);

And for minimizing it again, we can use:

(This snippet is in the ExitSpecialCapturing method in WindowSnap.cs)

ShowWindow(hWnd, ShowWindowEnum.Minimize);

4 - Capture

Nothing to say, there are dozens of articles about it; here is the code:

(This snippet is in the GetWindowImage method in WindowSnap.cs)

Bitmap bmp = new Bitmap(size.Width, size.Height);
Graphics g = Graphics.FromImage(bmp);
IntPtr dc = g.GetHdc();

PrintWindow(hWnd, dc, 0);

g.ReleaseHdc();
g.Dispose();

Capturing Child Windows

Capturing from MDI children is very similar to capturing ordinary windows, but with one exception, if the child window is partially hidden by the parent (and not another child), that part would be drawn as blank. For solving this problem, we can use GetParent and SetParent APIs to make it as an ordinary window and back.

[DllImport("user32")]
private static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr child, IntPtr newParent);  

We can pass IntPtr.Zero to newParent in the GetParent method for making it normal (not child).

Last Words

That's all, and for the last words, you can take a snap from Windows using WindowSnap class. It has two methods, GetAllWindows and GetWindowSnap. The first one returns a collection of window snaps from all available windows, and the second one returns a snap of the specific window.

Finally, I thank you for spending your time and reading this article. I hope it would be useful. Please help me with your suggestions and ideas for making this article better.

Updates

  • 6th October, 2007
    • Capturing Child Windows: Support for child windows added. Special thanks to mmjc23 who mentioned that. For more details, see Capturing Child Windows section.
    • MinAnimate Bug Fix: In the previous version, if MinAnimate effect was disabled, WindowSnap would enable it after SpecialCapturing (capturing from minimized window). Special thanks to Kalabuli who notified me about this bug.
  • 10th October, 2007
    • Child Dialog Capturing Fix: Capturing from Modal child dialogs fixed. Special thanks to Hitesh who notified me about this bug.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here