Win32
Window Screenshot Class
Here's a class that will create a bitmap of a window. Just pass in the Win32 handle to the window, and get a bitmap back!
Note that if a window is minimized, you generally won't get the actual contents, but rather usually a picture of the minimized task bar icon.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices;
/*
LICENSE
Copyright (c) 2009, Michael Lehman (http://www.machinegods.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the Michael Lehman, machinegods.com, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace MachineGods
{
public class WindowScreenShot
{
//pinvoke.net ftw
//----------------------------------------------------------------------------
internal enum TernaryRasterOperations : uint
{
SRCCOPY = 0x00CC0020,
SRCPAINT = 0x00EE0086,
SRCAND = 0x008800C6,
SRCINVERT = 0x00660046,
SRCERASE = 0x00440328,
NOTSRCCOPY = 0x00330008,
NOTSRCERASE = 0x001100A6,
MERGECOPY = 0x00C000CA,
MERGEPAINT = 0x00BB0226,
PATCOPY = 0x00F00021,
PATPAINT = 0x00FB0A09,
PATINVERT = 0x005A0049,
DSTINVERT = 0x00550009,
BLACKNESS = 0x00000042,
WHITENESS = 0x00FF0062
}
//----------------------------------------------------------------------------
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left_, int top_, int right_, int bottom_)
{
Left = left_;
Top = top_;
Right = right_;
Bottom = bottom_;
}
public int Height { get { return Bottom - Top; } }
public int Width { get { return Right - Left; } }
public Size Size { get { return new Size(Width, Height); } }
public Point Location { get { return new Point(Left, Top); } }
// Handy method for converting to a System.Drawing.Rectangle
public Rectangle ToRectangle()
{ return Rectangle.FromLTRB(Left, Top, Right, Bottom); }
public static RECT FromRectangle(Rectangle rectangle)
{
return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom);
}
public override int GetHashCode()
{
return Left ^ ((Top << 13) | (Top >> 0x13))
^ ((Width << 0x1a) | (Width >> 6))
^ ((Height << 7) | (Height >> 0x19));
}
#region Operator overloads
public static implicit operator Rectangle(RECT rect)
{
return rect.ToRectangle();
}
public static implicit operator RECT(Rectangle rect)
{
return FromRectangle(rect);
}
#endregion
}
//----------------------------------------------------------------------------
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
}
//----------------------------------------------------------------------------
[DllImport("user32.dll")]
internal static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[DllImport("gdi32.dll")]
internal static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth,
int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
[DllImport("user32", ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32", EntryPoint = "ReleaseDC", SetLastError = true)]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
//----------------------------------------------------------------------------
public static Bitmap Get(IntPtr hWnd)
{
WINDOWINFO winInfo = new WINDOWINFO();
bool ret = GetWindowInfo(hWnd, ref winInfo);
if (!ret)
{
return null;
}
int height = winInfo.rcWindow.Height;
int width = winInfo.rcWindow.Width;
if (height == 0 || width == 0) return null;
Graphics frmGraphics = Graphics.FromHwnd(hWnd);
IntPtr hDC = GetWindowDC(hWnd); //gets the entire window
//IntPtr hDC = frmGraphics.GetHdc(); -- gets the client area, no menu bars, etc..
System.Drawing.Bitmap tmpBitmap = new System.Drawing.Bitmap(width, height, frmGraphics);
Graphics bmGraphics = Graphics.FromImage(tmpBitmap);
IntPtr bmHdc = bmGraphics.GetHdc();
BitBlt(bmHdc, 0, 0,width, height, hDC, 0, 0, TernaryRasterOperations.SRCCOPY);
bmGraphics.ReleaseHdc(bmHdc);
ReleaseDC(hWnd, hDC);
return tmpBitmap;
}
//----------------------------------------------------------------------------
}
}
Reparse Points
I have two needs for working with both junctions and volume mount points that don't have good tools out in the public domain that meet the needs.
I should qualify that everything I use needs to be easily integrated into scripts, and be able to handle the full 32,767 characters in a path with all the funky characters that NTFS can use. (Someone tell me why even windows explorer can't do this!?!??)
1. I need to be able to list all volumes on a server and paths they are mounted to
2. I need to be able to easily find every junction on a drive as quickly as possible
I have learned how to do both of these, and will be posting tools with code in the near future.
My articles for reparse points:
Links for Reparse Points
Win32 Reparse Points
One of the common challenges that we server admins face at work is, of course, disk space.
Windows and NFTS have some very powerful features built in, but I sometimes get the impression that Microsoft didn't always think how a customer of theirs would actually be able to use those features.
Win32 reparse points fall into this category. They are currently my favorite MS "feature" to rant about at work...
What is a reparse point you ask? Well, the simplest explanation is that it's a file system object that causes the OS to do a bit of extra processing when it runs across one to go somewhere else to get the desired data - insetad of just reading that object directly like a normal file/folder. It parses the file system object a second time, hence the name.
A reparse point works by sending the contents of the reparse point to a file system filter driver, that does the actual processing and spits the results back.
That file system filter can be a MS driver, or a third party driver.
The most common examples of reparse points are junctions and volume mount points.
Other common uses of reparse points are for archival of files. The archival program moves the file off to archival storage location and creates a reparse point where it was. The OS calls the archival program when it encounters the reparse point to go and fetch the actual data. The OS can do that because the archival program registers a GUID with MS for their reparse point type (tag type), and the OS knows to call their filter based on that GUID.
Fun stuff.. the above was a bit of a simplification, but it should be accurate enough.
Junctions and volume mount points concern the average server admin.
A "junction" is a not-so-technical term that means a reparse point for which the target is another folder.
A "volume mount point" means a reparse point for which the target is a volume.
Interestingly, as far as the reparse point goes, there's no difference between a junction and a volume mount point.
The frustrating thing, is that Microsoft built these powerful features into the OS and then didn't bother to include tools to adequately manage them.
This is really bad, because if you're using these features a lot to get around drive letter limitations, drive space limitations, or to make the file system more intelligently laid out, you can end up having more problems from trying to get the security right, not have loops in the backups, etc...
I should point out there are some programs out there for doing some work with reparse points, but they aren't comprehensive to say the least, and most server admins will quickly realize that they can't do things they'd expect to easily be able to do.. such as, oh.. list all the volumes on a server and where they're mounted to.
So what do we do.. well, we learn the API calls and write the tools ourselves!
Look for some entries in the Win32 and Tools section soon about this...
Win32 API
Topics regarding the Win32 API
Reparse Points
I have two needs for working with both junctions and volume mount points that don't have good tools out in the public domain that meet the needs.
I should qualify that everything I use needs to be easily integrated into scripts, and be able to handle the full 32,767 characters in a path with all the funky characters that NTFS can use. (Someone tell me why even windows explorer can't do this!?!??)
1. I need to be able to list all volumes on a server and paths they are mounted to
2. I need to be able to easily find every junction on a drive as quickly as possible
I have learned how to do both of these, and will be posting tools with code in the near future.
My articles for reparse points
External Links for Reparse Points
