Page 1 of 1

Window Image Capture (Snapshot)

Posted: Sun Aug 10, 2014 5:05 pm
by Rescator
I was looking into adding a window capture feature to a project here, this could be used to capture a window and save it as a image.
Nice for debugging or users reporting errors or issues.

I got some of the ideas from another thread, but ended up re-writing the capture code.

There are 4 modes you can choose between, my favorite ones are mode 0 and mode 1.

Mode 3 while it looks great does grab underlying pixels of a window too (but retains the Vista+ borders). and Mode 2 crops off the borders on Vista+.

Mode 0 is a "non-aero" capture provided by the OS, this will probably have a different non-client area, on Windows 8+ aero is always forced so I have no idea how the non-client area looks in that case (how it looks on 8.1 would be interesting to see).

Mode 1 captures the client area only (no borders, no menu etc. if your window is borderless then this captures the entire window.)
This mode is the one I like the most of all as it's consistent (with the borders) over all Windows OS, and will probably be the most "neutral" look for a user manual as the border/frame varies from system to system anyway.

The example code will cause 4 images (showing all 4 modes) to be created when you click on the button. The images is saved in the user directory which is usually C:\Users\<username>\ on Vista and later.

The code was tested on x86 and x64, Unicode and Ascii, and is thread safe (the procedure is).

Also note that the source is under the zlib license which would normally require a attribution but that I specifically state that attribution is not required. Which makes this as close to public domain as possible (technically speaking you can't place anything "in" the public domain, only that which have their copyright expired or which is anonymous is truly public domain).

Code: Select all

;Window_ImageCapture v1.0
;© 2014 Roger Hågensen, httP://emsai.net/
;zlib License http://en.wikipedia.org/wiki/Zlib_License
;No attribution required.

EnableExplicit

Prototype.l PrintWindow_(hwnd.i, hdc.i, flag.l)

Prototype.l DwmGetWindowAttribute_(hwnd.i, dwAttribute.l, *pvAttribute, cbAttribute.l)
#DWMWA_EXTENDED_FRAME_BOUNDS = 9

#CAPTUREBLT = $40000000 

;If mode is 0 then PrintWindow is used to get the window.
;If mode is 1 then PrintWindow is used to get the client area.
;If mode is 2 then the window bitmap is copied (part of window border may get clipped on W2K/XP).
;If PrintWindow is not available the mode defaults to 2.
;Image is returned on success, #Null on failure.
Procedure.i Window_ImageCapture(image.i, window.i, mode.i)
	Protected result.i, hwnd.i, dll_user32.i, dll_dwmapi.i, dstdc.i, srcdc.i
	Protected PrintWindow_.PrintWindow_, DwmGetWindowAttribute_.DwmGetWindowAttribute_
	Protected rect.RECT, w.l, h.l

	hwnd = WindowID(window)
	If hwnd
		If (mode = 0) Or (mode = 1)
			dll_user32 = OpenLibrary(#PB_Any, "user32.dll")
			If dll_user32
				PrintWindow_ = GetFunction(dll_user32, "PrintWindow") ;Windows XP+
			EndIf   
			If PrintWindow_ = #Null
				mode = 3
			EndIf
		EndIf

		If mode = 1
         w = WindowWidth(window, #PB_Window_InnerCoordinate)
         h = WindowHeight(window, #PB_Window_InnerCoordinate)
      Else
      	If mode = 2
				dll_dwmapi = OpenLibrary(#PB_Any, "dwmapi.dll")
				If dll_dwmapi
					DwmGetWindowAttribute_ = GetFunction(dll_dwmapi, "DwmGetWindowAttribute") ;Windows Vista+
				EndIf
      	EndIf
      	If DwmGetWindowAttribute_ <> #Null
				If DwmGetWindowAttribute_(hwnd, #DWMWA_EXTENDED_FRAME_BOUNDS, rect, SizeOf(rect)) = #S_OK
					w = rect\right - rect\left
					h = rect\bottom - rect\top
				EndIf
      	Else
				If GetWindowRect_(hwnd, rect)
					w = rect\right - rect\left
					h = rect\bottom - rect\top
		      EndIf
      	EndIf
      EndIf

		If (w <> 0) And (h <> 0)
			result = CreateImage(image, w, h)
			If result
				If image = #PB_Any
					image = result
				EndIf

				If mode = 0

					dstdc = StartDrawing(ImageOutput(image))
					If dstdc
						result = PrintWindow_(hwnd, dstdc, #Null)
						StopDrawing()
					EndIf

				ElseIf mode = 1

					dstdc = StartDrawing(ImageOutput(image))
					If dstdc
						result = PrintWindow_(hwnd, dstdc, #PW_CLIENTONLY)
						StopDrawing()
					EndIf

				ElseIf mode = 2

					srcdc = GetWindowDC_(#Null)
					If srcdc
						dstdc = StartDrawing(ImageOutput(image))
						If dstdc
							result = BitBlt_(dstdc, 0, 0, w, h, srcdc, rect\left, rect\top, #SRCCOPY | #CAPTUREBLT)
							StopDrawing()
						EndIf
						DeleteDC_(srcdc)
					EndIf

				ElseIf mode = 3

					srcdc = GetWindowDC_(hwnd)
					If srcdc
						dstdc = StartDrawing(ImageOutput(image))
						If dstdc
							result = BitBlt_(dstdc, 0, 0, w, h, srcdc, 0, 0, #SRCCOPY)
							StopDrawing()
						EndIf
						DeleteDC_(srcdc)
					EndIf

				EndIf

			EndIf
			If result = #False
				If IsImage(image)
					FreeImage(image)
				EndIf
			Else
				result = image
			EndIF
		EndIf

		If dll_user32
			CloseLibrary(dll_user32)
		EndIf
		If dll_dwmapi
			CloseLibrary(dll_dwmapi)
		EndIf
	EndIf
	ProcedureReturn result
EndProcedure

;Example
OpenWindow(0, 0, 0, 320, 240, "Window_ImageCapture",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
SetWindowColor(0, $7f007f)
ButtonGadget(0, 24, 192, 96, 32, "Snapshot")

Define quit.i, n.i

Repeat
	Select WaitWindowEvent()

		Case #PB_Event_Gadget
			Select EventGadget()
				Case 0
					Window_ImageCapture(0, 0, 0)
					If IsImage(0)
						SaveImage(0, GetHomeDirectory() + Str(n)+"_mode0.bmp", #PB_ImagePlugin_BMP)
					EndIf
					Window_ImageCapture(0, 0, 1)
					If IsImage(0)
						SaveImage(0, GetHomeDirectory() + Str(n)+"_mode1.bmp", #PB_ImagePlugin_BMP)
					EndIf
					Window_ImageCapture(0, 0, 2)
					If IsImage(0)
						SaveImage(0, GetHomeDirectory() + Str(n)+"_mode2.bmp", #PB_ImagePlugin_BMP)
					EndIf
					Window_ImageCapture(0, 0, 3)
					If IsImage(0)
						SaveImage(0, GetHomeDirectory() + Str(n)+"_mode3.bmp", #PB_ImagePlugin_BMP)
					EndIf
					n + 1
			EndSelect

		Case #PB_Event_CloseWindow
			quit = 1

	EndSelect
Until quit = 1

Re: Window Image Capture (Snapshot)

Posted: Tue Aug 12, 2014 1:05 pm
by Kwai chang caine
Works great !!
Thanks for sharing 8)