mirror of
https://github.com/greenshot/greenshot
synced 2025-07-13 00:23:54 -07:00
This should fix most icon scaling issues
Improved the IniReader a bit and replaced some old code.
This commit is contained in:
parent
41baf27d84
commit
4a958be8b5
35 changed files with 2767 additions and 301 deletions
|
@ -16,7 +16,7 @@
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<!-- Optional: Embed source files that are not tracked by the source control manager in the PDB -->
|
<!-- Optional: Embed source files that are not tracked by the source control manager in the PDB -->
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- ILLinker and single file settings -->
|
<!-- ILLinker and single file settings -->
|
||||||
|
@ -25,8 +25,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="$(MSBuildProjectName) == 'Greenshot'">
|
<PropertyGroup Condition="$(MSBuildProjectName) == 'Greenshot'">
|
||||||
<IncludeSymbolsInSingleFile>false</IncludeSymbolsInSingleFile>
|
<IncludeSymbolsInSingleFile>false</IncludeSymbolsInSingleFile>
|
||||||
<ShowLinkerSizeComparison>true</ShowLinkerSizeComparison>
|
<ShowLinkerSizeComparison>true</ShowLinkerSizeComparison>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' != 'Debug' And !$(MSBuildProjectName.Contains('Test')) And !$(MSBuildProjectName.Contains('Demo'))">
|
<PropertyGroup Condition="'$(Configuration)' != 'Debug' And !$(MSBuildProjectName.Contains('Test')) And !$(MSBuildProjectName.Contains('Demo'))">
|
||||||
|
|
|
@ -33,9 +33,9 @@ namespace Greenshot.Controls {
|
||||||
private static Image _scaledCheckbox;
|
private static Image _scaledCheckbox;
|
||||||
|
|
||||||
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) {
|
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) {
|
||||||
if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.IconSize) {
|
if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) {
|
||||||
_scaledCheckbox?.Dispose();
|
_scaledCheckbox?.Dispose();
|
||||||
_scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.IconSize.Width, CoreConfig.IconSize.Height, null);
|
_scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null);
|
||||||
}
|
}
|
||||||
Rectangle old = e.ImageRectangle;
|
Rectangle old = e.ImageRectangle;
|
||||||
ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height));
|
ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height));
|
||||||
|
|
|
@ -102,7 +102,7 @@ namespace Greenshot.Drawing {
|
||||||
};
|
};
|
||||||
using GraphicsPath path = new GraphicsPath();
|
using GraphicsPath path = new GraphicsPath();
|
||||||
path.AddLine(Left, Top, Left + Width, Top + Height);
|
path.AddLine(Left, Top, Left + Width, Top + Height);
|
||||||
return path.IsOutlineVisible(x, y, pen);
|
return path.IsOutlineVisible(x, y, pen);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
10
Greenshot/Forms/ImageEditorForm.Designer.cs
generated
10
Greenshot/Forms/ImageEditorForm.Designer.cs
generated
|
@ -293,7 +293,7 @@ namespace Greenshot {
|
||||||
// toolsToolStrip
|
// toolsToolStrip
|
||||||
//
|
//
|
||||||
this.toolsToolStrip.ClickThrough = true;
|
this.toolsToolStrip.ClickThrough = true;
|
||||||
this.toolsToolStrip.ImageScalingSize = coreConfiguration.IconSize;
|
this.toolsToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize;
|
||||||
this.toolsToolStrip.Dock = System.Windows.Forms.DockStyle.None;
|
this.toolsToolStrip.Dock = System.Windows.Forms.DockStyle.None;
|
||||||
this.toolsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
this.toolsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||||
this.toolsToolStrip.Renderer = new CustomToolStripProfessionalRenderer();
|
this.toolsToolStrip.Renderer = new CustomToolStripProfessionalRenderer();
|
||||||
|
@ -529,7 +529,7 @@ namespace Greenshot {
|
||||||
// menuStrip1
|
// menuStrip1
|
||||||
//
|
//
|
||||||
this.menuStrip1.ClickThrough = true;
|
this.menuStrip1.ClickThrough = true;
|
||||||
this.menuStrip1.ImageScalingSize = coreConfiguration.IconSize;
|
this.menuStrip1.ImageScalingSize = coreConfiguration.ScaledIconSize;
|
||||||
this.menuStrip1.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.menuStrip1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.menuStrip1.Stretch = true;
|
this.menuStrip1.Stretch = true;
|
||||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||||
|
@ -858,7 +858,7 @@ namespace Greenshot {
|
||||||
// destinationsToolStrip
|
// destinationsToolStrip
|
||||||
//
|
//
|
||||||
this.destinationsToolStrip.ClickThrough = true;
|
this.destinationsToolStrip.ClickThrough = true;
|
||||||
this.destinationsToolStrip.ImageScalingSize = coreConfiguration.IconSize;
|
this.destinationsToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize;
|
||||||
this.destinationsToolStrip.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.destinationsToolStrip.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.destinationsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
this.destinationsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||||
this.destinationsToolStrip.Name = "toolStrip1";
|
this.destinationsToolStrip.Name = "toolStrip1";
|
||||||
|
@ -1014,10 +1014,10 @@ namespace Greenshot {
|
||||||
//
|
//
|
||||||
this.propertiesToolStrip.AutoSize = false;
|
this.propertiesToolStrip.AutoSize = false;
|
||||||
this.propertiesToolStrip.ClickThrough = true;
|
this.propertiesToolStrip.ClickThrough = true;
|
||||||
this.propertiesToolStrip.ImageScalingSize = coreConfiguration.IconSize;
|
this.propertiesToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize;
|
||||||
this.propertiesToolStrip.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.propertiesToolStrip.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.propertiesToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
this.propertiesToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||||
this.propertiesToolStrip.MinimumSize = new System.Drawing.Size(150, coreConfiguration.IconSize.Height + 10);
|
this.propertiesToolStrip.MinimumSize = new System.Drawing.Size(150, coreConfiguration.ScaledIconSize.Height + 10);
|
||||||
this.propertiesToolStrip.Name = "propertiesToolStrip";
|
this.propertiesToolStrip.Name = "propertiesToolStrip";
|
||||||
this.propertiesToolStrip.Stretch = true;
|
this.propertiesToolStrip.Stretch = true;
|
||||||
this.propertiesToolStrip.TabIndex = 2;
|
this.propertiesToolStrip.TabIndex = 2;
|
||||||
|
|
2
Greenshot/Forms/MainForm.Designer.cs
generated
2
Greenshot/Forms/MainForm.Designer.cs
generated
|
@ -203,7 +203,7 @@ namespace Greenshot {
|
||||||
// contextmenu_quicksettings
|
// contextmenu_quicksettings
|
||||||
//
|
//
|
||||||
this.contextmenu_quicksettings.Name = "contextmenu_quicksettings";
|
this.contextmenu_quicksettings.Name = "contextmenu_quicksettings";
|
||||||
this.contextmenu_quicksettings.Size = new System.Drawing.Size(170, coreConfiguration.IconSize.Height + 8);
|
this.contextmenu_quicksettings.Size = new System.Drawing.Size(170, coreConfiguration.ScaledIconSize.Height + 8);
|
||||||
//
|
//
|
||||||
// contextmenu_settings
|
// contextmenu_settings
|
||||||
//
|
//
|
||||||
|
|
|
@ -549,7 +549,7 @@ namespace Greenshot {
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) {
|
private void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) {
|
||||||
if (e.PropertyName == "IconSize") {
|
if (e.PropertyName == "IconSize") {
|
||||||
contextMenu.ImageScalingSize = coreConfiguration.IconSize;
|
contextMenu.ImageScalingSize = coreConfiguration.ScaledIconSize;
|
||||||
string ieExePath = PluginUtils.GetExePath("iexplore.exe");
|
string ieExePath = PluginUtils.GetExePath("iexplore.exe");
|
||||||
if (!string.IsNullOrEmpty(ieExePath)) {
|
if (!string.IsNullOrEmpty(ieExePath)) {
|
||||||
contextmenu_captureie.Image = PluginUtils.GetCachedExeIcon(ieExePath, 0);
|
contextmenu_captureie.Image = PluginUtils.GetCachedExeIcon(ieExePath, 0);
|
||||||
|
@ -614,7 +614,7 @@ namespace Greenshot {
|
||||||
/// <returns>true if onedrive has hotkeys turned on</returns>
|
/// <returns>true if onedrive has hotkeys turned on</returns>
|
||||||
private static bool IsOneDriveBlockingHotkey()
|
private static bool IsOneDriveBlockingHotkey()
|
||||||
{
|
{
|
||||||
if (!Environment.OSVersion.IsWindows10())
|
if (!WindowsVersion.IsWindows10OrLater)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,6 +334,7 @@ namespace Greenshot {
|
||||||
listview_destinations.Items.Clear();
|
listview_destinations.Items.Clear();
|
||||||
listview_destinations.ListViewItemSorter = new ListviewWithDestinationComparer();
|
listview_destinations.ListViewItemSorter = new ListviewWithDestinationComparer();
|
||||||
ImageList imageList = new ImageList();
|
ImageList imageList = new ImageList();
|
||||||
|
imageList.ImageSize = coreConfiguration.ScaledIconSize;
|
||||||
listview_destinations.SmallImageList = imageList;
|
listview_destinations.SmallImageList = imageList;
|
||||||
int imageNr = -1;
|
int imageNr = -1;
|
||||||
foreach (IDestination currentDestination in DestinationHelper.GetAllDestinations()) {
|
foreach (IDestination currentDestination in DestinationHelper.GetAllDestinations()) {
|
||||||
|
@ -422,7 +423,7 @@ namespace Greenshot {
|
||||||
|
|
||||||
numericUpDown_daysbetweencheck.Value = coreConfiguration.UpdateCheckInterval;
|
numericUpDown_daysbetweencheck.Value = coreConfiguration.UpdateCheckInterval;
|
||||||
numericUpDown_daysbetweencheck.Enabled = !coreConfiguration.Values["UpdateCheckInterval"].IsFixed;
|
numericUpDown_daysbetweencheck.Enabled = !coreConfiguration.Values["UpdateCheckInterval"].IsFixed;
|
||||||
numericUpdownIconSize.Value = coreConfiguration.IconSize.Width /16 * 16;
|
numericUpdownIconSize.Value = coreConfiguration.ScaledIconSize.Width /16 * 16;
|
||||||
CheckDestinationSettings();
|
CheckDestinationSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ namespace Greenshot.Forms {
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
CheckOnClick = false;
|
CheckOnClick = false;
|
||||||
_multiCheckAllowed = allowMultiCheck;
|
_multiCheckAllowed = allowMultiCheck;
|
||||||
if (_defaultImage == null || _defaultImage.Size != CoreConfig.IconSize) {
|
if (_defaultImage == null || _defaultImage.Size != CoreConfig.ScaledIconSize) {
|
||||||
_defaultImage?.Dispose();
|
_defaultImage?.Dispose();
|
||||||
_defaultImage = ImageHelper.CreateEmpty(CoreConfig.IconSize.Width, CoreConfig.IconSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb, Color.Transparent, 96f, 96f);
|
_defaultImage = ImageHelper.CreateEmpty(CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb, Color.Transparent, 96f, 96f);
|
||||||
}
|
}
|
||||||
Image = _defaultImage;
|
Image = _defaultImage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ namespace GreenshotJiraPlugin.Forms {
|
||||||
jiraListView.Columns.Add(translation);
|
jiraListView.Columns.Add(translation);
|
||||||
}
|
}
|
||||||
var imageList = new ImageList {
|
var imageList = new ImageList {
|
||||||
ImageSize = CoreConfig.IconSize
|
ImageSize = CoreConfig.ScaledIconSize
|
||||||
};
|
};
|
||||||
jiraListView.SmallImageList = imageList;
|
jiraListView.SmallImageList = imageList;
|
||||||
jiraListView.LargeImageList = imageList;
|
jiraListView.LargeImageList = imageList;
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace GreenshotJiraPlugin {
|
||||||
{
|
{
|
||||||
if (args.PropertyName == nameof(CoreConfig.IconSize))
|
if (args.PropertyName == nameof(CoreConfig.IconSize))
|
||||||
{
|
{
|
||||||
JiraPlugin.Instance.JiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.IconSize.Width, Height = CoreConfig.IconSize.Height });
|
JiraPlugin.Instance.JiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.ScaledIconSize.Width, Height = CoreConfig.ScaledIconSize.Height });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ namespace GreenshotJiraPlugin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_jiraClient = JiraClient.Create(new Uri(JiraConfig.Url));
|
_jiraClient = JiraClient.Create(new Uri(JiraConfig.Url));
|
||||||
_jiraClient.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.IconSize.Width, Height = CoreConfig.IconSize.Height });
|
_jiraClient.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.ScaledIconSize.Width, Height = CoreConfig.ScaledIconSize.Height });
|
||||||
_jiraClient.SetBasicAuthentication(user, password);
|
_jiraClient.SetBasicAuthentication(user, password);
|
||||||
|
|
||||||
_issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient);
|
_issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient);
|
||||||
|
|
|
@ -16,16 +16,34 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Interop.Microsoft.Office.Interop.OneNote" Version="1.1.0" />
|
<PackageReference Include="Interop.Microsoft.Office.Interop.OneNote" Version="1.1.0">
|
||||||
<PackageReference Include="Microsoft.Office.Interop.Excel" Version="15.0.4795.1000" />
|
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||||
<PackageReference Include="Microsoft.Office.Interop.Outlook" Version="15.0.4797.1003" />
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
<PackageReference Include="Microsoft.Office.Interop.PowerPoint" Version="15.0.4420.1017" />
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Office.Interop.Word" Version="15.0.4797.1003" />
|
<PackageReference Include="Microsoft.Office.Interop.Excel" Version="15.0.4795.1000">
|
||||||
<PackageReference Include="MicrosoftOfficeCore" Version="15.0.0" />
|
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.Office.Interop.Outlook" Version="15.0.4797.1003">
|
||||||
|
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.Office.Interop.PowerPoint" Version="15.0.4420.1017">
|
||||||
|
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.Office.Interop.Word" Version="15.0.4797.1003">
|
||||||
|
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="MicrosoftOfficeCore" Version="15.0.0">
|
||||||
|
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Unofficial.Microsoft.mshtml" Version="7.0.3300">
|
<PackageReference Include="Unofficial.Microsoft.mshtml" Version="7.0.3300">
|
||||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="log4net" Version="2.0.8" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace GreenshotPlugin.Core {
|
||||||
ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker"));
|
ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker"));
|
||||||
var menu = new ContextMenuStrip
|
var menu = new ContextMenuStrip
|
||||||
{
|
{
|
||||||
ImageScalingSize = CoreConfig.IconSize,
|
ImageScalingSize = CoreConfig.ScaledIconSize,
|
||||||
Tag = null,
|
Tag = null,
|
||||||
TopLevel = true
|
TopLevel = true
|
||||||
};
|
};
|
||||||
|
|
|
@ -267,7 +267,7 @@ namespace GreenshotPlugin.Core {
|
||||||
public Size Win10BorderCrop { get; set; }
|
public Size Win10BorderCrop { get; set; }
|
||||||
|
|
||||||
private Size _iconSize;
|
private Size _iconSize;
|
||||||
[IniProperty("IconSize", Description = "Defines the size of the icons (e.g. for the buttons in the editor), default value 16,16 anything bigger will cause scaling", DefaultValue = "16,16")]
|
[IniProperty("BaseIconSize", Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", DefaultValue = "16,16")]
|
||||||
public Size IconSize {
|
public Size IconSize {
|
||||||
get {
|
get {
|
||||||
return _iconSize;
|
return _iconSize;
|
||||||
|
@ -295,6 +295,8 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize);
|
||||||
|
|
||||||
[IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")]
|
[IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")]
|
||||||
public int WebRequestTimeout { get; set; }
|
public int WebRequestTimeout { get; set; }
|
||||||
[IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")]
|
[IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")]
|
||||||
|
|
711
GreenshotPlugin/Core/DpiHelper.cs
Normal file
711
GreenshotPlugin/Core/DpiHelper.cs
Normal file
|
@ -0,0 +1,711 @@
|
||||||
|
using GreenshotPlugin.Core.Enums;
|
||||||
|
using GreenshotPlugin.UnmanagedHelpers;
|
||||||
|
using log4net;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace GreenshotPlugin.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This handles DPI changes see
|
||||||
|
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266.aspx">Writing DPI-Aware Desktop and Win32 Applications</a>
|
||||||
|
/// </summary>
|
||||||
|
public static class DpiHelper
|
||||||
|
{
|
||||||
|
private static readonly ILog Log = LogManager.GetLogger(typeof(DpiHelper));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the default DPI for the screen
|
||||||
|
/// </summary>
|
||||||
|
public const uint DefaultScreenDpi = 96;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the current DPI for the UI element which is related to this DpiHandler
|
||||||
|
/// </summary>
|
||||||
|
public static uint Dpi { get; private set; } = GetDpiForSystem();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate a DPI scale factor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dpi">uint</param>
|
||||||
|
/// <returns>double</returns>
|
||||||
|
public static float DpiScaleFactor(uint dpi)
|
||||||
|
{
|
||||||
|
return (float)dpi / DefaultScreenDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scale the supplied number according to the supplied dpi
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="someNumber">double with e.g. the width 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>double with the scaled number</returns>
|
||||||
|
public static float ScaleWithDpi(float someNumber, uint dpi, Func<float, float> scaleModifier = null)
|
||||||
|
{
|
||||||
|
var dpiScaleFactor = DpiScaleFactor(dpi);
|
||||||
|
if (scaleModifier != null)
|
||||||
|
{
|
||||||
|
dpiScaleFactor = scaleModifier(dpiScaleFactor);
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
/// <param name="size">Size 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 Size ScaleWithDpi(Size size, uint dpi, Func<float, float> scaleModifier = null)
|
||||||
|
{
|
||||||
|
var dpiScaleFactor = DpiScaleFactor(dpi);
|
||||||
|
if (scaleModifier != null)
|
||||||
|
{
|
||||||
|
dpiScaleFactor = scaleModifier(dpiScaleFactor);
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
/// <param name="size">NativeSize to scale</param>
|
||||||
|
/// <param name="scaleModifier">A function which can modify the scale factor</param>
|
||||||
|
/// <returns>NativeSize scaled</returns>
|
||||||
|
public static Size ScaleWithCurrentDpi(Size size, Func<float, float> scaleModifier = null)
|
||||||
|
{
|
||||||
|
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>
|
||||||
|
/// Retrieve the DPI value for the supplied window handle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd">IntPtr</param>
|
||||||
|
/// <returns>dpi value</returns>
|
||||||
|
public static uint GetDpi(IntPtr hWnd)
|
||||||
|
{
|
||||||
|
if (!User32.IsWindow(hWnd))
|
||||||
|
{
|
||||||
|
return DefaultScreenDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the easiest method, but this only works for Windows 10
|
||||||
|
if (WindowsVersion.IsWindows10OrLater)
|
||||||
|
{
|
||||||
|
return GetDpiForWindow(hWnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the second easiest method, but this only works for Windows 8.1 or later
|
||||||
|
if (WindowsVersion.IsWindows81OrLater)
|
||||||
|
{
|
||||||
|
var hMonitor = User32.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest);
|
||||||
|
// ReSharper disable once UnusedVariable
|
||||||
|
if (GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY))
|
||||||
|
{
|
||||||
|
return dpiX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to the global DPI settings
|
||||||
|
using var hdc = SafeWindowDcHandle.FromWindow(hWnd);
|
||||||
|
if (hdc == null)
|
||||||
|
{
|
||||||
|
return DefaultScreenDpi;
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd">IntPtr</param>
|
||||||
|
/// <returns>uint with dpi</returns>
|
||||||
|
[DllImport("User32.dll")]
|
||||||
|
private static extern uint GetDpiForWindow(IntPtr hWnd);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See
|
||||||
|
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx">GetDpiForMonitor function</a>
|
||||||
|
/// Queries the dots per inch (dpi) of a display.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hMonitor">IntPtr</param>
|
||||||
|
/// <param name="dpiType">MonitorDpiType</param>
|
||||||
|
/// <param name="dpiX">out int for the horizontal dpi</param>
|
||||||
|
/// <param name="dpiY">out int for the vertical dpi</param>
|
||||||
|
/// <returns>true if all okay</returns>
|
||||||
|
[DllImport("shcore")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static extern bool 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <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);
|
||||||
|
}
|
||||||
|
}
|
34
GreenshotPlugin/Core/Enums/DialogDpiChangeBehaviors.cs
Normal file
34
GreenshotPlugin/Core/Enums/DialogDpiChangeBehaviors.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
32
GreenshotPlugin/Core/Enums/DialogScalingBehaviors.cs
Normal file
32
GreenshotPlugin/Core/Enums/DialogScalingBehaviors.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
40
GreenshotPlugin/Core/Enums/DpiAwareness.cs
Normal file
40
GreenshotPlugin/Core/Enums/DpiAwareness.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
46
GreenshotPlugin/Core/Enums/DpiAwarenessContext.cs
Normal file
46
GreenshotPlugin/Core/Enums/DpiAwarenessContext.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
28
GreenshotPlugin/Core/Enums/DpiHostingBehavior.cs
Normal file
28
GreenshotPlugin/Core/Enums/DpiHostingBehavior.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,25 @@
|
||||||
using System;
|
// Greenshot - a free and open source screenshot tool
|
||||||
using System.Collections.Generic;
|
// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
|
||||||
using System.Diagnostics.CodeAnalysis;
|
//
|
||||||
using System.Linq;
|
// For more information see: http://getgreenshot.org/
|
||||||
using System.Text;
|
// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||||
using System.Threading.Tasks;
|
//
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
namespace GreenshotWin10Plugin.Native
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace GreenshotPlugin.Core.Enums
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The HRESULT represents Windows error codes
|
/// The HRESULT represents Windows error codes
|
40
GreenshotPlugin/Core/Enums/MonitorDpiType.cs
Normal file
40
GreenshotPlugin/Core/Enums/MonitorDpiType.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// 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>
|
||||||
|
/// See
|
||||||
|
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511(v=vs.85).aspx">
|
||||||
|
/// MONITOR_DPI_TYPE
|
||||||
|
/// enumeration
|
||||||
|
/// </a>
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum MonitorDpiType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The effective DPI.
|
||||||
|
/// This value should be used when determining the correct scale factor for scaling UI elements.
|
||||||
|
/// This incorporates the scale factor set by the user for this specific display.
|
||||||
|
/// </summary>
|
||||||
|
EffectiveDpi = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The angular DPI.
|
||||||
|
/// This DPI ensures rendering at a compliant angular resolution on the screen.
|
||||||
|
/// This does not include the scale factor set by the user for this specific display
|
||||||
|
/// </summary>
|
||||||
|
AngularDpi = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The raw DPI.
|
||||||
|
/// This value is the linear DPI of the screen as measured on the screen itself.
|
||||||
|
/// Use this value when you want to read the pixel density and not the recommended scaling setting.
|
||||||
|
/// This does not include the scale factor set by the user for this specific display and is not guaranteed to be a
|
||||||
|
/// supported DPI value.
|
||||||
|
/// </summary>
|
||||||
|
RawDpi = 2
|
||||||
|
}
|
||||||
|
}
|
30
GreenshotPlugin/Core/Enums/MonitorFrom.cs
Normal file
30
GreenshotPlugin/Core/Enums/MonitorFrom.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// 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>
|
||||||
|
/// Flags for the MonitorFromRect / MonitorFromWindow "flags" field
|
||||||
|
/// see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145063(v=vs.85).aspx">MonitorFromRect function</a>
|
||||||
|
/// or see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145064(v=vs.85).aspx">MonitorFromWindow function</a>
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum MonitorFrom : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a handle to the display monitor that is nearest to the rectangle.
|
||||||
|
/// </summary>
|
||||||
|
DefaultToNearest = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns NULL. (why??)
|
||||||
|
/// </summary>
|
||||||
|
DefaultToNull = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a handle to the primary display monitor.
|
||||||
|
/// </summary>
|
||||||
|
DefaultToPrimary = 2
|
||||||
|
}
|
||||||
|
}
|
1390
GreenshotPlugin/Core/Enums/SystemParametersInfoActions.cs
Normal file
1390
GreenshotPlugin/Core/Enums/SystemParametersInfoActions.cs
Normal file
File diff suppressed because it is too large
Load diff
28
GreenshotPlugin/Core/Enums/SystemParametersInfoBehaviors.cs
Normal file
28
GreenshotPlugin/Core/Enums/SystemParametersInfoBehaviors.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,10 +17,11 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using GreenshotPlugin.Core.Enums;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace GreenshotWin10Plugin.Native
|
namespace GreenshotPlugin.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extensions to handle the HResult
|
/// Extensions to handle the HResult
|
||||||
|
@ -55,7 +56,7 @@ namespace GreenshotWin10Plugin.Native
|
||||||
/// <param name="hResult">HResult</param>
|
/// <param name="hResult">HResult</param>
|
||||||
public static void ThrowOnFailure(this HResult hResult)
|
public static void ThrowOnFailure(this HResult hResult)
|
||||||
{
|
{
|
||||||
if (Failed(hResult))
|
if (hResult.Failed())
|
||||||
{
|
{
|
||||||
throw Marshal.GetExceptionForHR((int)hResult);
|
throw Marshal.GetExceptionForHR((int)hResult);
|
||||||
}
|
}
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* Greenshot - a free and open source screenshot tool
|
|
||||||
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
|
|
||||||
*
|
|
||||||
* For more information see: http://getgreenshot.org/
|
|
||||||
* The Greenshot project is hosted on GitHub: https://github.com/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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Extensions to help with querying the Operating System
|
|
||||||
/// </summary>
|
|
||||||
public static class OperatingSystemExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows 10
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows 10</returns>
|
|
||||||
public static bool IsWindows10(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
return operatingSystem.Version.Major == 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows 10 or later
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows 10 or later</returns>
|
|
||||||
public static bool IsWindows10OrLater(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
return operatingSystem.Version.Major >= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows 8(.1)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows 8(.1)</returns>
|
|
||||||
public static bool IsWindows8(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
return operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows 8 or later
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows 8 or later</returns>
|
|
||||||
public static bool IsWindows8OrLater(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
return (operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 2) || operatingSystem.Version.Major > 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows 7 or later
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows 7 or later</returns>
|
|
||||||
public static bool IsWindows7OrLater(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
return (operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 1) || operatingSystem.Version.Major > 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows Vista or later
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows Vista or later</returns>
|
|
||||||
public static bool IsWindowsVistaOrLater(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
return operatingSystem.Version.Major >= 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test if the current OS is Windows XP or later
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operatingSystem">OperatingSystem from Environment.OSVersion</param>
|
|
||||||
/// <returns>true if we are running on Windows XP or later</returns>
|
|
||||||
public static bool IsWindowsXpOrLater(this OperatingSystem operatingSystem)
|
|
||||||
{
|
|
||||||
// Windows 2000 is Major 5 minor 0
|
|
||||||
return Environment.OSVersion.Version.Major > 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -757,7 +757,7 @@ namespace GreenshotPlugin.Core {
|
||||||
_lastWindowRectangleRetrieveTime = now;
|
_lastWindowRectangleRetrieveTime = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gotFrameBounds && Environment.OSVersion.IsWindows10() && !Maximised)
|
if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised)
|
||||||
{
|
{
|
||||||
// Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture
|
// Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture
|
||||||
// Remove this border, currently it's fixed but TODO: Make it depend on the OS?
|
// Remove this border, currently it's fixed but TODO: Make it depend on the OS?
|
||||||
|
@ -969,7 +969,7 @@ namespace GreenshotPlugin.Core {
|
||||||
} else {
|
} else {
|
||||||
doesCaptureFit = true;
|
doesCaptureFit = true;
|
||||||
}
|
}
|
||||||
} else if (!Environment.OSVersion.IsWindows8OrLater()) {
|
} else if (!WindowsVersion.IsWindows8OrLater) {
|
||||||
//GetClientRect(out windowRectangle);
|
//GetClientRect(out windowRectangle);
|
||||||
GetBorderSize(out borderSize);
|
GetBorderSize(out borderSize);
|
||||||
formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height);
|
formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height);
|
||||||
|
@ -986,7 +986,7 @@ namespace GreenshotPlugin.Core {
|
||||||
captureRectangle.Inflate(borderSize.Width, borderSize.Height);
|
captureRectangle.Inflate(borderSize.Width, borderSize.Height);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Also 8.x?
|
// TODO: Also 8.x?
|
||||||
if (Environment.OSVersion.IsWindows10())
|
if (WindowsVersion.IsWindows10OrLater)
|
||||||
{
|
{
|
||||||
captureRectangle.Inflate(Conf.Win10BorderCrop);
|
captureRectangle.Inflate(Conf.Win10BorderCrop);
|
||||||
}
|
}
|
||||||
|
@ -1079,7 +1079,7 @@ namespace GreenshotPlugin.Core {
|
||||||
}
|
}
|
||||||
if (capturedBitmap != null) {
|
if (capturedBitmap != null) {
|
||||||
// Not needed for Windows 8
|
// Not needed for Windows 8
|
||||||
if (!Environment.OSVersion.IsWindows8OrLater()) {
|
if (!WindowsVersion.IsWindows8OrLater) {
|
||||||
// Only if the Inivalue is set, not maximized and it's not a tool window.
|
// Only if the Inivalue is set, not maximized and it's not a tool window.
|
||||||
if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) {
|
if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) {
|
||||||
// Remove corners
|
// Remove corners
|
||||||
|
|
107
GreenshotPlugin/Core/WindowsVersion.cs
Normal file
107
GreenshotPlugin/Core/WindowsVersion.cs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods to test the windows version
|
||||||
|
/// </summary>
|
||||||
|
public static class WindowsVersion
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get the current windows version
|
||||||
|
/// </summary>
|
||||||
|
public static Version WinVersion { get; } = Environment.OSVersion.Version;
|
||||||
|
|
||||||
|
/// <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 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;
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// <returns>true if we are running on Windows 8.1 or later</returns>
|
||||||
|
public static bool IsWindows81OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 3 || WinVersion.Major > 6;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test if the current OS is Windows 8 or later
|
||||||
|
/// </summary>
|
||||||
|
/// <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>
|
||||||
|
/// Test if the current Windows version is 10 and the build number or later
|
||||||
|
/// See the build numbers <a href="https://en.wikipedia.org/wiki/Windows_10_version_history">here</a>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="minimalBuildNumber">int</param>
|
||||||
|
/// <returns>bool</returns>
|
||||||
|
public static bool IsWindows10BuildOrLater(int minimalBuildNumber)
|
||||||
|
{
|
||||||
|
return IsWindows10 && WinVersion.Build >= minimalBuildNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,12 +25,12 @@ using System.Text;
|
||||||
|
|
||||||
namespace Greenshot.IniFile {
|
namespace Greenshot.IniFile {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// The IniReader does exactly what it says, it reads the .ini file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class IniReader {
|
public static class IniReader {
|
||||||
private const string SectionStart = "[";
|
private const char SectionStartToken = '[';
|
||||||
private const string SectionEnd = "]";
|
private const char SectionEndToken = ']';
|
||||||
private const string Comment = ";";
|
private const char CommentToken = ';';
|
||||||
private static readonly char[] Assignment = { '=' };
|
private static readonly char[] Assignment = { '=' };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -52,11 +52,16 @@ namespace Greenshot.IniFile {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
string cleanLine = line.Trim();
|
string cleanLine = line.Trim();
|
||||||
if (cleanLine.Length == 0 || cleanLine.StartsWith(Comment)) {
|
if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (cleanLine.StartsWith(SectionStart)) {
|
if (cleanLine[0] == SectionStartToken) {
|
||||||
string section = line.Replace(SectionStart, string.Empty).Replace(SectionEnd, string.Empty).Trim();
|
var sectionEndIndex = line.IndexOf(SectionEndToken,1);
|
||||||
|
if (sectionEndIndex <0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string section = line.Substring(1,sectionEndIndex-1).Trim();
|
||||||
if (!ini.TryGetValue(section, out nameValues))
|
if (!ini.TryGetValue(section, out nameValues))
|
||||||
{
|
{
|
||||||
nameValues = new Dictionary<string, string>();
|
nameValues = new Dictionary<string, string>();
|
||||||
|
|
|
@ -30,6 +30,7 @@ using Microsoft.Win32.SafeHandles;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Security.Permissions;
|
using System.Security.Permissions;
|
||||||
using log4net;
|
using log4net;
|
||||||
|
using GreenshotPlugin.Core.Enums;
|
||||||
|
|
||||||
namespace GreenshotPlugin.UnmanagedHelpers {
|
namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -62,6 +63,19 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
|
|
||||||
[DllImport("user32", SetLastError = true)]
|
[DllImport("user32", SetLastError = true)]
|
||||||
public static extern bool keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
|
public static extern bool keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified window handle identifies an existing window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd">A handle to the window to be tested.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// If the window handle identifies an existing window, the return value is true.
|
||||||
|
/// If the window handle does not identify an existing window, the return value is false.
|
||||||
|
/// </returns>
|
||||||
|
[DllImport("user32", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool IsWindow(IntPtr hWnd);
|
||||||
|
|
||||||
[DllImport("user32", SetLastError = true)]
|
[DllImport("user32", SetLastError = true)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool IsWindowVisible(IntPtr hWnd);
|
public static extern bool IsWindowVisible(IntPtr hWnd);
|
||||||
|
@ -125,7 +139,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
[DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")]
|
[DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")]
|
||||||
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags);
|
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags);
|
||||||
[DllImport("user32", SetLastError = true)]
|
[DllImport("user32", SetLastError = true)]
|
||||||
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
|
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, MonitorFrom dwFlags);
|
||||||
[DllImport("user32", SetLastError = true)]
|
[DllImport("user32", SetLastError = true)]
|
||||||
public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags);
|
public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags);
|
||||||
[DllImport("user32", SetLastError = true)]
|
[DllImport("user32", SetLastError = true)]
|
||||||
|
@ -224,8 +238,18 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
[DllImport("user32", SetLastError = true)]
|
[DllImport("user32", SetLastError = true)]
|
||||||
public static extern bool CloseDesktop(IntPtr hDesktop);
|
public static extern bool CloseDesktop(IntPtr hDesktop);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area.
|
||||||
|
/// GetWindowDC assigns default attributes to the window device context each time it retrieves the device context.Previous attributes are lost.
|
||||||
|
/// See <a href="https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowdc">GetWindowDC function</a>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd">A handle to the window whose DC is to be retrieved. If this value is NULL, GetWindowDC retrieves the DC for the entire screen.</param>
|
||||||
|
/// <returns>If the function succeeds, the return value is a handle to a device context for the specified window.</returns>
|
||||||
|
[DllImport("user32", SetLastError = true)]
|
||||||
|
public static extern IntPtr GetWindowDC(IntPtr hWnd);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
|
/// <summary>
|
||||||
/// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7.
|
/// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Point with cursor location, relative to the origin of the monitor setup
|
/// <returns>Point with cursor location, relative to the origin of the monitor setup
|
||||||
|
@ -407,6 +431,21 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd">IntPtr</param>
|
||||||
|
/// <returns>SafeWindowDcHandle</returns>
|
||||||
|
public static SafeWindowDcHandle FromWindow(IntPtr hWnd)
|
||||||
|
{
|
||||||
|
if (hWnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var hDcDesktop = GetWindowDC(hWnd);
|
||||||
|
return new SafeWindowDcHandle(hWnd, hDcDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
public static SafeWindowDcHandle FromDesktop() {
|
public static SafeWindowDcHandle FromDesktop() {
|
||||||
IntPtr hWndDesktop = User32.GetDesktopWindow();
|
IntPtr hWndDesktop = User32.GetDesktopWindow();
|
||||||
IntPtr hDCDesktop = GetWindowDC(hWndDesktop);
|
IntPtr hDCDesktop = GetWindowDC(hWndDesktop);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using GreenshotPlugin.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices.WindowsRuntime;
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
|
|
|
@ -17,18 +17,19 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using GreenshotPlugin.Core.Enums;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
|
|
||||||
namespace GreenshotWin10Plugin.Native
|
namespace GreenshotWin10Plugin.Native
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The IDataTransferManagerInterOp is documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/jj542488(v=vs.85).aspx.
|
/// The IDataTransferManagerInterOp is documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/jj542488(v=vs.85).aspx.
|
||||||
/// This interface allows an app to tie the share context to a specific
|
/// This interface allows an app to tie the share context to a specific
|
||||||
/// window using a window handle. Useful for Win32 apps.
|
/// window using a window handle. Useful for Win32 apps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ComImport, Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")]
|
[ComImport, Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")]
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
public interface IDataTransferManagerInterOp
|
public interface IDataTransferManagerInterOp
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace GreenshotWin10Plugin
|
||||||
/// <returns>IEnumerable with the destinations</returns>
|
/// <returns>IEnumerable with the destinations</returns>
|
||||||
public IEnumerable<IDestination> Destinations()
|
public IEnumerable<IDestination> Destinations()
|
||||||
{
|
{
|
||||||
if (!Environment.OSVersion.IsWindows10OrLater())
|
if (!WindowsVersion.IsWindows10OrLater)
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue