PC Review
Forums
Newsgroups
Microsoft DotNet
Microsoft Dot NET Framework Forms
capture screen even when workstation is locked
Forums
Newsgroups
Microsoft DotNet
Microsoft Dot NET Framework Forms
capture screen even when workstation is locked
![]() |
capture screen even when workstation is locked |
|
|
Thread Tools | Rate Thread |
|
|
#1 |
|
Guest
Posts: n/a
|
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. |
|
|
|
#2 |
|
Guest
Posts: n/a
|
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] "Jeremy Chapman" <me@here.com> wrote in message news:ORPS5AEAGHA.3048@TK2MSFTNGP15.phx.gbl... > 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. > |
|
|
|
#3 |
|
Guest
Posts: n/a
|
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) [C# MVP]" <100@100.com> wrote in message news:efh$w1LAGHA.344@TK2MSFTNGP11.phx.gbl... > 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] > > "Jeremy Chapman" <me@here.com> wrote in message > news:ORPS5AEAGHA.3048@TK2MSFTNGP15.phx.gbl... >> 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. >> > > |
|
|
|
#4 |
|
Guest
Posts: n/a
|
Jeremy,
It is great that you decide to share with all of us. I'm surprised though that this works on XP and 2003, but not on win2k let say after all talk about security. I'd concider this as a security flaw. It might be somehow connected to the remote dektop feature available on these platforms. It is funny that I new about this PrintWindow method, but I never tried because the docs say that it is similar to sending WM_PRINT and the latter didn't work If you don't mind I'd like to give some suggestions: 1. When you declare import API methods for PInovke use IntPtr for handlers (such as HWND and HDC) instead of *int* 2. Try to avoid as much as it's possible using non mamaged calls. For example you use GetDeviceCaps to get the screen size. You can do that using Screen class: "Jeremy Chapman" <me@here.com> wrote in message news:urJWtLQAGHA.3864@tk2msftngp13.phx.gbl... > 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) [C# MVP]" <100@100.com> wrote in message > news:efh$w1LAGHA.344@TK2MSFTNGP11.phx.gbl... >> 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] >> >> "Jeremy Chapman" <me@here.com> wrote in message >> news:ORPS5AEAGHA.3048@TK2MSFTNGP15.phx.gbl... >>> 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. >>> >> >> > > |
|
|
|
#5 |
|
Guest
Posts: n/a
|
Sorry about the previous post. I pressed wrong key combination
![]() Jeremy, It is great that you decide to share with all of us. I'm surprised though that this works on XP and 2003, but not on win2k let say after all talk about security. I'd concider this as a security flaw. It might be somehow connected to the remote dektop feature available on these platforms. It is funny that I new about this PrintWindow method, but I never tried because the docs say that it is similar to sending WM_PRINT and the latter didn't work If you don't mind I'd like to give some suggestions: 1. When you declare import API methods for PInovke use IntPtr for handlers (such as HWND and HDC) instead of *int* 2. Try to avoid as much as it's possible using non mamaged calls. For example you use GetDeviceCaps to get the screen size. You can do that using Screen class: screenBounds = Screen.FromHandle(hWnd).Bounds; screenWidth = screenBounds.Width; screenHeight = screenBounds.Height; 3. You accept handle to a window to capture, but the image you create is as big as the whole screen, which makes small windows to appear in the corner of an almost empty image. I'd suggest to create the bitmap as big as the window is. If you capture only client part if an window you can do it from managed code - Graphics.VisibleClipBounds. For the wole window though you need to use Pinvoke. For example you can use GetWindowDC and then create Graphics.FormHdc, etc or you can use APIs such as GetWindowRect. Here is little bit nodified version of your code. Not that it is better or something, but it is little bit shorter. I hope you don't mind. public class User32 { const string strUSER32DLL = "user32.dll"; [System.Runtime.InteropServices.DllImport(strUSER32DLL)] public static extern int PrintWindow(IntPtr iHwnd, IntPtr hdcBlt, uint iFlags); [System.Runtime.InteropServices.DllImport(strUSER32DLL)] public static extern IntPtr GetWindowDC(IntPtr hWnd); /// <summary> /// /// </summary> /// <param name="hWnd"></param> /// <param name="eFlags"></param> /// <returns></returns> public static System.Drawing.Bitmap PrintWindow(IntPtr hWnd, PrintWindowFlags flags) { //Rectangle screenBounds = Rectangle.Empty; Rectangle visibleBounds = Rectangle.Empty; System.Drawing.Bitmap image = null; using(Graphics grfx = Graphics.FromHdc(GetWindowDC(hWnd))) { visibleBounds = Rectangle.Round(grfx.VisibleClipBounds); } image = new System.Drawing.Bitmap( visibleBounds.Width, visibleBounds.Height); System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(image); IntPtr hDC = graphics.GetHdc(); //paint control onto graphics using provided options try { User32.PrintWindow(hWnd, hDC, (uint)flags); } finally { graphics.ReleaseHdc(hDC); } return image; } public enum PrintWindowFlags : 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) [C# MVP] "Jeremy Chapman" <me@here.com> wrote in message news:urJWtLQAGHA.3864@tk2msftngp13.phx.gbl... > 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) [C# MVP]" <100@100.com> wrote in message > news:efh$w1LAGHA.344@TK2MSFTNGP11.phx.gbl... >> 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] >> >> "Jeremy Chapman" <me@here.com> wrote in message >> news:ORPS5AEAGHA.3048@TK2MSFTNGP15.phx.gbl... >>> 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. >>> >> >> > > |
|
|
|
#6 |
|
Guest
Posts: n/a
|
Great feedback, thanks a lot!.
"Stoitcho Goutsev (100) [C# MVP]" <100@100.com> wrote in message news:OMKCuzZAGHA.2356@tk2msftngp13.phx.gbl... > Sorry about the previous post. I pressed wrong key combination ![]() > > Jeremy, > > It is great that you decide to share with all of us. > I'm surprised though that this works on XP and 2003, but not on win2k let > say after all talk about security. I'd concider this as a security flaw. > It > might be somehow connected to the remote dektop feature available on these > platforms. > > It is funny that I new about this PrintWindow method, but I never tried > because the docs say that it is similar to sending WM_PRINT and the latter > didn't work > > If you don't mind I'd like to give some suggestions: > 1. When you declare import API methods for PInovke use IntPtr for handlers > (such as HWND and HDC) instead of *int* > 2. Try to avoid as much as it's possible using non mamaged calls. For > example you use GetDeviceCaps to get the screen size. You can do that > using > Screen class: > screenBounds = Screen.FromHandle(hWnd).Bounds; > screenWidth = screenBounds.Width; > screenHeight = screenBounds.Height; > 3. You accept handle to a window to capture, but the image you create is > as big as the whole screen, which makes small windows to appear in the > corner of an almost empty image. > I'd suggest to create the bitmap as big as the window is. If you capture > only client part if an window you can do it from managed code - > Graphics.VisibleClipBounds. For the wole window though you need to use > Pinvoke. For example you can use GetWindowDC and then create > Graphics.FormHdc, etc or you can use APIs such as GetWindowRect. > > Here is little bit nodified version of your code. Not that it is better or > something, but it is little bit shorter. I hope you don't mind. > > public class User32 > { > > const string strUSER32DLL = "user32.dll"; > > [System.Runtime.InteropServices.DllImport(strUSER32DLL)] > public static extern int PrintWindow(IntPtr iHwnd, IntPtr hdcBlt, uint > iFlags); > [System.Runtime.InteropServices.DllImport(strUSER32DLL)] > public static extern IntPtr GetWindowDC(IntPtr hWnd); > > > /// <summary> > /// > /// </summary> > /// <param name="hWnd"></param> > /// <param name="eFlags"></param> > /// <returns></returns> > public static System.Drawing.Bitmap PrintWindow(IntPtr hWnd, > PrintWindowFlags flags) > { > > //Rectangle screenBounds = Rectangle.Empty; > Rectangle visibleBounds = Rectangle.Empty; > System.Drawing.Bitmap image = null; > > using(Graphics grfx = Graphics.FromHdc(GetWindowDC(hWnd))) > { > > visibleBounds = Rectangle.Round(grfx.VisibleClipBounds); > > } > > image = new System.Drawing.Bitmap( > visibleBounds.Width, > visibleBounds.Height); > > System.Drawing.Graphics graphics = > System.Drawing.Graphics.FromImage(image); > > IntPtr hDC = graphics.GetHdc(); > //paint control onto graphics using provided options > try > { > User32.PrintWindow(hWnd, hDC, (uint)flags); > } > finally > { > graphics.ReleaseHdc(hDC); > } > > return image; > } > > public enum PrintWindowFlags : 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) [C# MVP] > > "Jeremy Chapman" <me@here.com> wrote in message > news:urJWtLQAGHA.3864@tk2msftngp13.phx.gbl... >> 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) [C# MVP]" <100@100.com> wrote in message >> news:efh$w1LAGHA.344@TK2MSFTNGP11.phx.gbl... >>> 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] >>> >>> "Jeremy Chapman" <me@here.com> wrote in message >>> news:ORPS5AEAGHA.3048@TK2MSFTNGP15.phx.gbl... >>>> 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. >>>> >>> >>> >> >> > > |
|
![]() |
|
| Thread Tools | |
| Rate This Thread | |
|
|

Main Page 


