Revert of the change to the DWMWINDOWATTRIBUTE, as the enum values were not fixed we lost some functionality. Also fixed some potential issues with the ThumbnailForm, and aligned a bit of code with Dapplo.Window [skip ci]

This commit is contained in:
Robin Krom 2021-03-26 22:30:28 +01:00
commit b22d982f36
No known key found for this signature in database
GPG key ID: BCC01364F1371490
7 changed files with 174 additions and 102 deletions

View file

@ -918,7 +918,7 @@ namespace Greenshot.Forms {
private void ShowThumbnailOnEnter(object sender, EventArgs e) { private void ShowThumbnailOnEnter(object sender, EventArgs e) {
if (sender is not ToolStripMenuItem captureWindowItem) return; if (sender is not ToolStripMenuItem captureWindowItem) return;
WindowDetails window = captureWindowItem.Tag as WindowDetails; var window = captureWindowItem.Tag as WindowDetails;
if (_thumbnailForm == null) { if (_thumbnailForm == null) {
_thumbnailForm = new ThumbnailForm(); _thumbnailForm = new ThumbnailForm();
} }
@ -939,29 +939,39 @@ namespace Greenshot.Forms {
_thumbnailForm = null; _thumbnailForm = null;
} }
/// <summary>
/// Create the "capture window from list" list
/// </summary>
/// <param name="menuItem">ToolStripMenuItem</param>
/// <param name="eventHandler">EventHandler</param>
public void AddCaptureWindowMenuItems(ToolStripMenuItem menuItem, EventHandler eventHandler) { public void AddCaptureWindowMenuItems(ToolStripMenuItem menuItem, EventHandler eventHandler) {
menuItem.DropDownItems.Clear(); menuItem.DropDownItems.Clear();
// check if thumbnailPreview is enabled and DWM is enabled // check if thumbnailPreview is enabled and DWM is enabled
bool thumbnailPreview = _conf.ThumnailPreview && DWM.IsDwmEnabled; bool thumbnailPreview = _conf.ThumnailPreview && DWM.IsDwmEnabled;
foreach(WindowDetails window in WindowDetails.GetTopLevelWindows()) { foreach(var window in WindowDetails.GetTopLevelWindows()) {
if (LOG.IsDebugEnabled)
{
LOG.Debug(window.ToString());
}
string title = window.Text; string title = window.Text;
if (title != null) { if (string.IsNullOrEmpty(title))
if (title.Length > _conf.MaxMenuItemLength) { {
title = title.Substring(0, Math.Min(title.Length, _conf.MaxMenuItemLength)); continue;
} }
ToolStripItem captureWindowItem = menuItem.DropDownItems.Add(title); if (title.Length > _conf.MaxMenuItemLength) {
captureWindowItem.Tag = window; title = title.Substring(0, Math.Min(title.Length, _conf.MaxMenuItemLength));
captureWindowItem.Image = window.DisplayIcon; }
captureWindowItem.Click += eventHandler; ToolStripItem captureWindowItem = menuItem.DropDownItems.Add(title);
// Only show preview when enabled captureWindowItem.Tag = window;
if (thumbnailPreview) { captureWindowItem.Image = window.DisplayIcon;
captureWindowItem.MouseEnter += ShowThumbnailOnEnter; captureWindowItem.Click += eventHandler;
captureWindowItem.MouseLeave += HideThumbnailOnLeave; // Only show preview when enabled
} if (thumbnailPreview) {
} captureWindowItem.MouseEnter += ShowThumbnailOnEnter;
} captureWindowItem.MouseLeave += HideThumbnailOnLeave;
}
}
} }
private void CaptureAreaToolStripMenuItemClick(object sender, EventArgs e) { private void CaptureAreaToolStripMenuItemClick(object sender, EventArgs e) {

View file

@ -970,7 +970,7 @@ namespace Greenshot.Helpers {
// The following, to be precise the HideApp, causes the app to close as described in BUG-1620 // The following, to be precise the HideApp, causes the app to close as described in BUG-1620
// Added check for metro (Modern UI) apps, which might be maximized and cover the screen. // Added check for metro (Modern UI) apps, which might be maximized and cover the screen.
//foreach(WindowDetails app in WindowDetails.GetMetroApps()) { //foreach(WindowDetails app in WindowDetails.GetAppWindows()) {
// if (app.Maximised) { // if (app.Maximised) {
// app.HideApp(); // app.HideApp();
// } // }

View file

@ -22,6 +22,7 @@ using System;
using System.Windows.Forms; using System.Windows.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using System.Drawing; using System.Drawing;
using GreenshotPlugin.Core.Enums;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers;
using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Enums;
@ -32,7 +33,7 @@ namespace GreenshotPlugin.Controls {
/// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture.
/// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform.
/// </summary> /// </summary>
public class ThumbnailForm : FormWithoutActivation { public sealed class ThumbnailForm : FormWithoutActivation {
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
private IntPtr _thumbnailHandle = IntPtr.Zero; private IntPtr _thumbnailHandle = IntPtr.Zero;
@ -59,12 +60,13 @@ namespace GreenshotPlugin.Controls {
base.Hide(); base.Hide();
} }
private void UnregisterThumbnail() { private void UnregisterThumbnail()
if (_thumbnailHandle != IntPtr.Zero) { {
DWM.DwmUnregisterThumbnail(_thumbnailHandle); if (_thumbnailHandle == IntPtr.Zero) return;
_thumbnailHandle = IntPtr.Zero;
} DWM.DwmUnregisterThumbnail(_thumbnailHandle);
} _thumbnailHandle = IntPtr.Zero;
}
/// <summary> /// <summary>
/// Show the thumbnail of the supplied window above (or under) the parent Control /// Show the thumbnail of the supplied window above (or under) the parent Control
@ -75,41 +77,60 @@ namespace GreenshotPlugin.Controls {
UnregisterThumbnail(); UnregisterThumbnail();
DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle);
if (_thumbnailHandle != IntPtr.Zero) { if (_thumbnailHandle == IntPtr.Zero) return;
DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize);
int thumbnailHeight = 200;
int thumbnailWidth = (int)(thumbnailHeight * (sourceSize.Width / (float)sourceSize.Height));
if (parentControl != null && thumbnailWidth > parentControl.Width) {
thumbnailWidth = parentControl.Width;
thumbnailHeight = (int)(thumbnailWidth * (sourceSize.Height / (float)sourceSize.Width));
}
Width = thumbnailWidth;
Height = thumbnailHeight;
// Prepare the displaying of the Thumbnail
DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES
{
Opacity = 255,
Visible = true,
SourceClientAreaOnly = false,
Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight)
};
DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref props);
if (parentControl != null) {
AlignToControl(parentControl);
}
if (!Visible) { var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize);
Show(); if (result.Failed())
} {
// Make sure it's on "top"! DWM.DwmUnregisterThumbnail(_thumbnailHandle);
if (parentControl != null) { return;
User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); }
}
} if (sourceSize.IsEmpty)
} {
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
return;
}
int thumbnailHeight = 200;
int thumbnailWidth = (int)(thumbnailHeight * (sourceSize.Width / (float)sourceSize.Height));
if (parentControl != null && thumbnailWidth > parentControl.Width)
{
thumbnailWidth = parentControl.Width;
thumbnailHeight = (int)(thumbnailWidth * (sourceSize.Height / (float)sourceSize.Width));
}
Width = thumbnailWidth;
Height = thumbnailHeight;
// Prepare the displaying of the Thumbnail
var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES
{
Opacity = 255,
Visible = true,
SourceClientAreaOnly = false,
Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight)
};
result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties);
if (result.Failed())
{
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
return;
}
if (parentControl != null) {
AlignToControl(parentControl);
}
if (!Visible) {
Show();
}
// Make sure it's on "top"!
if (parentControl != null) {
User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE);
}
}
public void AlignToControl(Control alignTo) { public void AlignToControl(Control alignTo) {
Rectangle screenBounds = WindowCapture.GetScreenBounds(); var screenBounds = WindowCapture.GetScreenBounds();
if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) { if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) {
Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height);
} else { } else {

View file

@ -2,7 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -25,11 +27,11 @@ namespace GreenshotPlugin.Core
/// ///
/// Provides details about a Window returned by the enumeration /// Provides details about a Window returned by the enumeration
/// </summary> /// </summary>
public class WindowDetails : IEquatable<WindowDetails>{ public class WindowDetails : IEquatable<WindowDetails> {
private const string MetroWindowsClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1)
private const string FramedAppClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow
private const string MetroApplauncherClass = "ImmersiveLauncher"; private const string ApplauncherClass = "ImmersiveLauncher";
private const string MetroGutterClass = "ImmersiveGutter"; private const string GutterClass = "ImmersiveGutter";
private static readonly IList<string> IgnoreClasses = new List<string>(new[] { "Progman", "Button", "Dwm" }); //"MS-SDIa" private static readonly IList<string> IgnoreClasses = new List<string>(new[] { "Progman", "Button", "Dwm" }); //"MS-SDIa"
private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails));
@ -72,23 +74,28 @@ namespace GreenshotPlugin.Core
/// This checks if the window is a Windows 8 App /// This checks if the window is a Windows 8 App
/// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow"
/// </summary> /// </summary>
public bool IsApp => MetroWindowsClass.Equals(ClassName); public bool IsApp => AppWindowClass.Equals(ClassName);
/// <summary> /// <summary>
/// This checks if the window is a Windows 10 App /// This checks if the window is a Windows 10 App
/// For Windows 10 apps are hosted inside "ApplicationFrameWindow" /// For Windows 10 apps are hosted inside "ApplicationFrameWindow"
/// </summary> /// </summary>
public bool IsWin10App => FramedAppClass.Equals(ClassName); public bool IsWin10App => AppFrameWindowClass.Equals(ClassName);
/// <summary>
/// Check if this window belongs to a background app
/// </summary>
public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && !Children.Any(window => string.Equals(window.ClassName, AppWindowClass));
/// <summary> /// <summary>
/// Check if the window is the metro gutter (sizeable separator) /// Check if the window is the metro gutter (sizeable separator)
/// </summary> /// </summary>
public bool IsGutter => MetroGutterClass.Equals(ClassName); public bool IsGutter => GutterClass.Equals(ClassName);
/// <summary> /// <summary>
/// Test if this window is for the App-Launcher /// Test if this window is for the App-Launcher
/// </summary> /// </summary>
public bool IsAppLauncher => MetroApplauncherClass.Equals(ClassName); public bool IsAppLauncher => ApplauncherClass.Equals(ClassName);
/// <summary> /// <summary>
/// Check if this window is the window of a metro app /// Check if this window is the window of a metro app
@ -447,7 +454,7 @@ namespace GreenshotPlugin.Core
/// </summary> /// </summary>
public bool Visible { public bool Visible {
get { get {
// Tip from Raymond Chen // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507
if (IsCloaked) if (IsCloaked)
{ {
return false; return false;
@ -1337,7 +1344,7 @@ namespace GreenshotPlugin.Core
/// <returns>List WindowDetails with all the visible top level windows</returns> /// <returns>List WindowDetails with all the visible top level windows</returns>
public static IEnumerable<WindowDetails> GetVisibleWindows() { public static IEnumerable<WindowDetails> GetVisibleWindows() {
Rectangle screenBounds = WindowCapture.GetScreenBounds(); Rectangle screenBounds = WindowCapture.GetScreenBounds();
foreach(var window in GetMetroApps()) { foreach(var window in GetAppWindows()) {
if (IsVisible(window, screenBounds)) if (IsVisible(window, screenBounds))
{ {
yield return window; yield return window;
@ -1357,37 +1364,24 @@ namespace GreenshotPlugin.Core
/// These are all Windows with Classname "Windows.UI.Core.CoreWindow" /// These are all Windows with Classname "Windows.UI.Core.CoreWindow"
/// </summary> /// </summary>
/// <returns>List WindowDetails with visible metro apps</returns> /// <returns>List WindowDetails with visible metro apps</returns>
public static IEnumerable<WindowDetails> GetMetroApps() { public static IEnumerable<WindowDetails> GetAppWindows() {
// if the appVisibility != null we have Windows 8. // if the appVisibility != null we have Windows 8.
if (AppVisibility == null) if (AppVisibility == null)
{ {
yield break; yield break;
} }
//string[] wcs = {"ImmersiveGutter", "Snapped Desktop", "ImmersiveBackgroundWindow","ImmersiveLauncher","Windows.UI.Core.CoreWindow","ApplicationManager_ImmersiveShellWindow","SearchPane","MetroGhostWindow","EdgeUiInputWndClass", "NativeHWNDHost", "Shell_CharmWindow"}; var nextHandle = User32.FindWindow(AppWindowClass, null);
//List<WindowDetails> specials = new List<WindowDetails>();
//foreach(string wc in wcs) {
// IntPtr wcHandle = User32.FindWindow(null, null);
// while (wcHandle != IntPtr.Zero) {
// WindowDetails special = new WindowDetails(wcHandle);
// if (special.WindowRectangle.Left >= 1920 && special.WindowRectangle.Size != Size.Empty) {
// specials.Add(special);
// LOG.DebugFormat("Found special {0} : {1} at {2} visible: {3} {4} {5}", special.ClassName, special.Text, special.WindowRectangle, special.Visible, special.ExtendedWindowStyle, special.WindowStyle);
// }
// wcHandle = User32.FindWindowEx(IntPtr.Zero, wcHandle, null, null);
// };
//}
IntPtr nextHandle = User32.FindWindow(MetroWindowsClass, null);
while (nextHandle != IntPtr.Zero) { while (nextHandle != IntPtr.Zero) {
var metroApp = new WindowDetails(nextHandle); var metroApp = new WindowDetails(nextHandle);
yield return metroApp; yield return metroApp;
// Check if we have a gutter! // Check if we have a gutter!
if (metroApp.Visible && !metroApp.Maximised) { if (metroApp.Visible && !metroApp.Maximised) {
var gutterHandle = User32.FindWindow(MetroGutterClass, null); var gutterHandle = User32.FindWindow(GutterClass, null);
if (gutterHandle != IntPtr.Zero) { if (gutterHandle != IntPtr.Zero) {
yield return new WindowDetails(gutterHandle); yield return new WindowDetails(gutterHandle);
} }
} }
nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, MetroWindowsClass, null); nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null);
} }
} }
@ -1398,21 +1392,10 @@ namespace GreenshotPlugin.Core
/// <returns>bool</returns> /// <returns>bool</returns>
private static bool IsTopLevel(WindowDetails window) private static bool IsTopLevel(WindowDetails window)
{ {
// Window is not on this desktop
if (window.IsCloaked) if (window.IsCloaked)
{ {
return false; return false;
} }
// Ignore windows without title
if (window.Text.Length == 0)
{
return false;
}
if (IgnoreClasses.Contains(window.ClassName))
{
return false;
}
// Windows without size // Windows without size
if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0)
{ {
@ -1437,7 +1420,21 @@ namespace GreenshotPlugin.Core
{ {
return false; return false;
} }
return window.Visible || window.Iconic; // Ignore windows without title
if (window.Text.Length == 0)
{
return false;
}
if (IgnoreClasses.Contains(window.ClassName))
{
return false;
}
if (!(window.Visible || window.Iconic))
{
return false;
}
return !window.IsBackgroundWin10App;
} }
/// <summary> /// <summary>
@ -1445,7 +1442,7 @@ namespace GreenshotPlugin.Core
/// </summary> /// </summary>
/// <returns>List WindowDetails with all the top level windows</returns> /// <returns>List WindowDetails with all the top level windows</returns>
public static IEnumerable<WindowDetails> GetTopLevelWindows() { public static IEnumerable<WindowDetails> GetTopLevelWindows() {
foreach (var possibleTopLevel in GetMetroApps()) foreach (var possibleTopLevel in GetAppWindows())
{ {
if (IsTopLevel(possibleTopLevel)) if (IsTopLevel(possibleTopLevel))
{ {
@ -1523,7 +1520,7 @@ namespace GreenshotPlugin.Core
if (AppVisibility == null) { if (AppVisibility == null) {
return null; return null;
} }
IntPtr appLauncher = User32.FindWindow(MetroApplauncherClass, null); IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null);
if (appLauncher != IntPtr.Zero) { if (appLauncher != IntPtr.Zero) {
return new WindowDetails (appLauncher); return new WindowDetails (appLauncher);
} }
@ -1542,5 +1539,32 @@ namespace GreenshotPlugin.Core
return false; return false;
} }
} }
/// <summary>
/// Make a string representation of the window details
/// </summary>
/// <returns>string</returns>
public override string ToString()
{
var result = new StringBuilder();
result.AppendLine($"Text: {Text}");
result.AppendLine($"ClassName: {ClassName}");
result.AppendLine($"ExtendedWindowStyle: {ExtendedWindowStyle}");
result.AppendLine($"WindowStyle: {WindowStyle}");
result.AppendLine($"Size: {WindowRectangle.Size}");
result.AppendLine($"HasParent: {HasParent}");
result.AppendLine($"IsWin10App: {IsWin10App}");
result.AppendLine($"IsApp: {IsApp}");
result.AppendLine($"Visible: {Visible}");
result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}");
result.AppendLine($"IsCloaked: {IsCloaked}");
result.AppendLine($"Iconic: {Iconic}");
result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}");
if (HasChildren)
{
result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}");
}
return result.ToString();
}
} }
} }

View file

@ -23,6 +23,7 @@ using System;
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Core.Enums;
using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Enums;
using GreenshotPlugin.UnmanagedHelpers.Structs; using GreenshotPlugin.UnmanagedHelpers.Structs;
using Microsoft.Win32; using Microsoft.Win32;
@ -40,9 +41,9 @@ namespace GreenshotPlugin.UnmanagedHelpers {
[DllImport("dwmapi", SetLastError = true)] [DllImport("dwmapi", SetLastError = true)]
public static extern int DwmUnregisterThumbnail(IntPtr thumb); public static extern int DwmUnregisterThumbnail(IntPtr thumb);
[DllImport("dwmapi", SetLastError = true)] [DllImport("dwmapi", SetLastError = true)]
public static extern int DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size);
[DllImport("dwmapi", SetLastError = true)] [DllImport("dwmapi", SetLastError = true)]
public static extern int DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props);
// Deprecated as of Windows 8 Release Preview // Deprecated as of Windows 8 Release Preview
[DllImport("dwmapi", SetLastError = true)] [DllImport("dwmapi", SetLastError = true)]

View file

@ -26,7 +26,21 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums
[SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DWMWINDOWATTRIBUTE : uint public enum DWMWINDOWATTRIBUTE : uint
{ {
DWMWA_NCRENDERING_ENABLED = 1,
DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT,
DWMWA_CAPTION_BUTTON_BOUNDS,
DWMWA_NONCLIENT_RTL_LAYOUT,
DWMWA_FORCE_ICONIC_REPRESENTATION,
DWMWA_FLIP3D_POLICY,
DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista
DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7
DWMWA_DISALLOW_PEEK, // Since Windows 7
DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7
DWMWA_CLOAK, // Since Windows 8
DWMWA_CLOAKED, // Since Windows 8 DWMWA_CLOAKED, // Since Windows 8
DWMWA_FREEZE_REPRESENTATION, // Since Windows 8
DWMWA_LAST
} }
} }

View file

@ -40,5 +40,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs {
public Size ToSize() { public Size ToSize() {
return new Size(Width, Height); return new Size(Width, Height);
} }
public bool IsEmpty => Width * Height == 0;
} }
} }