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