Well, give PrintWindow
a try.
This function issues a WM_PRINT
or WM_PRINTCLIENT
message (depending on the flags specified), so the Window that receives and processes the message prints itself to the hDC
passed in the function call.
► The Window can be completely obscured by another, it doesn't matter, it's not a screenshot. The Window has to process the message, though.
The static (Shared
) RenderWindow
method shown here, returns a Bitmap object generated by the PrintWindow function.
You should try to pass True
as the clientAreaOnly
argument, to set PW_CLIENTONLY
as the nFlags
option, because many WPF apps are designed to hide the default Window Frame, while WinForms Windows usually don't, so try to pass False
in this case.
The optional tryGetFullContent
argument sets the PW_RENDERFULLCONTENT
flag, which is available from Windows 8.1+. This flag is not documented.
UPDATE: in this case, it's what gets the job done.
To get the Handle of the Window you care about, you have many options.
Process.GetProcessesByName("processName").FirstOrDefault(...)
or Process.GetProcessById(id)
, if you know the Process Id.
Or FindWindowEx, or EnumWindows, or EnumDesktopWindows, depending on the context.
See here: How to obtain task bar Notification Area width for a simple use of the FindWindowEx
function.
Assuming you have a WinForms app, you can call the method like this, to show a Bitmap of the rendered Window in a PictureBox:
Dim proc = Process.GetProcessesByName("WINWORD").FirstOrDefault(Function(p) p.MainWindowHandle <> IntPtr.Zero)
If proc IsNot Nothing Then
PictureBox1.Image = RenderWindow(proc.MainWindowHandle, True)
End If
Win32 Declarations and implementation of the RenderWindow method:
► Here, I'm using DwmGetWindowAttribute, specifying DWMWA_EXTENDED_FRAME_BOUNDS
as the attribute, to retrieve the Window rectangle.
You could also use GetWindowRect, but this function is not DpiAware (and a bit old :), it may return a wrong size in specific conditions.
Public Shared Function RenderWindow(hWnd As IntPtr, clientAreaOnly As Boolean, Optional tryGetFullContent As Boolean = False) As Bitmap
Dim printOption = If(clientAreaOnly, PrintWindowOptions.PW_CLIENTONLY, PrintWindowOptions.PW_DEFAULT)
printOption = If(tryGetFullContent, PrintWindowOptions.PW_RENDERFULLCONTENT, printOption)
Dim dwmRect = New Rectangle()
Dim hResult = DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, dwmRect, Marshal.SizeOf(Of Rectangle)())
If hResult < 0 Then
Marshal.ThrowExceptionForHR(hResult)
Return Nothing
End If
Dim bmp = New Bitmap(dwmRect.Width, dwmRect.Height)
Using g = Graphics.FromImage(bmp)
Dim hDC = g.GetHdc()
Try
Dim success = PrintWindow(hWnd, hDC, printOption)
' success result not fully handled here
If Not success Then
Dim win32Error = Marshal.GetLastWin32Error()
Return Nothing
End If
Return bmp
Finally
g.ReleaseHdc(hDC)
End Try
End Using
End Function
Native methods:
<DllImport("user32.dll", SetLastError:=True)>
Friend Shared Function PrintWindow(hwnd As IntPtr, hDC As IntPtr, nFlags As UInteger) As Boolean
End Function
<DllImport("dwmapi.dll", SetLastError:=True)>
Friend Shared Function DwmGetWindowAttribute(hwnd As IntPtr, dwAttribute As DWMWINDOWATTRIBUTE, ByRef pvAttribute As Rectangle, cbAttribute As Integer) As Integer
End Function
Public Enum DWMWINDOWATTRIBUTE As UInteger
DWMWA_NCRENDERING_ENABLED = 1 ' [get] Is non-client rendering enabled/disabled
DWMWA_NCRENDERING_POLICY ' [set] DWMNCRENDERINGPOLICY - Non-client rendering policy
DWMWA_TRANSITIONS_FORCEDISABLED ' [set] Potentially enable/forcibly disable transitions
DWMWA_ALLOW_NCPAINT ' [set] Allow contents rendered In the non-client area To be visible On the DWM-drawn frame.
DWMWA_CAPTION_BUTTON_BOUNDS ' [get] Bounds Of the caption button area In window-relative space.
DWMWA_NONCLIENT_RTL_LAYOUT ' [set] Is non-client content RTL mirrored
DWMWA_FORCE_ICONIC_REPRESENTATION ' [set] Force this window To display iconic thumbnails.
DWMWA_FLIP3D_POLICY ' [set] Designates how Flip3D will treat the window.
DWMWA_EXTENDED_FRAME_BOUNDS ' [get] Gets the extended frame bounds rectangle In screen space
DWMWA_HAS_ICONIC_BITMAP ' [set] Indicates an available bitmap When there Is no better thumbnail representation.
DWMWA_DISALLOW_PEEK ' [set] Don't invoke Peek on the window.
DWMWA_EXCLUDED_FROM_PEEK ' [set] LivePreview exclusion information
DWMWA_CLOAK ' [set] Cloak Or uncloak the window
DWMWA_CLOAKED ' [get] Gets the cloaked state Of the window
DWMWA_FREEZE_REPRESENTATION ' [set] BOOL, Force this window To freeze the thumbnail without live update
DWMWA_LAST
End Enum
Public Enum PrintWindowOptions As UInteger
PW_DEFAULT = 0
PW_CLIENTONLY = 1
PW_RENDERFULLCONTENT = 2
End Enum