Improved the support for dragging and dropping images from a website, now also parsing HTML img src information, to be able to download that image. For this we need the HtmlAgilityPack.dll (#294)

Removed a lot of dead code, and remove the old OCR code as we don't even know if it still works.
This commit is contained in:
Robin Krom 2021-03-21 22:34:17 +01:00 committed by GitHub
commit 26fe579d31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
151 changed files with 1138 additions and 8174 deletions

View file

@ -91,35 +91,7 @@ namespace GreenshotPlugin.Core {
}
}
public void ActivateIETab(string tabCaptionToActivate) {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
if (tab.Name == tabCaptionToActivate) {
tab.Activate();
return;
}
}
}
}
}
public void CloseIETab(string tabCaptionToClose) {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
if (tab.Name == tabCaptionToClose) {
foreach (var CloseTab in tab.Children) {
CloseTab.Activate();
}
return;
}
}
}
}
}
public void ActivateIETab(int tabIndexToActivate) {
public void ActivateIETab(int tabIndexToActivate) {
var index = 0;
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
@ -138,50 +110,7 @@ namespace GreenshotPlugin.Core {
}
}
public string IEActiveTabUrl {
get {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
object tabIndex = tab.accessible.get_accState(CHILDID_SELF);
if ((int)tabIndex == IE_ACTIVE_TAB) {
var description = tab.accessible.get_accDescription(CHILDID_SELF);
if (!string.IsNullOrEmpty(description)) {
if (description.Contains(Environment.NewLine)) {
var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim();
return url;
}
}
}
}
}
}
return string.Empty;
}
}
public int IEActiveTabIndex {
get {
var index = 0;
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
object tabIndex = tab.accessible.get_accState(0);
if ((int)tabIndex == IE_ACTIVE_TAB) {
return index;
}
index++;
}
}
}
return -1;
}
}
public string IEActiveTabCaption {
public string IEActiveTabCaption {
get {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
@ -238,21 +167,8 @@ namespace GreenshotPlugin.Core {
}
}
}
public int IETabCount {
get {
foreach (Accessible accessor in Children) {
foreach (var child in accessor.Children) {
foreach (var tab in child.Children) {
return child.ChildCount - 1;
}
}
}
return 0;
}
}
private Accessible(IAccessible acc) {
private Accessible(IAccessible acc) {
accessible = acc ?? throw new Exception();
}

View file

@ -1,5 +1,25 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using GreenshotPlugin.Interfaces;
@ -14,7 +34,6 @@ namespace GreenshotPlugin.Core
/// </summary>
public class Capture : ICapture {
private static readonly ILog Log = LogManager.GetLogger(typeof(Capture));
private List<ICaptureElement> _elements = new List<ICaptureElement>();
private Rectangle _screenBounds;
/// <summary>
@ -178,15 +197,6 @@ namespace GreenshotPlugin.Core
// TODO: Remove invisible lines/words?
CaptureDetails.OcrInformation?.Offset(-cropRectangle.Location.X, -cropRectangle.Location.Y);
// Remove invisible elements
var visibleElements = new List<ICaptureElement>();
foreach(var captureElement in _elements) {
if (captureElement.Bounds.IntersectsWith(cropRectangle)) {
visibleElements.Add(captureElement);
}
}
_elements = visibleElements;
return true;
}

View file

@ -1,3 +1,24 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using GreenshotPlugin.Interfaces;

View file

@ -1,48 +0,0 @@
using System.Collections.Generic;
using System.Drawing;
using GreenshotPlugin.Interfaces;
namespace GreenshotPlugin.Core
{
/// <summary>
/// A class representing an element in the capture
/// </summary>
public class CaptureElement : ICaptureElement {
public CaptureElement(Rectangle bounds) {
Bounds = bounds;
}
public CaptureElement(string name) {
Name = name;
}
public CaptureElement(string name, Rectangle bounds) {
Name = name;
Bounds = bounds;
}
public List<ICaptureElement> Children { get; set; } = new List<ICaptureElement>();
public string Name {
get;
set;
}
public Rectangle Bounds {
get;
set;
}
// CaptureElements are regarded equal if their bounds are equal. this should be sufficient.
public override bool Equals(object obj) {
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return obj is CaptureElement other && Bounds.Equals(other.Bounds);
}
public override int GetHashCode() {
// TODO: Fix this, this is not right...
return Bounds.GetHashCode();
}
}
}

View file

@ -34,7 +34,9 @@ using System.Runtime.InteropServices;
using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
using GreenshotPlugin.Interop;
using log4net;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
namespace GreenshotPlugin.Core {
/// <summary>
@ -45,7 +47,8 @@ namespace GreenshotPlugin.Core {
private static readonly object ClipboardLockObject = new object();
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
private static readonly string FORMAT_FILECONTENTS = "FileContents";
private static readonly string FORMAT_PNG = "PNG";
private static readonly string FORMAT_HTML = "text/html";
private static readonly string FORMAT_PNG = "PNG";
private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art";
private static readonly string FORMAT_17 = "Format17";
private static readonly string FORMAT_JPG = "JPG";
@ -207,17 +210,8 @@ EndSelection:<<<<<<<4
}
return null;
}
/// <summary>
/// Wrapper for Clipboard.ContainsText, Created for Bug #3432313
/// </summary>
/// <returns>boolean if there is text on the clipboard</returns>
public static bool ContainsText() {
IDataObject clipboardData = GetDataObject();
return ContainsText(clipboardData);
}
/// <summary>
/// <summary>
/// Test if the IDataObject contains Text
/// </summary>
/// <param name="dataObject"></param>
@ -246,41 +240,124 @@ EndSelection:<<<<<<<4
/// <param name="dataObject"></param>
/// <returns>true if an image is there</returns>
public static bool ContainsImage(IDataObject dataObject) {
if (dataObject != null) {
if (dataObject.GetDataPresent(DataFormats.Bitmap)
|| dataObject.GetDataPresent(DataFormats.Dib)
|| dataObject.GetDataPresent(DataFormats.Tiff)
|| dataObject.GetDataPresent(DataFormats.EnhancedMetafile)
|| dataObject.GetDataPresent(FORMAT_PNG)
|| dataObject.GetDataPresent(FORMAT_17)
|| dataObject.GetDataPresent(FORMAT_JPG)
|| dataObject.GetDataPresent(FORMAT_JFIF)
|| dataObject.GetDataPresent(FORMAT_JPEG)
|| dataObject.GetDataPresent(FORMAT_GIF)) {
return true;
}
var imageFiles = GetImageFilenames(dataObject);
if (imageFiles.Any()) {
return true;
}
if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) {
try {
MemoryStream imageStream = dataObject.GetData(FORMAT_FILECONTENTS) as MemoryStream;
if (IsValidStream(imageStream)) {
using (ImageHelper.FromStream(imageStream))
{
// If we get here, there is an image
return true;
}
}
} catch (Exception) {
// Ignore
}
}
}
return false;
if (dataObject == null) return false;
if (dataObject.GetDataPresent(DataFormats.Bitmap)
|| dataObject.GetDataPresent(DataFormats.Dib)
|| dataObject.GetDataPresent(DataFormats.Tiff)
|| dataObject.GetDataPresent(DataFormats.EnhancedMetafile)
|| dataObject.GetDataPresent(FORMAT_PNG)
|| dataObject.GetDataPresent(FORMAT_17)
|| dataObject.GetDataPresent(FORMAT_JPG)
|| dataObject.GetDataPresent(FORMAT_JFIF)
|| dataObject.GetDataPresent(FORMAT_JPEG)
|| dataObject.GetDataPresent(FORMAT_GIF)) {
return true;
}
var imageFiles = GetImageFilenames(dataObject);
if (imageFiles.Any()) {
return true;
}
var fileDescriptor = (MemoryStream)dataObject.GetData("FileGroupDescriptorW");
var files = FileDescriptorReader.Read(fileDescriptor);
var fileIndex = 0;
foreach (var fileContentFile in files)
{
if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0)
{
//Do something with directories?
//Note that directories do not have FileContents
//And will throw if we try to read them
continue;
}
var fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex);
try
{
//Do something with the fileContent Stream
if (IsValidStream(fileData))
{
fileData.Position = 0;
using (ImageHelper.FromStream(fileData))
{
// If we get here, there is an image
return true;
}
}
}
finally
{
fileData?.Dispose();
}
fileIndex++;
}
if (dataObject.GetDataPresent(FORMAT_FILECONTENTS))
{
try
{
var clipboardContent = dataObject.GetData(FORMAT_FILECONTENTS, true);
var imageStream = clipboardContent as MemoryStream;
if (IsValidStream(imageStream))
{
using (ImageHelper.FromStream(imageStream))
{
// If we get here, there is an image
return true;
}
}
}
catch (Exception)
{
// Ignore
}
}
// Try to get the image from the HTML code
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
if (textObject != null)
{
var doc = new HtmlDocument();
doc.LoadHtml(textObject);
var imgNodes = doc.DocumentNode.SelectNodes("//img");
if (imgNodes != null)
{
foreach (var imgNode in imgNodes)
{
var srcAttribute = imgNode.Attributes["src"];
var imageUrl = srcAttribute.Value;
if (!string.IsNullOrEmpty(imageUrl))
{
return true;
}
}
}
}
return false;
}
/// <summary>
/// Get the specified IDataObject format as a string
/// </summary>
/// <param name="dataObject">IDataObject</param>
/// <param name="format">string</param>
/// <param name="encoding">Encoding</param>
/// <returns>sting</returns>
private static string ContentAsString(IDataObject dataObject, string format, Encoding encoding = null)
{
encoding ??= Encoding.Unicode;
var objectAsFormat = dataObject.GetData(format);
return objectAsFormat switch
{
null => null,
string text => text,
MemoryStream ms => encoding.GetString(ms.ToArray()),
_ => null
};
}
/// <summary>
/// Simple helper to check the stream
/// </summary>
@ -348,9 +425,9 @@ EndSelection:<<<<<<<4
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) {
// Outlook ??
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF };
retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML };
} else {
retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF };
retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML };
}
foreach (string currentFormat in retrieveFormats) {
if (formats != null && formats.Contains(currentFormat)) {
@ -376,8 +453,32 @@ EndSelection:<<<<<<<4
/// <param name="dataObject">IDataObject</param>
/// <returns>Image or null</returns>
private static Image GetImageForFormat(string format, IDataObject dataObject) {
if (format == FORMAT_HTML)
{
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
if (textObject != null)
{
var doc = new HtmlDocument();
doc.LoadHtml(textObject);
var imgNodes = doc.DocumentNode.SelectNodes("//img");
if (imgNodes != null)
{
foreach (var imgNode in imgNodes)
{
var srcAttribute = imgNode.Attributes["src"];
var imageUrl = srcAttribute.Value;
Log.Debug(imageUrl);
var image = NetworkHelper.DownloadImage(imageUrl);
if (image != null)
{
return image;
}
}
}
}
}
object clipboardObject = GetFromDataObject(dataObject, format);
MemoryStream imageStream = clipboardObject as MemoryStream;
var imageStream = clipboardObject as MemoryStream;
if (!IsValidStream(imageStream)) {
// TODO: add "HTML Format" support here...
return clipboardObject as Image;
@ -390,14 +491,14 @@ EndSelection:<<<<<<<4
{
byte[] dibBuffer = new byte[imageStream.Length];
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
if (!infoHeader.IsDibV5) {
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
uint infoHeaderSize = infoHeader.biSize;
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER
var fileHeader = new BITMAPFILEHEADER
{
bfType = BITMAPFILEHEADER.BM,
bfSize = fileSize,
@ -408,7 +509,7 @@ EndSelection:<<<<<<<4
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
using MemoryStream bitmapStream = new MemoryStream();
using var bitmapStream = new MemoryStream();
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
bitmapStream.Seek(0, SeekOrigin.Begin);
@ -459,6 +560,7 @@ EndSelection:<<<<<<<4
} catch (Exception streamImageEx) {
Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx);
}
return null;
}
@ -706,16 +808,8 @@ EndSelection:<<<<<<<4
// Use false to make the object disappear when the application stops.
SetDataObject(dataObj, true);
}
/// <summary>
/// Retrieve a list of all formats currently on the clipboard
/// </summary>
/// <returns>List of strings with the current formats</returns>
public static List<string> GetFormats() {
return GetFormats(GetDataObject());
}
/// <summary>
/// <summary>
/// Retrieve a list of all formats currently in the IDataObject
/// </summary>
/// <returns>List of string with the current formats</returns>
@ -732,16 +826,7 @@ EndSelection:<<<<<<<4
return new List<string>();
}
/// <summary>
/// Check if there is currently something in the dataObject which has the supplied format
/// </summary>
/// <param name="format">string with format</param>
/// <returns>true if one the format is found</returns>
public static bool ContainsFormat(string format) {
return ContainsFormat(GetDataObject(), new[]{format});
}
/// <summary>
/// <summary>
/// Check if there is currently something on the clipboard which has the supplied format
/// </summary>
/// <param name="dataObject">IDataObject</param>
@ -781,17 +866,7 @@ EndSelection:<<<<<<<4
return formatFound;
}
/// <summary>
/// Get Object of type Type from the clipboard
/// </summary>
/// <param name="type">Type to get</param>
/// <returns>object from clipboard</returns>
public static object GetClipboardData(Type type) {
string format = type.FullName;
return GetClipboardData(format);
}
/// <summary>
/// <summary>
/// Get Object for format from IDataObject
/// </summary>
/// <param name="dataObj">IDataObject</param>
@ -837,14 +912,5 @@ EndSelection:<<<<<<<4
}
return null;
}
/// <summary>
/// Get Object for format from the clipboard
/// </summary>
/// <param name="format">format to get</param>
/// <returns>object from clipboard</returns>
public static object GetClipboardData(string format) {
return GetFromDataObject(GetDataObject(), format);
}
}
}
}

View file

@ -305,25 +305,7 @@ namespace GreenshotPlugin.Core {
[IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")]
public int WebRequestReadWriteTimeout { get; set; }
/// <summary>
/// Specifies what THIS build is
/// </summary>
public BuildStates BuildState {
get {
string informationalVersion = Application.ProductVersion;
if (informationalVersion != null) {
if (informationalVersion.ToLowerInvariant().Contains("-rc")) {
return BuildStates.RELEASE_CANDIDATE;
}
if (informationalVersion.ToLowerInvariant().Contains("-unstable")) {
return BuildStates.UNSTABLE;
}
}
return BuildStates.RELEASE;
}
}
public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32;
public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32;
/// <summary>
/// A helper method which returns true if the supplied experimental feature is enabled

View file

@ -242,68 +242,14 @@ namespace GreenshotPlugin.Core {
}
}
/// <summary>Shows the credentials dialog.</summary>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show() {
return Show(null, Name, Password, SaveChecked);
}
/// <summary>Shows the credentials dialog with the specified save checkbox status.</summary>
/// <param name="saveChecked">True if the save checkbox is checked.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(bool saveChecked) {
return Show(null, Name, Password, saveChecked);
}
/// <summary>Shows the credentials dialog with the specified name.</summary>
/// <summary>Shows the credentials dialog with the specified name.</summary>
/// <param name="name">The name for the credentials.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(string name) {
return Show(null, name, Password, SaveChecked);
}
/// <summary>Shows the credentials dialog with the specified name and password.</summary>
/// <param name="name">The name for the credentials.</param>
/// <param name="password">The password for the credentials.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(string name, string password) {
return Show(null, name, password, SaveChecked);
}
/// <summary>Shows the credentials dialog with the specified name, password and save checkbox status.</summary>
/// <param name="name">The name for the credentials.</param>
/// <param name="password">The password for the credentials.</param>
/// <param name="saveChecked">True if the save checkbox is checked.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(string name, string password, bool saveChecked) {
return Show(null, name, password, saveChecked);
}
/// <summary>Shows the credentials dialog with the specified owner.</summary>
/// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(IWin32Window owner) {
return Show(owner, Name, Password, SaveChecked);
}
/// <summary>Shows the credentials dialog with the specified owner and save checkbox status.</summary>
/// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param>
/// <param name="saveChecked">True if the save checkbox is checked.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(IWin32Window owner, bool saveChecked) {
return Show(owner, Name, Password, saveChecked);
}
/// <summary>Shows the credentials dialog with the specified owner, name and password.</summary>
/// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param>
/// <param name="name">The name for the credentials.</param>
/// <param name="password">The password for the credentials.</param>
/// <returns>Returns a DialogResult indicating the user action.</returns>
public DialogResult Show(IWin32Window owner, string name, string password) {
return Show(owner, name, password, SaveChecked);
}
/// <summary>Shows the credentials dialog with the specified owner, name, password and save checkbox status.</summary>
/// <summary>Shows the credentials dialog with the specified owner, name, password and save checkbox status.</summary>
/// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param>
/// <param name="name">The name for the credentials.</param>
/// <param name="password">The password for the credentials.</param>
@ -450,7 +396,6 @@ namespace GreenshotPlugin.Core {
public const int MAX_MESSAGE_LENGTH = 100;
public const int MAX_CAPTION_LENGTH = 100;
public const int MAX_GENERIC_TARGET_LENGTH = 100;
public const int MAX_DOMAIN_TARGET_LENGTH = 100;
public const int MAX_USERNAME_LENGTH = 100;
public const int MAX_PASSWORD_LENGTH = 100;
@ -463,20 +408,12 @@ namespace GreenshotPlugin.Core {
public enum CredFlags {
INCORRECT_PASSWORD = 0x1,
DO_NOT_PERSIST = 0x2,
REQUEST_ADMINISTRATOR = 0x4,
EXCLUDE_CERTIFICATES = 0x8,
REQUIRE_CERTIFICATE = 0x10,
SHOW_SAVE_CHECK_BOX = 0x40,
ALWAYS_SHOW_UI = 0x80,
REQUIRE_SMARTCARD = 0x100,
PASSWORD_ONLY_OK = 0x200,
VALIDATE_USERNAME = 0x400,
COMPLETE_USERNAME = 0x800,
PERSIST = 0x1000,
SERVER_CREDENTIAL = 0x4000,
EXPECT_CONFIRMATION = 0x20000,
GENERIC_CREDENTIALS = 0x40000,
USERNAME_TARGET_CREDENTIALS = 0x80000,
KEEP_USERNAME = 0x100000,
}

View file

@ -1,8 +1,28 @@
using GreenshotPlugin.Core.Enums;
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://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 <http://www.gnu.org/licenses/>.
*/
using GreenshotPlugin.Core.Enums;
using GreenshotPlugin.UnmanagedHelpers;
using log4net;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using GreenshotPlugin.UnmanagedHelpers.Enums;
@ -59,23 +79,6 @@ namespace GreenshotPlugin.Core
return dpiScaleFactor * someNumber;
}
/// <summary>
/// Scale the supplied number according to the supplied dpi
/// </summary>
/// <param name="number">int with e.g. 16 for 16x16 images</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>Scaled width</returns>
public static int ScaleWithDpi(int number, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return (int)(dpiScaleFactor * number);
}
/// <summary>
/// Scale the supplied Size according to the supplied dpi
/// </summary>
@ -93,79 +96,6 @@ namespace GreenshotPlugin.Core
return new Size((int)(dpiScaleFactor * size.Width), (int)(dpiScaleFactor * size.Height));
}
/// <summary>
/// Scale the supplied NativePoint according to the supplied dpi
/// </summary>
/// <param name="size">NativePoint to resize</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativePoint scaled</returns>
public static Point ScaleWithDpi(Point size, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new Point((int)(dpiScaleFactor * size.X), (int)(dpiScaleFactor * size.Y));
}
/// <summary>
/// Scale the supplied NativeSizeFloat according to the supplied dpi
/// </summary>
/// <param name="point">PointF</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>PointF</returns>
public static PointF ScaleWithDpi(PointF point, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new PointF(dpiScaleFactor * point.X, dpiScaleFactor * point.Y);
}
/// <summary>
/// Scale the supplied NativeSizeFloat according to the supplied dpi
/// </summary>
/// <param name="size">NativeSizeFloat to resize</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativeSize scaled</returns>
public static SizeF ScaleWithDpi(SizeF size, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new SizeF(dpiScaleFactor * size.Width, dpiScaleFactor * size.Height);
}
/// <summary>
/// Scale the supplied number to the current dpi
/// </summary>
/// <param name="someNumber">double with e.g. a width like 16 for 16x16 images</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>double with scaled number</returns>
public static float ScaleWithCurrentDpi(float someNumber, Func<float, float> scaleModifier = null)
{
return ScaleWithDpi(someNumber, Dpi, scaleModifier);
}
/// <summary>
/// Scale the supplied number to the current dpi
/// </summary>
/// <param name="someNumber">int with e.g. a width like 16 for 16x16 images</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>int with scaled number</returns>
public static int ScaleWithCurrentDpi(int someNumber, Func<float, float> scaleModifier = null)
{
return ScaleWithDpi(someNumber, Dpi, scaleModifier);
}
/// <summary>
/// Scale the supplied NativeSize to the current dpi
/// </summary>
@ -177,282 +107,6 @@ namespace GreenshotPlugin.Core
return ScaleWithDpi(size, Dpi, scaleModifier);
}
/// <summary>
/// Scale the supplied NativeSizeFloat to the current dpi
/// </summary>
/// <param name="size">NativeSizeFloat to scale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativeSizeFloat scaled</returns>
public static SizeF ScaleWithCurrentDpi(SizeF size, Func<float, float> scaleModifier = null)
{
return ScaleWithDpi(size, Dpi, scaleModifier);
}
/// <summary>
/// Scale the supplied NativePoint to the current dpi
/// </summary>
/// <param name="point">NativePoint to scale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativePoint scaled</returns>
public static Point ScaleWithCurrentDpi(Point point, Func<float, float> scaleModifier = null)
{
return ScaleWithDpi(point, Dpi, scaleModifier);
}
/// <summary>
/// Scale the supplied PointF to the current dpi
/// </summary>
/// <param name="point">PointF to scale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>PointF scaled</returns>
public static PointF ScaleWithCurrentDpi(PointF point, Func<float, float> scaleModifier = null)
{
return ScaleWithDpi(point, Dpi, scaleModifier);
}
/// <summary>
/// Calculate a DPI unscale factor
/// </summary>
/// <param name="dpi">uint</param>
/// <returns>float</returns>
public static float DpiUnscaleFactor(uint dpi)
{
return (float)DefaultScreenDpi / dpi;
}
/// <summary>
/// Unscale the supplied number according to the supplied dpi
/// </summary>
/// <param name="someNumber">double with e.g. the scaled width</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>double with the unscaled number</returns>
public static float UnscaleWithDpi(float someNumber, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return dpiUnscaleFactor * someNumber;
}
/// <summary>
/// Unscale the supplied number according to the supplied dpi
/// </summary>
/// <param name="number">int with a scaled width</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>Unscaled width</returns>
public static int UnscaleWithDpi(int number, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return (int)(dpiUnscaleFactor * number);
}
/// <summary>
/// Unscale the supplied NativeSize according to the supplied dpi
/// </summary>
/// <param name="size">NativeSize to unscale</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>Size unscaled</returns>
public static Size UnscaleWithDpi(Size size, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return new Size((int)(dpiUnscaleFactor * size.Width), (int)(dpiUnscaleFactor * size.Height));
}
/// <summary>
/// Unscale the supplied Point according to the supplied dpi
/// </summary>
/// <param name="size">Point to unscale</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>Point unscaled</returns>
public static Point UnscaleWithDpi(Point point, uint dpi, Func<float, float> scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return new Point((int)(dpiUnscaleFactor * point.X), (int)(dpiUnscaleFactor * point.Y));
}
/// <summary>
/// unscale the supplied NativeSizeFloat according to the supplied dpi
/// </summary>
/// <param name="size">NativeSizeFloat to resize</param>
/// <param name="dpi">current dpi, normal is 96.</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>SizeF unscaled</returns>
public static SizeF UnscaleWithDpi(SizeF size, uint dpi, Func<float, float> scaleModifier = null)
{
float dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return new SizeF(dpiUnscaleFactor * size.Width, dpiUnscaleFactor * size.Height);
}
/// <summary>
/// Unscale the supplied number to the current dpi
/// </summary>
/// <param name="someNumber">double with e.g. a width like 16 for 16x16 images</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>double with unscaled number</returns>
public static float UnscaleWithCurrentDpi(float someNumber, Func<float, float> scaleModifier = null)
{
return UnscaleWithDpi(someNumber, Dpi, scaleModifier);
}
/// <summary>
/// Unscale the supplied number to the current dpi
/// </summary>
/// <param name="someNumber">int with e.g. a width like 16 for 16x16 images</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>int with unscaled number</returns>
public static int UnscaleWithCurrentDpi(int someNumber, Func<float, float> scaleModifier = null)
{
return UnscaleWithDpi(someNumber, Dpi, scaleModifier);
}
/// <summary>
/// Unscale the supplied NativeSize to the current dpi
/// </summary>
/// <param name="size">Size to unscale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>Size unscaled</returns>
public static Size UnscaleWithCurrentDpi(Size size, Func<float, float> scaleModifier = null)
{
return UnscaleWithDpi(size, Dpi, scaleModifier);
}
/// <summary>
/// Unscale the supplied NativeSizeFloat to the current dpi
/// </summary>
/// <param name="size">NativeSizeFloat to unscale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativeSizeFloat unscaled</returns>
public static SizeF UnscaleWithCurrentDpi(SizeF size, Func<float, float> scaleModifier = null)
{
return UnscaleWithDpi(size, Dpi, scaleModifier);
}
/// <summary>
/// Unscale the supplied NativePoint to the current dpi
/// </summary>
/// <param name="point">NativePoint to unscale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativePoint unscaled</returns>
public static Point UnscaleWithCurrentDpi(Point point, Func<float, float> scaleModifier = null)
{
return UnscaleWithDpi(point, Dpi, scaleModifier);
}
/// <summary>
/// Unscale the supplied NativePointFloat to the current dpi
/// </summary>
/// <param name="point">NativePointFloat to unscale</param>
/// <param name="scaleModifier">A function which can modify the scale factor</param>
/// <returns>NativePointFloat unscaled</returns>
public static PointF UnscaleWithCurrentDpi(PointF point, Func<float, float> scaleModifier = null)
{
return ScaleWithDpi(point, Dpi, scaleModifier);
}
/// <summary>
/// public wrapper for EnableNonClientDpiScaling, this also checks if the function is available.
/// </summary>
/// <param name="hWnd">IntPtr</param>
/// <returns>true if it worked</returns>
public static bool TryEnableNonClientDpiScaling(IntPtr hWnd)
{
// EnableNonClientDpiScaling is only available on Windows 10 and later
if (!WindowsVersion.IsWindows10OrLater)
{
return false;
}
var result = EnableNonClientDpiScaling(hWnd);
if (result.Succeeded())
{
return true;
}
var error = Win32.GetLastErrorCode();
if (Log.IsDebugEnabled)
{
Log.DebugFormat("Error enabling non client dpi scaling : {0}", Win32.GetMessage(error));
}
return false;
}
/// <summary>
/// Make the current process DPI Aware, this should be done via the manifest but sometimes this is not possible.
/// </summary>
/// <returns>bool true if it was possible to change the DPI awareness</returns>
public static bool EnableDpiAware()
{
// We can only test this for Windows 8.1 or later
if (!WindowsVersion.IsWindows81OrLater)
{
Log.Debug("An application can only be DPI aware starting with Window 8.1 and later.");
return false;
}
if (WindowsVersion.IsWindows10BuildOrLater(15063))
{
if (IsValidDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2))
{
SetProcessDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2);
}
else
{
SetProcessDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2);
}
return true;
}
return SetProcessDpiAwareness(DpiAwareness.PerMonitorAware).Succeeded();
}
/// <summary>
/// Check if the process is DPI Aware, an DpiHandler doesn't make sense if not.
/// </summary>
public static bool IsDpiAware
{
get
{
// We can only test this for Windows 8.1 or later
if (!WindowsVersion.IsWindows81OrLater)
{
Log.Debug("An application can only be DPI aware starting with Window 8.1 and later.");
return false;
}
using var process = Process.GetCurrentProcess();
GetProcessDpiAwareness(process.Handle, out var dpiAwareness);
if (Log.IsDebugEnabled)
{
Log.DebugFormat("Process {0} has a Dpi awareness {1}", process.ProcessName, dpiAwareness);
}
return dpiAwareness != DpiAwareness.Unaware && dpiAwareness != DpiAwareness.Invalid;
}
}
/// <summary>
/// Return the DPI for the screen which the location is located on
/// </summary>
@ -510,40 +164,6 @@ namespace GreenshotPlugin.Core
return (uint)GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX);
}
/// <summary>
/// See details <a hef="https://msdn.microsoft.com/en-us/library/windows/desktop/dn302113(v=vs.85).aspx">GetProcessDpiAwareness function</a>
/// Retrieves the dots per inch (dpi) awareness of the specified process.
/// </summary>
/// <param name="processHandle">IntPtr with handle of the process that is being queried. If this parameter is NULL, the current process is queried.</param>
/// <param name="value">out DpiAwareness - The DPI awareness of the specified process. Possible values are from the PROCESS_DPI_AWARENESS enumeration.</param>
/// <returns>HResult</returns>
[DllImport("shcore")]
private static extern HResult GetProcessDpiAwareness(IntPtr processHandle, out DpiAwareness value);
/// <summary>
/// Sets the current process to a specified dots per inch (dpi) awareness level. The DPI awareness levels are from the PROCESS_DPI_AWARENESS enumeration.
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx">SetProcessDpiAwareness function</a>
/// </summary>
/// <param name="dpiAwareness">DpiAwareness</param>
/// <returns>HResult</returns>
[DllImport("shcore")]
private static extern HResult SetProcessDpiAwareness(DpiAwareness dpiAwareness);
/// <summary>
/// It is recommended that you set the process-default DPI awareness via application manifest. See Setting the default DPI awareness for a process for more information. Setting the process-default DPI awareness via API call can lead to unexpected application behavior.
///
/// Sets the current process to a specified dots per inch (dpi) awareness context. The DPI awareness contexts are from the DPI_AWARENESS_CONTEXT value.
/// Remarks:
/// This API is a more advanced version of the previously existing SetProcessDpiAwareness API, allowing for the process default to be set to the finer-grained DPI_AWARENESS_CONTEXT values. Most importantly, this allows you to programmatically set Per Monitor v2 as the process default value, which is not possible with the previous API.
///
/// This method sets the default DPI_AWARENESS_CONTEXT for all threads within an application. Individual threads can have their DPI awareness changed from the default with the SetThreadDpiAwarenessContext method.
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt807676(v=vs.85).aspx">SetProcessDpiAwarenessContext function</a>
/// </summary>
/// <param name="dpiAwarenessContext">DpiAwarenessContext</param>
/// <returns>bool</returns>
[DllImport("User32.dll", SetLastError = true)]
private static extern bool SetProcessDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
/// <summary>
/// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748624(v=vs.85).aspx">GetDpiForWindow function</a>
/// Returns the dots per inch (dpi) value for the associated window.
@ -566,14 +186,6 @@ namespace GreenshotPlugin.Core
[DllImport("shcore.dll", SetLastError = true)]
private static extern HResult GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY);
/// <summary>
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748621(v=vs.85).aspx">EnableNonClientDpiScaling function</a>
/// </summary>
/// <param name="hWnd">IntPtr</param>
/// <returns>bool</returns>
[DllImport("User32.dll", SetLastError = true)]
private static extern HResult EnableNonClientDpiScaling(IntPtr hWnd);
/// <summary>
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748623(v=vs.85).aspx">GetDpiForSystem function</a>
/// Returns the system DPI.
@ -581,151 +193,5 @@ namespace GreenshotPlugin.Core
/// <returns>uint with the system DPI</returns>
[DllImport("User32.dll")]
private static extern uint GetDpiForSystem();
/// <summary>
/// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS.
/// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn384110(v=vs.85).aspx">LogicalToPhysicalPointForPerMonitorDPI function</a>
/// </summary>
/// <param name="hWnd">IntPtr A handle to the window whose transform is used for the conversion.</param>
/// <param name="point">A pointer to a POINT structure that specifies the logical coordinates to be converted. The new physical coordinates are copied into this structure if the function succeeds.</param>
/// <returns>bool</returns>
[DllImport("User32.dll")]
private static extern bool LogicalToPhysicalPointForPerMonitorDPI(IntPtr hWnd, ref POINT point);
/// <summary>
/// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS.
/// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn384112(v=vs.85).aspx">PhysicalToLogicalPointForPerMonitorDPI function</a>
/// </summary>
/// <param name="hWnd">IntPtr A handle to the window whose transform is used for the conversion.</param>
/// <param name="point">NativePoint A pointer to a POINT structure that specifies the physical/screen coordinates to be converted. The new logical coordinates are copied into this structure if the function succeeds.</param>
/// <returns>bool</returns>
[DllImport("User32.dll")]
private static extern bool PhysicalToLogicalPointForPerMonitorDPI(IntPtr hWnd, ref POINT point);
/// <summary>
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx">SystemParametersInfo function</a>
/// Retrieves the value of one of the system-wide parameters, taking into account the provided DPI value.
/// </summary>
/// <param name="uiAction">
/// SystemParametersInfoActions The system-wide parameter to be retrieved.
/// This function is only intended for use with SPI_GETICONTITLELOGFONT, SPI_GETICONMETRICS, or SPI_GETNONCLIENTMETRICS. See SystemParametersInfo for more information on these values.
/// </param>
/// <param name="uiParam">
/// A parameter whose usage and format depends on the system parameter being queried or set. For more
/// information about system-wide parameters, see the uiAction parameter. If not otherwise indicated, you must specify
/// zero for this parameter.
/// </param>
/// <param name="pvParam">IntPtr</param>
/// <param name="fWinIni">SystemParametersInfoBehaviors</param>
/// <param name="dpi">uint with dpi value</param>
/// <returns>bool</returns>
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfoForDpi(SystemParametersInfoActions uiAction, uint uiParam, IntPtr pvParam, SystemParametersInfoBehaviors fWinIni, uint dpi);
/// <summary>
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748626(v=vs.85).aspx">GetThreadDpiAwarenessContext function</a>
/// Gets the DPI_AWARENESS_CONTEXT for the current thread.
///
/// This method will return the latest DPI_AWARENESS_CONTEXT sent to SetThreadDpiAwarenessContext. If SetThreadDpiAwarenessContext was never called for this thread, then the return value will equal the default DPI_AWARENESS_CONTEXT for the process.
/// </summary>
/// <returns>DpiAwarenessContext</returns>
[DllImport("User32.dll")]
private static extern DpiAwarenessContext GetThreadDpiAwarenessContext();
/// <summary>
/// Set the DPI awareness for the current thread to the provided value.
/// </summary>
/// <param name="dpiAwarenessContext">DpiAwarenessContext the new value for the current thread</param>
/// <returns>DpiAwarenessContext previous value</returns>
[DllImport("User32.dll")]
private static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
/// <summary>
/// Retrieves the DpiAwareness value from a DpiAwarenessContext.
/// </summary>
/// <param name="dpiAwarenessContext">DpiAwarenessContext</param>
/// <returns>DpiAwareness</returns>
[DllImport("User32.dll")]
private static extern DpiAwareness GetAwarenessFromDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
/// <summary>
/// Retrieves the DPI from a given DPI_AWARENESS_CONTEXT handle. This enables you to determine the DPI of a thread without needed to examine a window created within that thread.
/// </summary>
/// <param name="dpiAwarenessContext">DpiAwarenessContext</param>
/// <returns>uint with dpi value</returns>
[DllImport("User32.dll")]
private static extern uint GetDpiFromDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
/// <summary>
/// Determines if a specified DPI_AWARENESS_CONTEXT is valid and supported by the current system.
/// </summary>
/// <param name="dpiAwarenessContext">DpiAwarenessContext The context that you want to determine if it is supported.</param>
/// <returns>bool true if supported otherwise false</returns>
[DllImport("User32.dll")]
private static extern bool IsValidDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
/// <summary>
/// Returns the DPI_HOSTING_BEHAVIOR of the specified window.
///
/// This API allows you to examine the hosting behavior of a window after it has been created. A window's hosting behavior is the hosting behavior of the thread in which the window was created, as set by a call to SetThreadDpiHostingBehavior. This is a permanent value and cannot be changed after the window is created, even if the thread's hosting behavior is changed.
/// </summary>
/// <returns>DpiHostingBehavior</returns>
[DllImport("User32.dll")]
private static extern DpiHostingBehavior GetWindowDpiHostingBehavior();
/// <summary>
/// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt845775.aspx">SetThreadDpiHostingBehavior function</a>
/// Sets the thread's DPI_HOSTING_BEHAVIOR. This behavior allows windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT.
///
/// DPI_HOSTING_BEHAVIOR enables a mixed content hosting behavior, which allows parent windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT value. This property only effects new windows created within this thread while the mixed hosting behavior is active. A parent window with this hosting behavior is able to host child windows with different DPI_AWARENESS_CONTEXT values, regardless of whether the child windows have mixed hosting behavior enabled.
///
/// This hosting behavior does not allow for windows with per-monitor DPI_AWARENESS_CONTEXT values to be hosted until windows with DPI_AWARENESS_CONTEXT values of system or unaware.
///
/// To avoid unexpected outcomes, a thread's DPI_HOSTING_BEHAVIOR should be changed to support mixed hosting behaviors only when creating a new window which needs to support those behaviors. Once that window is created, the hosting behavior should be switched back to its default value.
///
/// This API is used to change the thread's DPI_HOSTING_BEHAVIOR from its default value. This is only necessary if your app needs to host child windows from plugins and third-party components that do not support per-monitor-aware context. This is most likely to occur if you are updating complex applications to support per-monitor DPI_AWARENESS_CONTEXT behaviors.
///
/// Enabling mixed hosting behavior will not automatically adjust the thread's DPI_AWARENESS_CONTEXT to be compatible with legacy content. The thread's awareness context must still be manually changed before new windows are created to host such content.
/// </summary>
/// <param name="dpiHostingBehavior">DpiHostingBehavior</param>
/// <returns>previous DpiHostingBehavior</returns>
[DllImport("User32.dll")]
private static extern DpiHostingBehavior SetThreadDpiHostingBehavior(DpiHostingBehavior dpiHostingBehavior);
/// <summary>
///Retrieves the DPI_HOSTING_BEHAVIOR from the current thread.
/// </summary>
/// <returns>DpiHostingBehavior</returns>
[DllImport("User32.dll")]
private static extern DpiHostingBehavior GetThreadDpiHostingBehavior();
/// <summary>
/// Overrides the default per-monitor DPI scaling behavior of a child window in a dialog.
/// This function returns TRUE if the operation was successful, and FALSE otherwise. To get extended error information, call GetLastError.
///
/// Possible errors are ERROR_INVALID_HANDLE if passed an invalid HWND, and ERROR_ACCESS_DENIED if the windows belongs to another process.
///
/// The behaviors are specified as values from the DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS enum. This function follows the typical two-parameter approach to setting flags, where a mask specifies the subset of the flags to be changed.
///
/// It is valid to set these behaviors on any window. It does not matter if the window is currently a child of a dialog at the point in time that SetDialogControlDpiChangeBehavior is called. The behaviors are retained and will take effect only when the window is an immediate child of a dialog that has per-monitor DPI scaling enabled.
///
/// This API influences individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior is controlled by SetDialogDpiChangeBehavior.
/// </summary>
/// <param name="hWnd">IntPtr A handle for the window whose behavior will be modified.</param>
/// <param name="mask">DialogScalingBehaviors A mask specifying the subset of flags to be changed.</param>
/// <param name="values">DialogScalingBehaviors The desired value to be set for the specified subset of flags.</param>
/// <returns>bool</returns>
[DllImport("User32.dll")]
private static extern bool SetDialogControlDpiChangeBehavior(IntPtr hWnd, DialogScalingBehaviors mask, DialogScalingBehaviors values);
/// <summary>
/// Retrieves and per-monitor DPI scaling behavior overrides of a child window in a dialog.
/// The flags set on the given window. If passed an invalid handle, this function will return zero, and set its last error to ERROR_INVALID_HANDLE.
/// </summary>
/// <param name="hWnd">IntPtr A handle for the window whose behavior will be modified.</param>
/// <returns>DialogScalingBehaviors</returns>
[DllImport("User32.dll")]
private static extern DialogScalingBehaviors GetDialogControlDpiChangeBehavior(IntPtr hWnd);
}
}

View file

@ -1,102 +0,0 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://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 <http://www.gnu.org/licenses/>.
*/
using System;
namespace GreenshotPlugin.Core {
public static class EnumerationExtensions {
public static bool Has<T>(this Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try {
if (underlyingType == typeof(int)) {
return (((int)(object)type & (int)(object)value) == (int)(object)value);
} else if (underlyingType == typeof(uint)) {
return (((uint)(object)type & (uint)(object)value) == (uint)(object)value);
}
}
catch
{
// ignored
}
return false;
}
public static bool Is<T>(this Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try
{
if (underlyingType == typeof(int)) {
return (int)(object)type == (int)(object)value;
}
if (underlyingType == typeof(uint)) {
return (uint)(object)type == (uint)(object)value;
}
}
catch
{
// ignored
}
return false;
}
/// <summary>
/// Add a flag to an enum
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static T Add<T>(this Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try
{
if (underlyingType == typeof(int)) {
return (T)(object)(((int)(object)type | (int)(object)value));
}
if (underlyingType == typeof(uint)) {
return (T)(object)(((uint)(object)type | (uint)(object)value));
}
} catch(Exception ex) {
throw new ArgumentException($"Could not append value '{value}' to enumerated type '{typeof(T).Name}'.", ex);
}
throw new ArgumentException($"Could not append value '{value}' to enumerated type '{typeof(T).Name}'.");
}
/// <summary>
/// Remove a flag from an enum type
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static T Remove<T>(this Enum type, T value) {
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
try
{
if (underlyingType == typeof(int)) {
return (T)(object)(((int)(object)type & ~(int)(object)value));
}
if (underlyingType == typeof(uint)) {
return (T)(object)(((uint)(object)type & ~(uint)(object)value));
}
} catch(Exception ex) {
throw new ArgumentException($"Could not remove value '{value}' from enumerated type '{typeof(T).Name}'.", ex);
}
throw new ArgumentException($"Could not remove value '{value}' from enumerated type '{typeof(T).Name}'.");
}
}
}

View file

@ -1,34 +0,0 @@
// Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace GreenshotPlugin.Core.Enums
{
/// <summary>
/// In Per Monitor v2 contexts, dialogs will automatically respond to DPI changes by resizing themselves and re-computing the positions of their child windows (here referred to as re-layouting). This enum works in conjunction with SetDialogDpiChangeBehavior in order to override the default DPI scaling behavior for dialogs.
/// This does not affect DPI scaling behavior for the child windows of dialogs(beyond re-layouting), which is controlled by DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS.
/// </summary>
[Flags]
public enum DialogDpiChangeBehaviors
{
/// <summary>
/// The default behavior of the dialog manager. In response to a DPI change, the dialog manager will re-layout each control, update the font on each control, resize the dialog, and update the dialog's own font.
/// </summary>
Default = 0,
/// <summary>
/// Prevents the dialog manager from responding to WM_GETDPISCALEDSIZE and WM_DPICHANGED, disabling all default DPI scaling behavior.
/// </summary>
DisableAll = 1,
/// <summary>
/// Prevents the dialog manager from resizing the dialog in response to a DPI change.
/// </summary>
DisableResize = 2,
/// <summary>
/// Prevents the dialog manager from re-layouting all of the dialogue's immediate children HWNDs in response to a DPI change.
/// </summary>
DisableControlRelayout = 3
}
}

View file

@ -1,32 +0,0 @@
// Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace GreenshotPlugin.Core.Enums
{
/// <summary>
/// Describes per-monitor DPI scaling behavior overrides for child windows within dialogs. The values in this enumeration are bitfields and can be combined.
///
/// This enum is used with SetDialogControlDpiChangeBehavior in order to override the default per-monitor DPI scaling behavior for a child window within a dialog.
///
/// These settings only apply to individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior of a dialog is controlled by DIALOG_DPI_CHANGE_BEHAVIORS.
/// </summary>
[Flags]
public enum DialogScalingBehaviors
{
/// <summary>
/// The default behavior of the dialog manager. The dialog managed will update the font, size, and position of the child window on DPI changes.
/// </summary>
Default = 0,
/// <summary>
/// Prevents the dialog manager from sending an updated font to the child window via WM_SETFONT in response to a DPI change.
/// </summary>
DisableFontUpdate = 1,
/// <summary>
/// Prevents the dialog manager from resizing and repositioning the child window in response to a DPI change.
/// </summary>
DisableRelayout = 2
}
}

View file

@ -1,40 +0,0 @@
// Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace GreenshotPlugin.Core.Enums
{
/// <summary>
/// Identifies the dots per inch (dpi) setting for a thread, process, or window.
/// Can be used everywhere ProcessDpiAwareness is passed.
/// </summary>
public enum DpiAwareness
{
/// <summary>
/// Invalid DPI awareness. This is an invalid DPI awareness value.
/// </summary>
Invalid = -1,
/// <summary>
/// DPI unaware.
/// This process does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI).
/// It will be automatically scaled by the system on any other DPI setting.
/// </summary>
Unaware = 0,
/// <summary>
/// System DPI aware.
/// This process does not scale for DPI changes.
/// It will query for the DPI once and use that value for the lifetime of the process.
/// If the DPI changes, the process will not adjust to the new DPI value.
/// It will be automatically scaled up or down by the system when the DPI changes from the system value.
/// </summary>
SystemAware = 1,
/// <summary>
/// Per monitor DPI aware.
/// This process checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes.
/// These processes are not automatically scaled by the system.
/// </summary>
PerMonitorAware = 2
}
}

View file

@ -1,46 +0,0 @@
// Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace GreenshotPlugin.Core.Enums
{
/// <summary>
/// </summary>
public enum DpiAwarenessContext
{
/// <summary>
/// DPI unaware.
/// This window does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI).
/// It will be automatically scaled by the system on any other DPI setting.
/// </summary>
Unaware = -1,
/// <summary>
/// System DPI aware.
/// This window does not scale for DPI changes.
/// It will query for the DPI once and use that value for the lifetime of the process.
/// If the DPI changes, the process will not adjust to the new DPI value.
/// It will be automatically scaled up or down by the system when the DPI changes from the system value.
/// </summary>
SystemAware = -2,
/// <summary>
/// Per monitor DPI aware.
/// This window checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes.
/// These processes are not automatically scaled by the system.
/// </summary>
PerMonitorAware = -3,
/// <summary>
/// Also known as Per Monitor v2. An advancement over the original per-monitor DPI awareness mode, which enables applications to access new DPI-related scaling behaviors on a per top-level window basis.
/// Per Monitor v2 was made available in the Creators Update of Windows 10, and is not available on earlier versions of the operating system.
/// The additional behaviors introduced are as follows:
/// * Child window DPI change notifications - In Per Monitor v2 contexts, the entire window tree is notified of any DPI changes that occur.
/// * Scaling of non-client area - All windows will automatically have their non-client area drawn in a DPI sensitive fashion. Calls to EnableNonClientDpiScaling are unnecessary.
/// * Scaling of Win32 menus - All NTUSER menus created in Per Monitor v2 contexts will be scaling in a per-monitor fashion.
/// * Dialog Scaling - Win32 dialogs created in Per Monitor v2 contexts will automatically respond to DPI changes.
/// * Improved scaling of comctl32 controls - Various comctl32 controls have improved DPI scaling behavior in Per Monitor v2 contexts.
/// * Improved theming behavior - UxTheme handles opened in the context of a Per Monitor v2 window will operate in terms of the DPI associated with that window.
/// </summary>
PerMonitorAwareV2 = -4
}
}

View file

@ -1,28 +0,0 @@
// Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace GreenshotPlugin.Core.Enums
{
/// <summary>
/// Identifies the DPI hosting behavior for a window.
/// This behavior allows windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT
/// </summary>
public enum DpiHostingBehavior
{
/// <summary>
/// Invalid DPI hosting behavior. This usually occurs if the previous SetThreadDpiHostingBehavior call used an invalid parameter.
/// </summary>
Invalid = -1,
/// <summary>
/// Default DPI hosting behavior. The associated window behaves as normal, and cannot create or re-parent child windows with a different DPI_AWARENESS_CONTEXT.
/// </summary>
Default = 0,
/// <summary>
/// Mixed DPI hosting behavior. This enables the creation and re-parenting of child windows with different DPI_AWARENESS_CONTEXT. These child windows will be independently scaled by the OS.
/// </summary>
Mixed = 1
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
// Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace GreenshotPlugin.Core.Enums
{
/// <summary>
/// If a system parameter is being set, specifies whether the user profile is to be updated, and if so, whether the
/// WM_SETTINGCHANGE message is to be broadcast to all top-level windows to notify them of the change.
/// This parameter can be zero if you do not want to update the user profile or broadcast the WM_SETTINGCHANGE message,
/// or it can be one or more of the following values.
/// </summary>
public enum SystemParametersInfoBehaviors : uint
{
/// <summary>
/// Do nothing
/// </summary>
None = 0x00,
/// <summary>Writes the new system-wide parameter setting to the user profile.</summary>
UpdateIniFile = 0x01,
/// <summary>Broadcasts the WM_SETTINGCHANGE message after updating the user profile.</summary>
SendChange = 0x02,
/// <summary>Same as SPIF_SENDCHANGE.</summary>
SendWinIniChange = SendChange
}
}

View file

@ -355,16 +355,7 @@ namespace GreenshotPlugin.Core {
}
}
/// <summary>
/// Factory for creating a FastBitmap as a destination for the source
/// </summary>
/// <param name="source">Bitmap to clone</param>
/// <returns>IFastBitmap</returns>
public static IFastBitmap CreateCloneOf(Image source) {
return CreateCloneOf(source, source.PixelFormat, Rectangle.Empty);
}
/// <summary>
/// <summary>
/// Factory for creating a FastBitmap as a destination for the source
/// </summary>
/// <param name="source">Bitmap to clone</param>

View file

@ -19,7 +19,6 @@
using GreenshotPlugin.Core.Enums;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
namespace GreenshotPlugin.Core
{
@ -29,7 +28,7 @@ namespace GreenshotPlugin.Core
public static class HResultExtensions
{
/// <summary>
/// Test if the HResult respresents a fail
/// Test if the HResult represents a fail
/// </summary>
/// <param name="hResult">HResult</param>
/// <returns>bool</returns>
@ -40,7 +39,7 @@ namespace GreenshotPlugin.Core
}
/// <summary>
/// Test if the HResult respresents a success
/// Test if the HResult represents a success
/// </summary>
/// <param name="hResult">HResult</param>
/// <returns>bool</returns>
@ -49,17 +48,5 @@ namespace GreenshotPlugin.Core
{
return hResult >= HResult.S_OK;
}
/// <summary>
/// Throw an exception on Failure
/// </summary>
/// <param name="hResult">HResult</param>
public static void ThrowOnFailure(this HResult hResult)
{
if (hResult.Failed())
{
throw Marshal.GetExceptionForHR((int)hResult);
}
}
}
}

View file

@ -12,16 +12,6 @@ namespace GreenshotPlugin.Core
private readonly Image _image;
private Image _imageClone;
/// <summary>
/// Factory method
/// </summary>
/// <param name="image">Image</param>
/// <returns>IImage</returns>
public static IImage FromImage(Image image)
{
return image == null ? null : new ImageWrapper(image);
}
public ImageWrapper(Image image)
{
// Make sure the orientation is set correctly so Greenshot can process the image correctly

View file

@ -20,9 +20,7 @@
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using GreenshotPlugin.Interfaces;
using log4net;
namespace GreenshotPlugin.Core {
@ -33,42 +31,28 @@ namespace GreenshotPlugin.Core {
private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils));
public static List<Type> GetSubclassesOf(Type type, bool excludeSystemTypes) {
List<Type> list = new List<Type>();
foreach(Assembly currentAssembly in Thread.GetDomain().GetAssemblies()) {
var list = new List<Type>();
foreach(var currentAssembly in Thread.GetDomain().GetAssemblies()) {
try {
Type[] types = currentAssembly.GetTypes();
if (!excludeSystemTypes || (excludeSystemTypes && !currentAssembly.FullName.StartsWith("System."))) {
foreach(Type currentType in types) {
if (type.IsInterface) {
if (currentType.GetInterface(type.FullName) != null) {
list.Add(currentType);
}
} else if (currentType.IsSubclassOf(type)) {
list.Add(currentType);
}
}
}
} catch (Exception ex) {
if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System.")))
{
continue;
}
foreach(var currentType in types) {
if (type.IsInterface) {
if (currentType.GetInterface(type.FullName) != null) {
list.Add(currentType);
}
} else if (currentType.IsSubclassOf(type)) {
list.Add(currentType);
}
}
} catch (Exception ex) {
LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message);
}
}
return list;
}
public static List<IProcessor> GetProcessors() {
List<IProcessor> processors = new List<IProcessor>();
foreach(Type processorType in GetSubclassesOf(typeof(IProcessor), true)) {
if (!processorType.IsAbstract) {
IProcessor processor = (IProcessor)Activator.CreateInstance(processorType);
if (processor.isActive) {
LOG.DebugFormat("Found processor {0} with designation {1}", processorType.Name, processor.Designation);
processors.Add(processor);
} else {
LOG.DebugFormat("Ignoring processor {0} with designation {1}", processorType.Name, processor.Designation);
}
}
}
return processors;
}
}
}
}

View file

@ -476,32 +476,7 @@ namespace GreenshotPlugin.Core {
}
}
/// <summary>
/// Check if a resource with prefix.key exists
/// </summary>
/// <param name="prefix"></param>
/// <param name="key"></param>
/// <returns>true if available</returns>
public static bool HasKey(string prefix, Enum key) {
if (key == null) {
return false;
}
return HasKey(prefix + "." + key);
}
/// <summary>
/// Check if a resource with key exists
/// </summary>
/// <param name="key"></param>
/// <returns>true if available</returns>
public static bool HasKey(Enum key) {
if (key == null) {
return false;
}
return HasKey(key.ToString());
}
/// <summary>
/// <summary>
/// Check if a resource with prefix.key exists
/// </summary>
/// <param name="prefix"></param>

View file

@ -40,9 +40,8 @@ namespace GreenshotPlugin.Core {
GET,
POST,
PUT,
DELETE,
HEAD
};
DELETE
};
/// <summary>
/// Description of NetworkHelper.
@ -61,54 +60,21 @@ namespace GreenshotPlugin.Core {
}
catch (Exception ex)
{
Log.Warn("An error has occured while allowing self-signed certificates:", ex);
Log.Warn("An error has occurred while allowing self-signed certificates:", ex);
}
}
/// <summary>
/// Download a uri response as string
/// </summary>
/// <param name="uri">An Uri to specify the download location</param>
/// <returns>string with the file content</returns>
public static string GetAsString(Uri uri) {
return GetResponseAsString(CreateWebRequest(uri));
}
/// <summary>
/// Download the FavIcon as a Bitmap
/// </summary>
/// <param name="baseUri"></param>
/// <returns>Bitmap with the FavIcon</returns>
public static Bitmap DownloadFavIcon(Uri baseUri) {
Uri url = new Uri(baseUri, new Uri("favicon.ico"));
try {
HttpWebRequest request = CreateWebRequest(url);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (request.HaveResponse)
{
using Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
using Image image = ImageHelper.FromStream(responseStream);
return image.Height > 16 && image.Width > 16 ? new Bitmap(image, 16, 16) : new Bitmap(image);
}
}
} catch (Exception e) {
Log.Error("Problem downloading the FavIcon from: " + baseUri, e);
}
return null;
}
/// <summary>
/// <summary>
/// Download the uri into a memory stream, without catching exceptions
/// </summary>
/// <param name="url">Of an image</param>
/// <returns>MemoryStream which is already seek-ed to 0</returns>
public static MemoryStream GetAsMemoryStream(string url) {
HttpWebRequest request = CreateWebRequest(url);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
MemoryStream memoryStream = new MemoryStream();
using (Stream responseStream = response.GetResponseStream()) {
var request = CreateWebRequest(url);
using var response = (HttpWebResponse)request.GetResponse();
var memoryStream = new MemoryStream();
using (var responseStream = response.GetResponseStream()) {
responseStream?.CopyTo(memoryStream);
// Make sure it can be used directly
memoryStream.Seek(0, SeekOrigin.Begin);
@ -123,7 +89,7 @@ namespace GreenshotPlugin.Core {
/// <returns>Bitmap</returns>
public static Image DownloadImage(string url)
{
StringBuilder extensions = new StringBuilder();
var extensions = new StringBuilder();
foreach (var extension in ImageHelper.StreamConverters.Keys)
{
if (string.IsNullOrEmpty(extension))
@ -147,7 +113,7 @@ namespace GreenshotPlugin.Core {
{
// If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
string content;
using (StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8, true))
using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true))
{
content = streamReader.ReadLine();
}
@ -198,7 +164,7 @@ namespace GreenshotPlugin.Core {
/// <param name="method">Method to use</param>
/// <returns>WebRequest</returns>
public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) {
HttpWebRequest webRequest = CreateWebRequest(uri);
var webRequest = CreateWebRequest(uri);
webRequest.Method = method.ToString();
return webRequest;
}
@ -209,7 +175,7 @@ namespace GreenshotPlugin.Core {
/// <param name="uri">Uri with uri to connect to</param>
/// <returns>WebRequest</returns>
public static HttpWebRequest CreateWebRequest(Uri uri) {
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null;
// Make sure the default credentials are available
webRequest.Credentials = CredentialCache.DefaultCredentials;
@ -231,28 +197,32 @@ namespace GreenshotPlugin.Core {
/// <returns>IWebProxy filled with all the proxy details or null if none is set/wanted</returns>
public static IWebProxy CreateProxy(Uri uri) {
IWebProxy proxyToUse = null;
if (Config.UseProxy) {
proxyToUse = WebRequest.DefaultWebProxy;
if (proxyToUse != null) {
proxyToUse.Credentials = CredentialCache.DefaultCredentials;
if (Log.IsDebugEnabled) {
// check the proxy for the Uri
if (!proxyToUse.IsBypassed(uri)) {
Uri proxyUri = proxyToUse.GetProxy(uri);
if (proxyUri != null) {
Log.Debug("Using proxy: " + proxyUri + " for " + uri);
} else {
Log.Debug("No proxy found!");
}
} else {
Log.Debug("Proxy bypass for: " + uri);
}
}
} else {
Log.Debug("No proxy found!");
}
}
return proxyToUse;
if (!Config.UseProxy)
{
return proxyToUse;
}
proxyToUse = WebRequest.DefaultWebProxy;
if (proxyToUse != null) {
proxyToUse.Credentials = CredentialCache.DefaultCredentials;
if (!Log.IsDebugEnabled)
{
return proxyToUse;
}
// check the proxy for the Uri
if (!proxyToUse.IsBypassed(uri)) {
var proxyUri = proxyToUse.GetProxy(uri);
if (proxyUri != null) {
Log.Debug("Using proxy: " + proxyUri + " for " + uri);
} else {
Log.Debug("No proxy found!");
}
} else {
Log.Debug("Proxy bypass for: " + uri);
}
} else {
Log.Debug("No proxy found!");
}
return proxyToUse;
}
/// <summary>
@ -263,7 +233,7 @@ namespace GreenshotPlugin.Core {
// [Obsolete("Use System.Uri.EscapeDataString instead")]
public static string UrlEncode(string text) {
if (!string.IsNullOrEmpty(text)) {
// Sytem.Uri provides reliable parsing, but doesn't encode spaces.
// System.Uri provides reliable parsing, but doesn't encode spaces.
return Uri.EscapeDataString(text).Replace("%20", "+");
}
return null;
@ -277,7 +247,7 @@ namespace GreenshotPlugin.Core {
/// <returns>escaped data string</returns>
public static string EscapeDataString(string text) {
if (!string.IsNullOrEmpty(text)) {
StringBuilder result = new StringBuilder();
var result = new StringBuilder();
int currentLocation = 0;
while (currentLocation < text.Length) {
string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation));
@ -326,7 +296,7 @@ namespace GreenshotPlugin.Core {
}
/// <summary>
/// Generate the query paramters
/// Generate the query parameters
/// </summary>
/// <param name="queryParameters">the list of query parameters</param>
/// <returns>a string with the query parameters</returns>
@ -337,7 +307,7 @@ namespace GreenshotPlugin.Core {
queryParameters = new SortedDictionary<string, object>(queryParameters);
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
foreach(string key in queryParameters.Keys) {
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}"));
}
@ -358,18 +328,8 @@ namespace GreenshotPlugin.Core {
WriteMultipartFormData(formDataStream, boundary, postParameters);
}
/// <summary>
/// Write Multipart Form Data to the HttpListenerResponse
/// </summary>
/// <param name="response">HttpListenerResponse</param>
/// <param name="postParameters">Parameters to include in the multipart form data</param>
public static void WriteMultipartFormData(HttpListenerResponse response, IDictionary<string, object> postParameters) {
string boundary = $"----------{Guid.NewGuid():N}";
response.ContentType = "multipart/form-data; boundary=" + boundary;
WriteMultipartFormData(response.OutputStream, boundary, postParameters);
}
/// <summary>
/// <summary>
/// Write Multipart Form Data to a Stream, content-type should be set before this!
/// </summary>
/// <param name="formDataStream">Stream to write the multipart form data to</param>
@ -519,27 +479,7 @@ namespace GreenshotPlugin.Core {
}
return responseData;
}
/// <summary>
/// Get LastModified for a URI
/// </summary>
/// <param name="uri">Uri</param>
/// <returns>DateTime</returns>
public static DateTime GetLastModified(Uri uri) {
try {
HttpWebRequest webRequest = CreateWebRequest(uri);
webRequest.Method = HTTPMethod.HEAD.ToString();
using HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Log.DebugFormat("RSS feed was updated at {0}", webResponse.LastModified);
return webResponse.LastModified;
} catch (Exception wE) {
Log.WarnFormat("Problem requesting HTTP - HEAD on uri {0}", uri);
Log.Warn(wE.Message);
// Pretend it is old
return DateTime.MinValue;
}
}
}
}
/// <summary>
/// This interface can be used to pass binary information around, like byte[] or Image
@ -555,158 +495,7 @@ namespace GreenshotPlugin.Core {
string Filename { get; set; }
}
/// <summary>
/// A container to supply files to a Multi-part form data upload
/// </summary>
public class ByteContainer : IBinaryContainer {
private readonly byte[] _file;
private readonly string _contentType;
private readonly int _fileSize;
public ByteContainer(byte[] file) : this(file, null) {
}
public ByteContainer(byte[] file, string filename) : this(file, filename, null) {
}
public ByteContainer(byte[] file, string filename, string contenttype) : this(file, filename, contenttype, 0) {
}
public ByteContainer(byte[] file, string filename, string contenttype, int filesize) {
_file = file;
Filename = filename;
_contentType = contenttype;
_fileSize = filesize == 0 ? file.Length : filesize;
}
/// <summary>
/// Create a Base64String from the byte[]
/// </summary>
/// <returns>string</returns>
public string ToBase64String(Base64FormattingOptions formattingOptions) {
return Convert.ToBase64String(_file, 0, _fileSize, formattingOptions);
}
/// <summary>
/// Returns the initial byte-array which was supplied when creating the FileParameter
/// </summary>
/// <returns>byte[]</returns>
public byte[] ToByteArray() {
return _file;
}
/// <summary>
/// Write Multipart Form Data directly to the HttpWebRequest response stream
/// </summary>
/// <param name="boundary">Separator</param>
/// <param name="name">name</param>
/// <param name="formDataStream">Stream to write to</param>
public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) {
// Add just the first part of this param, since we will write the file data directly to the Stream
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {_contentType ?? "application/octet-stream"}\r\n\r\n";
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
// Write the file data directly to the Stream, rather than serializing it to a string.
formDataStream.Write(_file, 0, _fileSize);
}
/// <summary>
/// A plain "write data to stream"
/// </summary>
/// <param name="dataStream">Stream to write to</param>
public void WriteToStream(Stream dataStream) {
// Write the file data directly to the Stream, rather than serializing it to a string.
dataStream.Write(_file, 0, _fileSize);
}
/// <summary>
/// Upload the file to the webrequest
/// </summary>
/// <param name="webRequest"></param>
public void Upload(HttpWebRequest webRequest) {
webRequest.ContentType = _contentType;
webRequest.ContentLength = _fileSize;
using var requestStream = webRequest.GetRequestStream();
WriteToStream(requestStream);
}
public string ContentType => _contentType;
public string Filename { get; set; }
}
/// <summary>
/// A container to supply images to a Multi-part form data upload
/// </summary>
public class BitmapContainer : IBinaryContainer {
private readonly Bitmap _bitmap;
private readonly SurfaceOutputSettings _outputSettings;
public BitmapContainer(Bitmap bitmap, SurfaceOutputSettings outputSettings, string filename) {
_bitmap = bitmap;
_outputSettings = outputSettings;
Filename = filename;
}
/// <summary>
/// Create a Base64String from the image by saving it to a memory stream and converting it.
/// Should be avoided if possible, as this uses a lot of memory.
/// </summary>
/// <returns>string</returns>
public string ToBase64String(Base64FormattingOptions formattingOptions)
{
using MemoryStream stream = new MemoryStream();
ImageOutput.SaveToStream(_bitmap, null, stream, _outputSettings);
return Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length, formattingOptions);
}
/// <summary>
/// Create a byte[] from the image by saving it to a memory stream.
/// Should be avoided if possible, as this uses a lot of memory.
/// </summary>
/// <returns>byte[]</returns>
public byte[] ToByteArray()
{
using MemoryStream stream = new MemoryStream();
ImageOutput.SaveToStream(_bitmap, null, stream, _outputSettings);
return stream.ToArray();
}
/// <summary>
/// Write Multipart Form Data directly to the HttpWebRequest response stream
/// </summary>
/// <param name="boundary">Separator</param>
/// <param name="name">Name of the thing/file</param>
/// <param name="formDataStream">Stream to write to</param>
public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) {
// Add just the first part of this param, since we will write the file data directly to the Stream
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n";
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
ImageOutput.SaveToStream(_bitmap, null, formDataStream, _outputSettings);
}
/// <summary>
/// A plain "write data to stream"
/// </summary>
/// <param name="dataStream"></param>
public void WriteToStream(Stream dataStream) {
// Write the file data directly to the Stream, rather than serializing it to a string.
ImageOutput.SaveToStream(_bitmap, null, dataStream, _outputSettings);
}
/// <summary>
/// Upload the image to the webrequest
/// </summary>
/// <param name="webRequest"></param>
public void Upload(HttpWebRequest webRequest) {
webRequest.ContentType = "image/" + _outputSettings.Format;
using var requestStream = webRequest.GetRequestStream();
WriteToStream(requestStream);
}
public string ContentType => "image/" + _outputSettings.Format;
public string Filename { get; set; }
}
/// <summary>
/// <summary>
/// A container to supply surfaces to a Multi-part form data upload
/// </summary>
public class SurfaceContainer : IBinaryContainer {

View file

@ -549,21 +549,7 @@ namespace GreenshotPlugin.Core {
return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData);
}
/// <summary>
/// Submit a web request using oAuth.
/// </summary>
/// <param name="method">GET or POST</param>
/// <param name="requestUrl">The full url, including the querystring for the signing/request</param>
/// <param name="headers">Header values</param>
/// <param name="parametersToSign">Parameters for the request, which need to be signed</param>
/// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param>
/// <param name="postData">Data to post (MemoryStream)</param>
/// <returns>The web server response.</returns>
public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) {
return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData);
}
/// <summary>
/// <summary>
/// Submit a web request using oAuth.
/// </summary>
/// <param name="method">GET or POST</param>

View file

@ -29,7 +29,6 @@ using System.Drawing;
using System.IO;
using System.Windows.Forms;
using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces.Forms;
namespace GreenshotPlugin.Core {
/// <summary>
@ -52,7 +51,7 @@ namespace GreenshotPlugin.Core {
/// <param name="e"></param>
private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName != "IconSize") return;
List<Image> cachedImages = new List<Image>();
var cachedImages = new List<Image>();
lock (ExeIconCache) {
foreach (string key in ExeIconCache.Keys) {
cachedImages.Add(ExeIconCache[key]);
@ -71,7 +70,7 @@ namespace GreenshotPlugin.Core {
/// <param name="exeName">e.g. cmd.exe</param>
/// <returns>Path to file</returns>
public static string GetExePath(string exeName) {
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) {
using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) {
if (key != null) {
// "" is the default key, which should point to the requested location
return (string)key.GetValue(string.Empty);
@ -147,69 +146,7 @@ namespace GreenshotPlugin.Core {
return null;
}
/// <summary>
/// Helper method to add a MenuItem to the File MenuItem of an ImageEditor
/// </summary>
/// <param name="imageEditor"></param>
/// <param name="image">Image to display in the menu</param>
/// <param name="text">Text to display in the menu</param>
/// <param name="tag">The TAG value</param>
/// <param name="shortcutKeys">Keys which can be used as shortcut</param>
/// <param name="handler">The onclick handler</param>
public static void AddToFileMenu(IImageEditor imageEditor, Image image, string text, object tag, Keys? shortcutKeys, EventHandler handler) {
var item = new ToolStripMenuItem
{
Image = image,
Text = text,
Tag = tag
};
if (shortcutKeys.HasValue) {
item.ShortcutKeys = shortcutKeys.Value;
}
item.Click += handler;
AddToFileMenu(imageEditor, item);
}
/// <summary>
/// Helper method to add a MenuItem to the File MenuItem of an ImageEditor
/// </summary>
/// <param name="imageEditor"></param>
/// <param name="item"></param>
public static void AddToFileMenu(IImageEditor imageEditor, ToolStripMenuItem item) {
ToolStripMenuItem toolStripMenuItem = imageEditor.GetFileMenuItem();
bool added = false;
for(int i = 0; i< toolStripMenuItem.DropDownItems.Count; i++) {
if (toolStripMenuItem.DropDownItems[i].GetType() == typeof(ToolStripSeparator)) {
toolStripMenuItem.DropDownItems.Insert(i, item);
added = true;
break;
}
}
if (!added) {
toolStripMenuItem.DropDownItems.Add(item);
}
}
/// <summary>
/// Helper method to add a MenuItem to the Plugin MenuItem of an ImageEditor
/// </summary>
/// <param name="imageEditor"></param>
/// <param name="item"></param>
public static void AddToPluginMenu(IImageEditor imageEditor, ToolStripMenuItem item) {
ToolStripMenuItem toolStripMenuItem = imageEditor.GetPluginMenuItem();
bool added = false;
for(int i = 0; i< toolStripMenuItem.DropDownItems.Count; i++) {
if (toolStripMenuItem.DropDownItems[i].GetType() == typeof(ToolStripSeparator)) {
toolStripMenuItem.DropDownItems.Insert(i, item);
added = true;
break;
}
}
if (!added) {
toolStripMenuItem.DropDownItems.Add(item);
}
}
/// <summary>
/// <summary>
/// Helper method to add a plugin MenuItem to the Greenshot context menu
/// </summary>
/// <param name="item">ToolStripMenuItem</param>

View file

@ -137,19 +137,5 @@ namespace GreenshotPlugin.Core {
return returnValue;
}
/// <summary>
/// Read "streamextensions" :)
/// </summary>
/// <param name="input">Stream</param>
/// <param name="output">Stream</param>
public static void CopyTo(this Stream input, Stream output) {
byte[] buffer = new byte[16 * 1024]; // Fairly arbitrary size
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) {
output.Write(buffer, 0, bytesRead);
}
}
}
}
}

View file

@ -298,17 +298,6 @@ namespace GreenshotPlugin.Core
return null;
}
/// <summary>
/// Retrieve the children with matching classname
/// </summary>
public IEnumerable<WindowDetails> GetChilden(string childClassname) {
foreach (var child in Children) {
if (childClassname.Equals(child.ClassName)) {
yield return child;
}
}
}
public IntPtr ParentHandle {
get {
if (_parentHandle == IntPtr.Zero) {
@ -379,92 +368,6 @@ namespace GreenshotPlugin.Core
return FindWindow(Children, titlePattern, classnamePattern);
}
/// <summary>
/// Recurse-ing helper method for the FindPath
/// </summary>
/// <param name="classNames">List string with classNames</param>
/// <param name="index">The index in the list to look for</param>
/// <returns>WindowDetails if a match was found</returns>
private WindowDetails FindPath(IList<string> classNames, int index) {
if (index == classNames.Count - 1) {
foreach (var foundWindow in FindChildren(null, classNames[index]))
{
return foundWindow;
}
} else {
foreach(var foundWindow in FindChildren(null, classNames[index]))
{
var resultWindow = foundWindow.FindPath(classNames, index+1);
if (resultWindow != null)
{
return resultWindow;
}
}
}
return null;
}
/// <summary>
/// This method will find the child window according to a path of classNames.
/// Usually used for finding a certain "content" window like for the IE Browser
/// </summary>
/// <param name="classNames">List of string with classname "path"</param>
/// <param name="allowSkip">true allows the search to skip a classname of the path</param>
/// <returns>WindowDetails if found</returns>
public WindowDetails FindPath(IList<string> classNames, bool allowSkip) {
int index = 0;
var resultWindow = FindPath(classNames, index++);
if (resultWindow == null && allowSkip) {
while(resultWindow == null && index < classNames.Count) {
resultWindow = FindPath(classNames, index);
}
}
return resultWindow;
}
/// <summary>
/// Deep scan for a certain classname pattern
/// </summary>
/// <param name="windowDetails">Window to scan into</param>
/// <param name="classnamePattern">Classname regexp pattern</param>
/// <returns>The first WindowDetails found</returns>
public static WindowDetails DeepScan(WindowDetails windowDetails, Regex classnamePattern) {
if (classnamePattern.IsMatch(windowDetails.ClassName)) {
return windowDetails;
}
// First loop through this level
foreach(var child in windowDetails.Children) {
if (classnamePattern.IsMatch(child.ClassName)) {
return child;
}
}
// Go into all children
foreach(var child in windowDetails.Children) {
var deepWindow = DeepScan(child, classnamePattern);
if (deepWindow != null) {
return deepWindow;
}
}
return null;
}
/// <summary>
/// GetWindow
/// </summary>
/// <param name="gwCommand">The GetWindowCommand to use</param>
/// <returns>null if nothing found, otherwise the WindowDetails instance of the "child"</returns>
public WindowDetails GetWindow(GetWindowCommand gwCommand) {
var tmphWnd = User32.GetWindow(Handle, gwCommand);
if (IntPtr.Zero == tmphWnd) {
return null;
}
var windowDetails = new WindowDetails(tmphWnd)
{
_parent = this
};
return windowDetails;
}
/// <summary>
/// Gets the window's handle
/// </summary>
@ -512,7 +415,7 @@ namespace GreenshotPlugin.Core
}
/// <summary>
/// Gets/Sets whether the window is maximised or not.
/// Gets/Sets whether the window is maximized or not.
/// </summary>
public bool Maximised {
get {
@ -541,13 +444,6 @@ namespace GreenshotPlugin.Core
}
}
/// <summary>
/// This doesn't work as good as is should, but does move the App out of the way...
/// </summary>
public void HideApp() {
User32.ShowWindow(Handle, ShowWindowCommand.Hide);
}
/// <summary>
/// Returns if this window is cloaked
/// </summary>
@ -627,13 +523,6 @@ namespace GreenshotPlugin.Core
}
}
/// <summary>
/// Make sure the next call of a cached value is guaranteed the real value
/// </summary>
public void Reset() {
_previousWindowRectangle = Rectangle.Empty;
}
private Rectangle _previousWindowRectangle = Rectangle.Empty;
private long _lastWindowRectangleRetrieveTime;
private const long CacheTime = TimeSpan.TicksPerSecond * 2;
@ -1354,24 +1243,6 @@ namespace GreenshotPlugin.Core
return null;
}
/// <summary>
/// Check if this window is Greenshot
/// </summary>
public bool IsGreenshot {
get {
try {
if (!IsMetroApp)
{
using Process thisWindowProcess = Process;
return "Greenshot".Equals(thisWindowProcess.MainModule.FileVersionInfo.ProductName);
}
} catch (Exception ex) {
Log.Warn(ex);
}
return false;
}
}
/// <summary>
/// Gets the Desktop window
/// </summary>

View file

@ -34,25 +34,7 @@ namespace GreenshotPlugin.Core {
/// </summary>
public IList<WindowDetails> Items { get; private set; }
/// <summary>
/// Gets all top level windows on the system.
/// </summary>
public WindowsEnumerator GetWindows() {
GetWindows(IntPtr.Zero, null);
return this;
}
/// <summary>
/// Gets all child windows of the specified window
/// </summary>
/// <param name="parent">Window Handle to get children for</param>
public WindowsEnumerator GetWindows(WindowDetails parent)
{
GetWindows(parent?.Handle ?? IntPtr.Zero, null);
return this;
}
/// <summary>
/// <summary>
/// Gets all child windows of the specified window
/// </summary>
/// <param name="hWndParent">Window Handle to get children for</param>
@ -69,7 +51,7 @@ namespace GreenshotPlugin.Core {
parentText = title.ToString();
}
List<WindowDetails> windows = new List<WindowDetails>();
var windows = new List<WindowDetails>();
foreach (var window in Items) {
if (hasParent) {
window.Text = parentText;

View file

@ -15,51 +15,18 @@ namespace GreenshotPlugin.Core
/// </summary>
public static Version WinVersion { get; } = Environment.OSVersion.Version;
public static double WinVersionTotal = WinVersion.Major + (double)WinVersion.Minor / 10;
/// <summary>
/// Test if the current OS is Windows 10
/// </summary>
/// <returns>true if we are running on Windows 10</returns>
public static bool IsWindows10 { get; } = WinVersion.Major == 10;
/// <summary>
/// Test if the current OS is before Windows 10
/// </summary>
/// <returns>true if we are running on Windows before 10</returns>
public static bool IsBeforeWindows10 { get; } = WinVersion.Major < 10;
/// <summary>
/// Test if the current OS is Windows 10 or later
/// </summary>
/// <returns>true if we are running on Windows 10 or later</returns>
public static bool IsWindows10OrLater { get; } = WinVersion.Major >= 10;
/// <summary>
/// Test if the current OS is Windows 7 or later
/// </summary>
/// <returns>true if we are running on Windows 7 or later</returns>
public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6;
public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1;
/// <summary>
/// Test if the current OS is Windows 8.0
/// </summary>
/// <returns>true if we are running on Windows 8.0</returns>
public static bool IsWindows8 { get; } = WinVersion.Major == 6 && WinVersion.Minor == 2;
/// <summary>
/// Test if the current OS is Windows 8(.1)
/// </summary>
/// <returns>true if we are running on Windows 8(.1)</returns>
public static bool IsWindows81 { get; } = WinVersion.Major == 6 && WinVersion.Minor == 3;
/// <summary>
/// Test if the current OS is Windows 8.0 or 8.1
/// </summary>
/// <returns>true if we are running on Windows 8.1 or 8.0</returns>
public static bool IsWindows8X { get; } = IsWindows8 || IsWindows81;
/// <summary>
/// Test if the current OS is Windows 8.1 or later
/// </summary>
@ -72,36 +39,12 @@ namespace GreenshotPlugin.Core
/// <returns>true if we are running on Windows 8 or later</returns>
public static bool IsWindows8OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 2 || WinVersion.Major > 6;
/// <summary>
/// Test if the current OS is Windows Vista
/// </summary>
/// <returns>true if we are running on Windows Vista or later</returns>
public static bool IsWindowsVista { get; } = WinVersion.Major >= 6 && WinVersion.Minor == 0;
/// <summary>
/// Test if the current OS is Windows Vista or later
/// </summary>
/// <returns>true if we are running on Windows Vista or later</returns>
public static bool IsWindowsVistaOrLater { get; } = WinVersion.Major >= 6;
/// <summary>
/// Test if the current OS is from before Windows Vista (e.g. Windows XP)
/// </summary>
/// <returns>true if we are running on Windows from before Vista</returns>
public static bool IsWindowsBeforeVista { get; } = WinVersion.Major < 6;
/// <summary>
/// Test if the current OS is Windows XP
/// </summary>
/// <returns>true if we are running on Windows XP or later</returns>
public static bool IsWindowsXp { get; } = WinVersion.Major == 5 && WinVersion.Minor >= 1;
/// <summary>
/// Test if the current OS is Windows XP or later
/// </summary>
/// <returns>true if we are running on Windows XP or later</returns>
public static bool IsWindowsXpOrLater { get; } = WinVersion.Major >= 5 || WinVersion.Major == 5 && WinVersion.Minor >= 1;
/// <summary>
/// Returns the windows build number
/// </summary>