Home
Manage Your Code
Snippet: Take a screenshot of an open window (C#)
Title: Take a screenshot of an open window Language: C#
Description: Given a handle of an open window, takes a screenshot of that window and returns it as an image object. Views: 376
Author: Matt Schmidt Date Added: 8/15/2008
Copy Code  
1        /// <summary>
2        /// Takes a screenshot of a specified window and keeps the result in the clipboard.
3        /// </summary>
4        /// <param name="hwnd">Window handle</param>
5        private System.Drawing.Image GetScreenshot(int hwnd)
6        {
7            SetWindowPos((IntPtr)hwnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
8
9            //?? it works but why?
10            Thread.Sleep(100);
11
12            SetForegroundWindow((IntPtr)hwnd);
13
14            uint intReturn = 0;
15            INPUT structInput;
16            structInput = new INPUT();
17            structInput.type = (uint)1;
18            structInput.ki.wScan = 0;
19            structInput.ki.time = 0;
20            structInput.ki.dwFlags = 0;
21            structInput.ki.dwExtraInfo = 0;
22
23            //Key down Alt Key
24            structInput.ki.wVk = (ushort)VK.MENU;
25            intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
26
27            //Key down Print Screen
28            structInput.ki.wVk = (ushort)VK.SNAPSHOT;//vk;
29            intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
30
31            //Key up Print Screen
32            structInput.ki.dwFlags = KEYEVENTF_KEYUP;
33            structInput.ki.wVk = (ushort)VK.SNAPSHOT;//vk;
34            intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
35
36            //Key up Alt
37            structInput.ki.dwFlags = KEYEVENTF_KEYUP;
38            structInput.ki.wVk = (ushort)VK.MENU;
39            intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
40
41            //Need to let the print screen copy catch up with the rest of the code, other wise the clipboard will be read before
42            //it is written to
43            Thread.Sleep(100);
44
45            Win32.SetWindowPos((IntPtr)hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, Win32.TOPMOST_FLAGS);
46
47            System.Windows.Forms.IDataObject data = Clipboard.GetDataObject();
48
49            try
50            {
51                if (data.GetDataPresent(DataFormats.Bitmap))
52                {
53                    System.Drawing.Image image = (System.Drawing.Image)data.GetData(DataFormats.Bitmap, true);
54                    return image;
55                }
56                else throw new Exception("Expected bitmap image.");
57            }
58            catch (Exception ex)
59            {
60                return null;
61            }
62        }
63
64        // For Windows Mobile, replace user32.dll with coredll.dll
65        [DllImport("user32.dll")]
66        [return: MarshalAs(UnmanagedType.Bool)]
67        public static extern bool SetForegroundWindow(IntPtr hWnd);
68
69        [DllImport("user32.dll")]
70        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,
71           int Y, int cx, int cy, uint uFlags);
72
73        public const ushort KEYEVENTF_KEYUP = 0x0002;
74
75        public enum VK : ushort
76        {
77            SHIFT = 0x10,
78            CONTROL = 0x11,
79            MENU = 0x12,
80            ESCAPE = 0x1B,
81            BACK = 0x08,
82            TAB = 0x09,
83            RETURN = 0x0D,
84            PRIOR = 0x21,
85            NEXT = 0x22,
86            END = 0x23,
87            HOME = 0x24,
88            LEFT = 0x25,
89            UP = 0x26,
90            RIGHT = 0x27,
91            DOWN = 0x28,
92            SELECT = 0x29,
93            PRINT = 0x2A,
94            EXECUTE = 0x2B,
95            SNAPSHOT = 0x2C,
96            INSERT = 0x2D,
97            DELETE = 0x2E,
98            HELP = 0x2F,
99            NUMPAD0 = 0x60,
100            NUMPAD1 = 0x61,
101            NUMPAD2 = 0x62,
102            NUMPAD3 = 0x63,
103            NUMPAD4 = 0x64,
104            NUMPAD5 = 0x65,
105            NUMPAD6 = 0x66,
106            NUMPAD7 = 0x67,
107            NUMPAD8 = 0x68,
108            NUMPAD9 = 0x69,
109            MULTIPLY = 0x6A,
110            ADD = 0x6B,
111            SEPARATOR = 0x6C,
112            SUBTRACT = 0x6D,
113            DECIMAL = 0x6E,
114            DIVIDE = 0x6F,
115            F1 = 0x70,
116            F2 = 0x71,
117            F3 = 0x72,
118            F4 = 0x73,
119            F5 = 0x74,
120            F6 = 0x75,
121            F7 = 0x76,
122            F8 = 0x77,
123            F9 = 0x78,
124            F10 = 0x79,
125            F11 = 0x7A,
126            F12 = 0x7B,
127            OEM_1 = 0xBA,   // ',:' for US
128            OEM_PLUS = 0xBB,   // '+' any country
129            OEM_COMMA = 0xBC,   // ',' any country
130            OEM_MINUS = 0xBD,   // '-' any country
131            OEM_PERIOD = 0xBE,   // '.' any country
132            OEM_2 = 0xBF,   // '/?' for US
133            OEM_3 = 0xC0,   // '`~' for US
134            MEDIA_NEXT_TRACK = 0xB0,
135            MEDIA_PREV_TRACK = 0xB1,
136            MEDIA_STOP = 0xB2,
137            MEDIA_PLAY_PAUSE = 0xB3,
138            LWIN = 0x5B,
139            RWIN = 0x5C
140        }
141
142        public struct KEYBDINPUT
143        {
144            public ushort wVk;
145            public ushort wScan;
146            public uint dwFlags;
147            public long time;
148            public uint dwExtraInfo;
149        };
150
151        [StructLayout(LayoutKind.Explicit, Size = 28)]
152        public struct INPUT
153        {
154            [FieldOffset(0)]
155            public uint type;
156            [FieldOffset(4)]
157            public KEYBDINPUT ki;
158        };
159
160        public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
161        public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
162        public static readonly IntPtr HWND_TOP = new IntPtr(0);
163        public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
164
165        // From winuser.h
166        public const UInt32 SWP_NOSIZE = 0x0001;
167        public const UInt32 SWP_NOMOVE = 0x0002;
168        public const UInt32 SWP_NOZORDER = 0x0004;
169        public const UInt32 SWP_NOREDRAW = 0x0008;
170        public const UInt32 SWP_NOACTIVATE = 0x0010;
171        public const UInt32 SWP_FRAMECHANGED = 0x0020;  /* The frame changed: send WM_NCCALCSIZE */
172        public const UInt32 SWP_SHOWWINDOW = 0x0040;
173        public const UInt32 SWP_HIDEWINDOW = 0x0080;
174        public const UInt32 SWP_NOCOPYBITS = 0x0100;
175        public const UInt32 SWP_NOOWNERZORDER = 0x0200;  /* Don't do owner Z ordering */
176        public const UInt32 SWP_NOSENDCHANGING = 0x0400;  /* Don't send WM_WINDOWPOSCHANGING */
177
178        public const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
Notes
Because of synchronization issues, a few Thread.Sleeps are required, else the program will do things like trying to read the clipboard before its written to and not giving the window enough time to take focus before taking the screenshot. Sending ALT+Print Screen programmatically is dirty, but it works. Make sure you include the win32 COM wrappers at the bottom.