首页  编辑  

抓取最小化的窗口

Tags: /超级猛料/Picture.图形图像编程/抓图/   Date Created:

Capturing Minimized Window

Background

I needed to capture from the minimized window for one of my projects, after several tries of 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 maybe useful for some others, so I thought putting it in CodeProject is better than not.

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 "PrintWindow" API which draws 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 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 title of the window back to us.

I tried several methods for capturing 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 make it minimized again; for having a hidden capture, before pop-up the window from minimized, it must be transparent and it can be done using "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 uncheck "Animate windows when minimizing and maximizing" and found this message "SPI_SETANIMATION" then, with little some searches I found 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 is 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 said 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 size of the structure, and pvParam must be equal with cbSize too.

Here is the Structure

(this snippet is in XPAppearance.cs)

Collapse[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 somehow 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);

and for remvoing applied transparency, we can do it by setting the old winLong again.

(this snippet is in "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 "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 "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 other 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 "GetParent" method, for making it normal (not child).

Last Words

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

Finally, I thank you for spending your time and reading this article, I hope it would be useful;

and please help me with your suggestions and ideas for making this article better.

Updates

Capturing Child Windows: Support for child windows added. Special thanks to mmjc23 who mentioned that. For more details, see "Capturing Child Windows" section. (6 October 2007)

MinAnimate Bug Fix: In Previous version, if "MinAnimate" effect was disabled, WindowSnap would enable it after "SpecialCapturing" (capturing from minimized window). Special thanks to Kalabuli who noticed me about this bug. (6 October 2007)

Child Dialog Capturing Fix: Capturing from Modal child dialogs fixed, Special thanks to Hitesh who noticed me about this bug. (10 October 2007)

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 may to use can be found here