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>
/// 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>
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;
}

View file

@ -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);

View file

@ -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);