Thanks for the info. After a little more searching with your direction,
I think I found a solution (only on xp and 2003) using the PrintWindow
API. Thought i'd share. I tried the WM_Print message but couldn't get it
to work at all with the window I wanted to capture. Doing a BitBlt also
worked, but not when the workstation was locked.
public class gdi32
{
private class Externs
{
[System.Runtime.InteropServices.DllImport(strGDI32DLL,
CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetDeviceCaps(int iHdc,int iIndex);
}
/// <summary>
///
/// </summary>
/// <param name="iHdc"></param>
/// <param name="eIndex"></param>
/// <returns></returns>
public static int GetDeviceCaps(int iHdc,enCapsIndex eIndex)
{
return Externs.GetDeviceCaps(iHdc,(int)eIndex);
}
/// <summary>
///
/// </summary>
public enum enCapsIndex
{
/// <summary>
/// The device driver version.
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device technology.
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Width, in millimeters, of the physical screen.
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Height, in millimeters, of the physical screen.
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Width, in pixels, of the screen.
/// </summary>
HORZRES = 8,
/// <summary>
/// Height, in raster lines, of the screen.
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of pixels per logical inch along the screen width. In a
system with multiple display monitors, this value is the same for all
monitors.
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Number of pixels per logical inch along the screen height. In a
system with multiple display monitors, this value is the same for all
monitors.
/// </summary>
LOGPIXELSY = 90,
/// <summary>
/// Number of adjacent color bits for each pixel.
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of color planes.
/// </summary>
PLANES = 14,
/// <summary>
/// Number of device-specific brushes.
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of device-specific pens.
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of device-specific markers.
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of device-specific fonts.
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of entries in the device's color table, if the device has a
color depth of no more than 8 bits per pixel. For devices with greater
color depths, 1 is returned.
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Reserved.
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Value that indicates the curve capabilities of the device, as shown
in the following table.
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Value that indicates the line capabilities of the device, as shown
in the following table:
/// </summary>
LINECAPS = 30,
/// <summary>
/// Value that indicates the polygon capabilities of the device, as
shown in the following table.
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Value that indicates the text capabilities of the device, as shown
in the following table.
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Flag that indicates the clipping capabilities of the device. If the
device can clip to a rectangle, it is 1. Otherwise, it is 0.
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Value that indicates the raster capabilities of the device, as
shown in the following table.
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Relative width of a device pixel used for line drawing.
/// </summary>
ASPECTX = 40,
/// <summary>
/// Relative height of a device pixel used for line drawing.
/// </summary>
ASPECTY = 42,
/// <summary>
/// Diagonal width of the device pixel used for line drawing.
/// </summary>
ASPECTXY = 44,
/// <summary>
/// For printing devices: the width of the physical page, in device
units. For example, a printer set to print at 600 dpi on 8.5-x11-inch
paper has a physical width value of 5100 device units. Note that the
physical page is almost always greater than the printable area of the
page, and never smaller.
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// For printing devices: the height of the physical page, in device
units. For example, a printer set to print at 600 dpi on 8.5-by-11-inch
paper has a physical height value of 6600 device units. Note that the
physical page is almost always greater than the printable area of the
page, and never smaller.
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// For printing devices: the distance from the left edge of the
physical page to the left edge of the printable area, in device units.
For example, a printer set to print at 600 dpi on 8.5-by-11-inch paper,
that cannot print on the leftmost 0.25-inch of paper, has a horizontal
physical offset of 150 device units.
/// </summary>
PHYSICALOFFSETX = 112, // Physical Printable Area x margin
/// <summary>
/// For printing devices: the distance from the top edge of the
physical page to the top edge of the printable area, in device units. For
example, a printer set to print at 600 dpi on 8.5-by-11-inch paper, that
cannot print on the topmost 0.5-inch of paper, has a vertical physical
offset of 300 device units.
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor for the x-axis of the printer.
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor for the y-axis of the printer.
/// </summary>
SCALINGFACTORY = 115
}
}
public class User32
{
const string strUSER32DLL = "user32.dll";
private class Externs
{
[System.Runtime.InteropServices.DllImport(strUSER32DLL,
CharSet=CharSet.Auto, SetLastError=true)]
public static extern int PrintWindow(int iHwnd, int hdcBlt, uint
iFlags);
}
/// <summary>
///
/// </summary>
/// <param name="hWnd"></param>
/// <param name="eFlags"></param>
/// <returns></returns>
public static System.Drawing.Bitmap PrintWindow(int hWnd,
enPrintWindowFlags eFlags)
{
int iWidth = 0;
int iHeight = 0;
int hdcSrc = User32.GetWindowDC(hWnd);
try
{
iWidth = gdi32.GetDeviceCaps(hdcSrc,gdi32.enCapsIndex.HORZRES);
iHeight = gdi32.GetDeviceCaps(hdcSrc,gdi32.enCapsIndex.VERTRES);
}
finally
{
User32.ReleaseDC(hWnd,hdcSrc);
}
System.Drawing.Bitmap pImage = new System.Drawing.Bitmap(iWidth,
iHeight);
System.Drawing.Graphics graphics =
System.Drawing.Graphics.FromImage(pImage);
IntPtr hDC = graphics.GetHdc();
//paint control onto graphics using provided options
try
{
Externs.PrintWindow(hWnd, (int)hDC, (uint)eFlags);
}
finally
{
graphics.ReleaseHdc(hDC);
}
return pImage;
}
public enum enPrintWindowFlags : uint
{
/// <summary>
///
/// </summary>
PW_ALL = 0x00000000,
/// <summary>
/// Only the client area of the window is copied. By default, the
entire window is copied.
/// </summary>
PW_CLIENTONLY = 0x00000001
}
}
Stoitcho Goutsev (100) said:
Jeremy,
No, it is not possible. If it was it would be a big security flaw. One
of the reason people lock their stations is because they don't want
anyone to be able to see what is on the screen.
Secondly, You can grab only what is visible on the screen. You cannot
capture anything that is not visible e.g. part of a window obscured by
other window. When the workstation is locked there is nothing on the
screen, but the dialog for unlocking the station.
Windows provides a message called WM_PRINT this message is meant to be
used to ask a window to draw itself to an arbitrary graphic device
context. In theory it can be used for capturing invisible parts of a
window, but this message needs to be handled and processed by the target
application. I remember playing with this message when I was doing Win32
native programming and it worked with all standard windows' controls,
but almost never worked with third party controls and windows.
Once I tried to use this in a .NET application but there were some
problem with the Graphics object and I didn't have any success. However
I gave up pretty quick because I did it out of curiosity only, it wasn't
important. It might be possible to make it work with .NET application, I
don't know.
--
Stoitcho Goutsev (100) [C# MVP]
Is it possible to grab a screen shot of an application window even when
the workstation is locked? I can do it when it's not locked but just
get a black image when it is locked.