Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Cleanup HWND related interop #1508

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions src/Common/src/DpiHelper.DpiAwarenessContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using static Interop;

namespace System.Windows.Forms
{
/// <summary>
Expand All @@ -16,7 +18,7 @@ internal static partial class DpiHelper
/// <param name="awareness">The new DPI awareness for the current thread</param>
/// <returns>An object that, when disposed, will reset the current thread's
/// DPI awareness to the value it had when the object was created.</returns>
public static IDisposable EnterDpiAwarenessScope(DpiAwarenessContext awareness)
public static IDisposable EnterDpiAwarenessScope(User32.DpiAwarenessContext awareness)
{
return new DpiAwarenessScope(awareness);
}
Expand All @@ -30,38 +32,36 @@ public static IDisposable EnterDpiAwarenessScope(DpiAwarenessContext awareness)
/// <returns> returns object created in system aware mode</returns>
public static T CreateInstanceInSystemAwareContext<T>(Func<T> createInstance)
{
using (EnterDpiAwarenessScope(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
using (EnterDpiAwarenessScope(User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
{
return createInstance();
}
}

#region Scoping DpiAwareness context helper class

/// <summary>
/// Class that help setting Dpi awareness context scope
/// </summary>
private class DpiAwarenessScope : IDisposable
{
private bool dpiAwarenessScopeIsSet = false;
private readonly DpiAwarenessContext originalAwareness = DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
private readonly User32.DpiAwarenessContext originalAwareness = User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;

/// <summary>
/// Enters given Dpi awareness scope
/// </summary>
public DpiAwarenessScope(DpiAwarenessContext awareness)
public DpiAwarenessScope(User32.DpiAwarenessContext awareness)
{
try
{
if (!CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(awareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED))
if (!User32.DpiAwarenessContextsEquals(awareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED))
{
originalAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
originalAwareness = User32.GetCurrentThreadDpiAwarenessContext();

// If current process dpiawareness is SYSTEM_UNAWARE or SYSTEM_AWARE (must be equal to awareness), calling this method will be a no-op.
if (!CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(originalAwareness, awareness) &&
!CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(originalAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
if (!User32.DpiAwarenessContextsEquals(originalAwareness, awareness) &&
!User32.DpiAwarenessContextsEquals(originalAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
{
originalAwareness = CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext(awareness);
originalAwareness = User32.SetCurrentThreadDpiAwarenessContext(awareness);
dpiAwarenessScopeIsSet = true;
}
}
Expand All @@ -75,10 +75,7 @@ public DpiAwarenessScope(DpiAwarenessContext awareness)
/// <summary>
/// Dispose object and resources
/// </summary>
public void Dispose()
{
ResetDpiAwarenessContextChanges();
}
public void Dispose() => ResetDpiAwarenessContextChanges();

/// <summary>
/// resetting dpiawareness of the thread.
Expand All @@ -87,11 +84,10 @@ private void ResetDpiAwarenessContextChanges()
{
if (dpiAwarenessScopeIsSet)
{
CommonUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(originalAwareness);
User32.SetCurrentThreadDpiAwarenessContext(originalAwareness);
dpiAwarenessScopeIsSet = false;
}
}
}
#endregion
}
}
29 changes: 10 additions & 19 deletions src/Common/src/DpiHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Runtime.InteropServices;

using CAPS = System.Windows.Forms.NativeMethods;
using static Interop;

namespace System.Windows.Forms
{
Expand Down Expand Up @@ -55,7 +56,7 @@ internal static void InitializeDpiHelperForWinforms()
if (OsVersion.IsWindows10_1607OrGreater)
{
// We are on Windows 10/1603 or greater, but we could still be DpiUnaware or SystemAware, so let's find that out...
var currentProcessId = SafeNativeMethods.GetCurrentProcessId();
int currentProcessId = Kernel32.GetCurrentProcessId();
IntPtr hProcess = SafeNativeMethods.OpenProcess(SafeNativeMethods.PROCESS_QUERY_INFORMATION, false, currentProcessId);
SafeNativeMethods.GetProcessDpiAwareness(hProcess, out CAPS.PROCESS_DPI_AWARENESS processDpiAwareness);

Expand Down Expand Up @@ -90,8 +91,8 @@ internal static bool IsPerMonitorV2Awareness
{
// We can't cache this value because different top level windows can have different DPI awareness context
// for mixed mode applications.
DpiAwarenessContext dpiAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
return CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
User32.DpiAwarenessContext dpiAwareness = User32.GetCurrentThreadDpiAwarenessContext();
return User32.DpiAwarenessContextsEquals(dpiAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
else
{
Expand Down Expand Up @@ -319,29 +320,29 @@ internal static HighDpiMode GetWinformsApplicationDpiAwareness()
// For Windows 10 RS2 and above
if (OsVersion.IsWindows10_1607OrGreater)
{
DpiAwarenessContext dpiAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
User32.DpiAwarenessContext dpiAwareness = User32.GetCurrentThreadDpiAwarenessContext();

if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
if (User32.DpiAwarenessContextsEquals(dpiAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
{
return HighDpiMode.SystemAware;
}

if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
if (User32.DpiAwarenessContextsEquals(dpiAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
{
return HighDpiMode.DpiUnaware;
}

if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
if (User32.DpiAwarenessContextsEquals(dpiAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
{
return HighDpiMode.PerMonitorV2;
}

if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
if (User32.DpiAwarenessContextsEquals(dpiAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
{
return HighDpiMode.PerMonitor;
}

if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
if (User32.DpiAwarenessContextsEquals(dpiAwareness, User32.DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
{
return HighDpiMode.DpiUnawareGdiScaled;
}
Expand Down Expand Up @@ -459,14 +460,4 @@ internal static bool SetWinformsApplicationDpiAwareness(HighDpiMode highDpiMode)
return false;
}
}

internal enum DpiAwarenessContext
{
DPI_AWARENESS_CONTEXT_UNSPECIFIED = 0,
DPI_AWARENESS_CONTEXT_UNAWARE = -1,
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = -3,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = -4,
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = -5
}
}
22 changes: 22 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.CloseHandle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern bool CloseHandle(IntPtr handle);

public static bool CloseHandle(HandleRef handle)
{
bool result = CloseHandle(handle.Handle);
GC.KeepAlive(handle.Wrapper);
return result;
}
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetCurrentProcess.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern IntPtr GetCurrentProcess();
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetCurrentProcessId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern int GetCurrentProcessId();
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetCurrentThread.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern IntPtr GetCurrentThread();
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetCurrentThreadId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern int GetCurrentThreadId();
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetExitCodeThread.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern bool GetExitCodeThread(IntPtr hWnd, out uint lpdwExitCode);
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetThreadLocale.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern int GetThreadLocale();
}
}
14 changes: 14 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.GetTickCount.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public static extern int GetTickCount();
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Kernel32/Interop.SetThreadLocale.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, ExactSpelling = true)]
public extern static bool SetThreadLocale(int Locale);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

internal static partial class Interop
{
public static partial class Shell32
internal static partial class Shell32
{
[DllImport(Libraries.Shell32, ExactSpelling = true)]
public static extern CoTaskMemSafeHandle SHBrowseForFolderW(ref BROWSEINFO lpbi);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

internal static partial class Interop
{
public static partial class Shell32
internal static partial class Shell32
{
[DllImport(Libraries.Shell32, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
public static extern int SHGetKnownFolderPath(ref Guid rfid, uint dwFlags, IntPtr hToken, out string pszPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

internal static partial class Interop
{
public static partial class Shell32
internal static partial class Shell32
{
[DllImport(ExternDll.Shell32, EntryPoint = "SHGetPathFromIDListEx", ExactSpelling = true)]
[DllImport(Libraries.Shell32, ExactSpelling = true)]
private static extern bool SHGetPathFromIDListEx(IntPtr pidl, IntPtr pszPath, int cchPath, int flags);

public static bool SHGetPathFromIDListLongPath(IntPtr pidl, out string path)
{
IntPtr pszPath = Marshal.AllocHGlobal((Interop.Kernel32.MAX_PATH + 1) * sizeof(char));
int length = Interop.Kernel32.MAX_PATH;
IntPtr pszPath = Marshal.AllocHGlobal((Kernel32.MAX_PATH + 1) * sizeof(char));
int length = Kernel32.MAX_PATH;
try
{
if (!SHGetPathFromIDListLongPath(pidl, ref pszPath, length))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

internal static partial class Interop
{
public static partial class Shell32
internal static partial class Shell32
{
[DllImport(Libraries.Shell32, ExactSpelling = true)]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out CoTaskMemSafeHandle ppidl);
Expand Down
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Shell32/Interop.ShellExecute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Shell32
{
[DllImport(Libraries.Shell32, ExactSpelling = true, CharSet = CharSet.Ansi, BestFitMapping = false)]
public static extern IntPtr ShellExecuteA(HandleRef hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, User32.ShowWindowCommand nShowCmd);
}
}
Loading