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

This commit is contained in:
Robin Krom 2022-02-06 21:21:40 +01:00
commit 4f3920d61a
No known key found for this signature in database
GPG key ID: BCC01364F1371490
4 changed files with 77 additions and 27 deletions

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
using System;
namespace Greenshot.Base.Core.Enums
{
[Flags]
public enum PrintWindowFlags : uint
{
/// <summary>Render the entire window.</summary>
PW_ENTIREWINDOW = 0,
/// <summary>Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.</summary>
PW_CLIENTONLY = 1,
/// <summary>Undocumented</summary>
PW_RENDERFULLCONTENT = 0x00000002,
}
}

View file

@ -1392,32 +1392,36 @@ namespace Greenshot.Base.Core
/// <summary> /// <summary>
/// Return an Image representing the Window! /// 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".
/// </summary> /// </summary>
public Image PrintWindow() public Image PrintWindow()
{ {
Rectangle windowRect = WindowRectangle; Rectangle windowRect = WindowRectangle;
// Start the capture // Start the capture
Exception exceptionOccured = null; Exception exceptionOccurred = null;
Image returnImage; Image returnImage;
using (Region region = GetRegion()) using (Region region = GetRegion())
{ {
var backgroundColor = Color.Black;
PixelFormat pixelFormat = PixelFormat.Format24bppRgb; PixelFormat pixelFormat = PixelFormat.Format24bppRgb;
// Only use 32 bpp ARGB when the window has a region // Only use 32 bpp ARGB when the window has a region
if (region != null) if (region != null)
{ {
pixelFormat = PixelFormat.Format32bppArgb; 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 Graphics graphics = Graphics.FromImage(returnImage);
using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) 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) if (!printSucceeded)
{ {
// something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC // something went wrong, most likely a "0x80004005" (Access Denied) when using UAC
exceptionOccured = User32.CreateWin32Exception("PrintWindow"); exceptionOccurred = User32.CreateWin32Exception("PrintWindow");
} }
} }
@ -1432,9 +1436,9 @@ namespace Greenshot.Base.Core
} }
// Return null if error // 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(); returnImage.Dispose();
return null; return null;
} }

View file

@ -121,7 +121,7 @@ namespace Greenshot.Base.UnmanagedHelpers
[DllImport("user32", SetLastError = true)] [DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [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)] [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);

View file

@ -969,6 +969,13 @@ namespace Greenshot.Helpers
// Take default screen // Take default screen
windowCaptureMode = WindowCaptureMode.Screen; windowCaptureMode = WindowCaptureMode.Screen;
// In https://github.com/greenshot/greenshot/issues/373 it was shown that PrintWindow (GDI) works great with Windows 11
if (WindowsVersion.IsWindows11OrLater)
{
windowCaptureMode = WindowCaptureMode.GDI;
}
else
{
// Change to GDI, if allowed // Change to GDI, if allowed
if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process))
{ {
@ -992,6 +999,7 @@ namespace Greenshot.Helpers
} }
} }
} }
}
else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent)
{ {
if (!dwmEnabled || (!windowToCapture.IsMetroApp && !WindowCapture.IsDwmAllowed(process))) if (!dwmEnabled || (!windowToCapture.IsMetroApp && !WindowCapture.IsDwmAllowed(process)))
@ -1034,7 +1042,7 @@ namespace Greenshot.Helpers
} }
tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); 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 // check if GDI capture any good, by comparing it with the screen content
int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false); int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false);