From 4f3920d61a61ddd6cca9f671b65ab8e89c9f4b1a Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 6 Feb 2022 21:21:40 +0100 Subject: [PATCH] Changed the default window capture for Windows 11 to use User32.PrintWindow (called GDI internally), which should solve #326. The background for this can be read in #373 --- .../Core/Enums/PrintWindowFlags.cs | 38 +++++++++++++++++ src/Greenshot.Base/Core/WindowDetails.cs | 22 ++++++---- src/Greenshot.Base/UnmanagedHelpers/User32.cs | 2 +- src/Greenshot/Helpers/CaptureHelper.cs | 42 +++++++++++-------- 4 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs diff --git a/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs b/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs new file mode 100644 index 000000000..6d18cdbe6 --- /dev/null +++ b/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs @@ -0,0 +1,38 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Core.Enums +{ + [Flags] + public enum PrintWindowFlags : uint + { + /// Render the entire window. + PW_ENTIREWINDOW = 0, + + /// Only the client area of the window is copied to hdcBlt. By default, the entire window is copied. + PW_CLIENTONLY = 1, + + /// Undocumented + PW_RENDERFULLCONTENT = 0x00000002, + } +} diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index 91ee52de1..be244bb6f 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -1392,32 +1392,36 @@ namespace Greenshot.Base.Core /// /// Return an Image representing the Window! - /// As GDI+ draws it, it will be without Aero borders! + /// For Windows 7, as GDI+ draws it, it will be without Aero borders! + /// For Windows 10+, there is an option PW_RENDERFULLCONTENT, which makes sure the capture is "as is". /// public Image PrintWindow() { Rectangle windowRect = WindowRectangle; // Start the capture - Exception exceptionOccured = null; + Exception exceptionOccurred = null; Image returnImage; using (Region region = GetRegion()) { + var backgroundColor = Color.Black; PixelFormat pixelFormat = PixelFormat.Format24bppRgb; // Only use 32 bpp ARGB when the window has a region if (region != null) { pixelFormat = PixelFormat.Format32bppArgb; + backgroundColor = Color.Transparent; } - - returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); + + returnImage = ImageHelper.CreateEmpty(windowRect.Width, windowRect.Height, pixelFormat, backgroundColor, 96,96); using Graphics graphics = Graphics.FromImage(returnImage); using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) { - bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); + var pwFlags = WindowsVersion.IsWindows10OrLater ? PrintWindowFlags.PW_RENDERFULLCONTENT : PrintWindowFlags.PW_ENTIREWINDOW; + bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), pwFlags); if (!printSucceeded) { - // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC - exceptionOccured = User32.CreateWin32Exception("PrintWindow"); + // something went wrong, most likely a "0x80004005" (Access Denied) when using UAC + exceptionOccurred = User32.CreateWin32Exception("PrintWindow"); } } @@ -1432,9 +1436,9 @@ namespace Greenshot.Base.Core } // Return null if error - if (exceptionOccured != null) + if (exceptionOccurred != null) { - Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); + Log.ErrorFormat("Error calling print window: {0}", exceptionOccurred.Message); returnImage.Dispose(); return null; } diff --git a/src/Greenshot.Base/UnmanagedHelpers/User32.cs b/src/Greenshot.Base/UnmanagedHelpers/User32.cs index 67a18ffeb..9764c3a89 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/User32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/User32.cs @@ -121,7 +121,7 @@ namespace Greenshot.Base.UnmanagedHelpers [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); + public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, PrintWindowFlags pwFlags); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 662f3439a..3d0d3385d 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -969,26 +969,34 @@ namespace Greenshot.Helpers // Take default screen windowCaptureMode = WindowCaptureMode.Screen; - // Change to GDI, if allowed - if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) + // In https://github.com/greenshot/greenshot/issues/373 it was shown that PrintWindow (GDI) works great with Windows 11 + if (WindowsVersion.IsWindows11OrLater) { - if (!dwmEnabled && IsWpf(process)) - { - // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF - Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); - } - else - { - windowCaptureMode = WindowCaptureMode.GDI; - } + windowCaptureMode = WindowCaptureMode.GDI; } - - // Change to DWM, if enabled and allowed - if (dwmEnabled) + else { - if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + // Change to GDI, if allowed + if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) { - windowCaptureMode = WindowCaptureMode.Aero; + if (!dwmEnabled && IsWpf(process)) + { + // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF + Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); + } + else + { + windowCaptureMode = WindowCaptureMode.GDI; + } + } + + // Change to DWM, if enabled and allowed + if (dwmEnabled) + { + if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + { + windowCaptureMode = WindowCaptureMode.Aero; + } } } } @@ -1034,7 +1042,7 @@ namespace Greenshot.Helpers } tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); - if (tmpCapture != null) + if (tmpCapture != null && !WindowsVersion.IsWindows11OrLater) { // check if GDI capture any good, by comparing it with the screen content int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false);