diff --git a/src/Microsoft.DotNet.Wpf/src/Common/Graphics/wgx_render.cs b/src/Microsoft.DotNet.Wpf/src/Common/Graphics/wgx_render.cs index 9728b803884..632ea310fbe 100644 --- a/src/Microsoft.DotNet.Wpf/src/Common/Graphics/wgx_render.cs +++ b/src/Microsoft.DotNet.Wpf/src/Common/Graphics/wgx_render.cs @@ -721,13 +721,7 @@ internal struct BitmapTransformCaps // TRUE if the effect supports multi-resolution [MarshalAs(UnmanagedType.Bool)] bool fSupportMultiResolution; -}; - - [StructLayout(LayoutKind.Sequential)] - internal struct HWND - { - public int hwnd; - } + }; [StructLayout(LayoutKind.Sequential)] internal struct MILAVInstruction diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs index 647fafee77f..67c6724ecf8 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs @@ -234,18 +234,23 @@ private void Initialize(HwndSourceParameters parameters) // list. If this is done the other way around, first HwndTarget resize will // force re-render, then layout will be updated according to the new size, // scheduling another render. - HwndWrapperHook[] wrapperHooks = { _hwndTargetHook, _layoutHook, _inputHook, null }; - if (null != parameters.HwndSourceHook) + ReadOnlySpan wrapperHooks = [_hwndTargetHook, _layoutHook, _inputHook, _publicHook]; + + if (parameters.HwndSourceHook is not null) { // In case there's more than one delegate, add these to the event storage backwards // so they'll get invoked in the expected order. Delegate[] handlers = parameters.HwndSourceHook.GetInvocationList(); - for (int i = handlers.Length -1; i >= 0; --i) + for (int i = handlers.Length - 1; i >= 0; --i) { EventHelper.AddHandler(ref _hooks, (HwndSourceHook)handlers[i]); } - wrapperHooks[3] = _publicHook; + } + else + { + // In this case, we do not need the _publicHook + wrapperHooks = wrapperHooks.Slice(0, 3); } _restoreFocusMode = parameters.RestoreFocusMode; @@ -260,27 +265,19 @@ private void Initialize(HwndSourceParameters parameters) parameters.ExtendedWindowStyle &= (~NativeMethods.WS_EX_LAYERED); } - _constructionParameters = parameters; - _hwndWrapper = new HwndWrapper(parameters.WindowClassStyle, - parameters.WindowStyle, - parameters.ExtendedWindowStyle, - parameters.PositionX, - parameters.PositionY, - parameters.Width, - parameters.Height, - parameters.WindowName, - parameters.ParentWindow, - wrapperHooks); - - _hwndTarget = new HwndTarget(_hwndWrapper.Handle); - _hwndTarget.UsesPerPixelOpacity = parameters.EffectivePerPixelOpacity; - if(_hwndTarget.UsesPerPixelOpacity) + + _hwndWrapper = new HwndWrapper(parameters.WindowClassStyle, parameters.WindowStyle, parameters.ExtendedWindowStyle, + parameters.PositionX, parameters.PositionY, parameters.Width, parameters.Height, + parameters.WindowName, parameters.ParentWindow, wrapperHooks); + + _hwndTarget = new HwndTarget(_hwndWrapper.Handle) { UsesPerPixelOpacity = parameters.EffectivePerPixelOpacity }; + if (_hwndTarget.UsesPerPixelOpacity) { _hwndTarget.BackgroundColor = Colors.Transparent; // Prevent this window from being themed. - UnsafeNativeMethods.CriticalSetWindowTheme(new HandleRef(this, _hwndWrapper.Handle), "", ""); + UnsafeNativeMethods.CriticalSetWindowTheme(new HandleRef(this, _hwndWrapper.Handle), string.Empty, string.Empty); } _constructionParameters = null; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs index 800cb572e61..4db4f80acd4 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs @@ -2567,19 +2567,7 @@ public NotificationWindowHelper() // (HwndWrapper keeps a WeakReference to the hook) _notificationHook = new HwndWrapperHook(NotificationFilterMessage); - HwndWrapperHook[] wrapperHooks = { _notificationHook }; - - _notificationHwnd = new HwndWrapper( - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "", - IntPtr.Zero, - wrapperHooks); + _notificationHwnd = new HwndWrapper(0, 0, 0, 0, 0, 0, 0, string.Empty, IntPtr.Zero, _notificationHook); Guid monitorGuid = new Guid(NativeMethods.GUID_MONITOR_POWER_ON.ToByteArray()); unsafe diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContextNotificationWindow.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContextNotificationWindow.cs index 48734c3f5c9..9a7ec7d401f 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContextNotificationWindow.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/MediaContextNotificationWindow.cs @@ -66,12 +66,9 @@ internal MediaContextNotificationWindow(MediaContext ownerMediaContext) // Create a top-level, invisible window so we can get the WM_DWMCOMPOSITIONCHANGED // and other DWM notifications that are broadcasted to top-level windows only. - HwndWrapper hwndNotification; - hwndNotification = new HwndWrapper(0, NativeMethods.WS_POPUP, 0, 0, 0, 0, 0, "MediaContextNotificationWindow", IntPtr.Zero, null); - _hwndNotificationHook = new HwndWrapperHook(MessageFilter); - _hwndNotification = hwndNotification; + _hwndNotification = new HwndWrapper(0, NativeMethods.WS_POPUP, 0, 0, 0, 0, 0, "MediaContextNotificationWindow", parent: IntPtr.Zero); _hwndNotification.AddHook(_hwndNotificationHook); _isDisposed = false; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs index b458a2139ba..9fd9b4bf5d7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs @@ -100,7 +100,7 @@ public virtual Nullable ShowDialog() // prevent breaking UIAutomation. if (hwndOwner == IntPtr.Zero) { - tempParentHwnd = new HwndWrapper(0, 0, 0, 0, 0, 0, 0, "", IntPtr.Zero, null); + tempParentHwnd = new HwndWrapper(0, 0, 0, 0, 0, 0, 0, string.Empty, IntPtr.Zero); hwndOwner = tempParentHwnd.Handle; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs index 5d22a1791ed..6bab78565bc 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs @@ -2143,19 +2143,7 @@ private void EnsureHwndSource() // (HwndWrapper keeps a WeakReference to the hook) _appFilterHook = new HwndWrapperHook(AppFilterMessage); - HwndWrapperHook[] wrapperHooks = {_appFilterHook}; - - _parkingHwnd = new HwndWrapper( - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "", - IntPtr.Zero, - wrapperHooks); + _parkingHwnd = new HwndWrapper(0, 0, 0, 0, 0, 0, 0, string.Empty, IntPtr.Zero, _appFilterHook); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/SystemResources.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/SystemResources.cs index 0252f614fba..42f12a448dc 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/SystemResources.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/SystemResources.cs @@ -1115,18 +1115,15 @@ private static DpiUtil.HwndDpiInfo CreateResourceChangeListenerWindow(DpiAwarene { // Create a top-level, invisible window so we can get the WM_THEMECHANGE notification // and for HwndHost to park non-visible HwndHosts. - var hwndNotify = - new HwndWrapper( - classStyle: 0, - style: NativeMethods.WS_POPUP | NativeMethods.WS_DISABLED, - exStyle: 0, - x: x, - y: y, - width: 0, - height: 0, - name: "SystemResourceNotifyWindow", - parent: IntPtr.Zero, - hooks: null); + HwndWrapper hwndNotify = new(classStyle: 0, + style: NativeMethods.WS_POPUP | NativeMethods.WS_DISABLED, + exStyle: 0, + x: x, + y: y, + width: 0, + height: 0, + name: "SystemResourceNotifyWindow", + parent: IntPtr.Zero); // Do not call into DpiUtil.GetExtendedDpiInfoForWindow() // unless IsPerMonitorDpiscalingActive == true. DpiUtil.GetExtendedDpiInfoForWindow() diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs index dc4729fca43..f66ae16fed5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs @@ -6377,21 +6377,15 @@ private static void _OnClipToBoundsChanged(DependencyObject d, DependencyPropert /// private HwndWrapper EnsureHiddenWindow() { - if (_hiddenWindow == null) - { - _hiddenWindow = new HwndWrapper( - 0, // classStyle - NativeMethods.WS_OVERLAPPEDWINDOW, // style - 0, // exStyle - NativeMethods.CW_USEDEFAULT, // x - NativeMethods.CW_USEDEFAULT, // y - NativeMethods.CW_USEDEFAULT, // width - NativeMethods.CW_USEDEFAULT, // height - "Hidden Window", // name - IntPtr.Zero, - null - ); - } + _hiddenWindow ??= new HwndWrapper(classStyle: 0, + NativeMethods.WS_OVERLAPPEDWINDOW, // style + exStyle: 0, + NativeMethods.CW_USEDEFAULT, // x + NativeMethods.CW_USEDEFAULT, // y + NativeMethods.CW_USEDEFAULT, // width + NativeMethods.CW_USEDEFAULT, // height + "Hidden Window", // name + IntPtr.Zero); return _hiddenWindow; } diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndSubclass.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndSubclass.cs index 17dac0280e3..3f05e8185be 100644 --- a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndSubclass.cs +++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndSubclass.cs @@ -2,29 +2,13 @@ // 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; -using MS.Internal; -using MS.Internal.Interop; -using MS.Utility; -using System.Windows; using System.Windows.Threading; -using System.Security; // CAS -using System.Threading; // Thread - -// The SecurityHelper class differs between assemblies and could not actually be -// shared, so it is duplicated across namespaces to prevent name collision. -#if WINDOWS_BASE - using MS.Internal.WindowsBase; -#elif PRESENTATION_CORE - using MS.Internal.PresentationCore; -#elif PRESENTATIONFRAMEWORK - using MS.Internal.PresentationFramework; -#elif DRT - using MS.Internal.Drt; -#else -#error Attempt to use a class (duplicated across multiple namespaces) from an unknown assembly. -#endif +using MS.Internal.Interop; +using System.Threading; +using System; + +using SR = MS.Internal.WindowsBase.SR; namespace MS.Win32 { @@ -49,7 +33,6 @@ namespace MS.Win32 /// is not thread safe and will be operated on by the thread that owns /// the window. /// - /// Not available to partial trust callers internal class HwndSubclass : IDisposable { static HwndSubclass() diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapper.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapper.cs index 4e38ac3c245..0e2d40ca867 100644 --- a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapper.cs +++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapper.cs @@ -2,31 +2,12 @@ // 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.Security; -using System.Collections.Generic; -using System.Threading; -using System.Windows.Threading; using System.Runtime.InteropServices; -using System.Diagnostics; -using MS.Internal; +using System.Windows.Threading; using MS.Internal.Interop; -using System.Globalization; // CultureInfo.InvariantCulture - -#if WINDOWS_BASE - using MS.Internal.WindowsBase; -#elif PRESENTATION_CORE - using MS.Internal.PresentationCore; -#elif PRESENTATIONFRAMEWORK - using MS.Internal.PresentationFramework; -#elif DRT - using MS.Internal.Drt; -#else -using MS.Internal.YourAssemblyName; -#endif - -// Disable pragma warnings to enable PREsharp pragmas -#pragma warning disable 1634, 1691 +using System.Threading; +using MS.Internal; +using System; namespace MS.Win32 { @@ -37,33 +18,18 @@ static HwndWrapper() s_msgGCMemory = UnsafeNativeMethods.RegisterWindowMessage("HwndWrapper.GetGCMemMessage"); } - public HwndWrapper( - int classStyle, - int style, - int exStyle, - int x, - int y, - int width, - int height, - string name, - IntPtr parent, - HwndWrapperHook[] hooks) + public HwndWrapper(int classStyle, int style, int exStyle, int x, int y, int width, int height, + string name, IntPtr parent, params ReadOnlySpan hooks) { _ownerThreadID = Environment.CurrentManagedThreadId; - - // First, add the set of hooks. This allows the hooks to receive the + // First, add the set of hooks. This allows the hooks to receive the // messages sent to the window very early in the process. - if(hooks != null) + foreach (HwndWrapperHook hook in hooks) { - for(int i = 0, iEnd = hooks.Length; i < iEnd; i++) - { - if(null != hooks[i]) - AddHook(hooks[i]); - } + AddHook(hook); } - _wndProc = new HwndWrapperHook(WndProc); // We create the HwndSubclass object so that we can use its @@ -81,7 +47,7 @@ public HwndWrapper( throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } - IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle( null ); + IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null); // We need to keep the Delegate object alive through the call to CreateWindowEx(). // Subclass.WndProc will install a better delegate (to the same function) when it @@ -92,25 +58,19 @@ public HwndWrapper( // The class name is a concat of AppName, ThreadName, and RandomNumber. // Register will fail if the string gets over 255 in length. // So limit each part to a reasonable amount. - string appName; - string currentDomainFriendlyName = AppDomain.CurrentDomain.FriendlyName; - if (null != currentDomainFriendlyName && 128 <= currentDomainFriendlyName.Length) - appName = currentDomainFriendlyName[..128]; - else - appName = currentDomainFriendlyName; - - string threadName; - if(null != Thread.CurrentThread.Name && 64 <= Thread.CurrentThread.Name.Length) - threadName = Thread.CurrentThread.Name.Substring(0, 64); - else - threadName = Thread.CurrentThread.Name; - - // Create a suitable unique class name. - _classAtom = 0; - string randomName = Guid.NewGuid().ToString(); - string className = String.Format(CultureInfo.InvariantCulture, "HwndWrapper[{0};{1};{2}]", appName, threadName, randomName); + ReadOnlySpan appName = AppDomain.CurrentDomain.FriendlyName; + if (appName.Length > 128) + appName = appName.Slice(0, 128); + + // Get current thread name, constrain at 64 chars max + ReadOnlySpan threadName = Thread.CurrentThread.Name; + if (threadName.Length > 64) + threadName = threadName.Slice(0, 64); - wc_d.cbSize = Marshal.SizeOf(typeof(NativeMethods.WNDCLASSEX_D)); + // Create a suitable unique class name + string className = $"HwndWrapper[{appName};{threadName};{Guid.NewGuid()}]"; + + wc_d.cbSize = Marshal.SizeOf(); wc_d.style = classStyle; wc_d.lpfnWndProc = initialWndProc; wc_d.cbClsExtra = 0; @@ -119,14 +79,13 @@ public HwndWrapper( wc_d.hIcon = IntPtr.Zero; wc_d.hCursor = IntPtr.Zero; wc_d.hbrBackground = hNullBrush; - wc_d.lpszMenuName = ""; + wc_d.lpszMenuName = string.Empty; wc_d.lpszClassName = className; wc_d.hIconSm = IntPtr.Zero; - // Register the unique class for this instance. - // Note we use a GUID in the name so we are confident that - // the class name should be unique. And RegisterClassEx won't - // fail (for that reason). + // Register the unique class for this window instance. + // Note we use a GUID in the name so we are confident that the class name should be unique. + // And RegisterClassEx won't fail (for that reason). _classAtom = UnsafeNativeMethods.RegisterClassEx(wc_d); // call CreateWindow @@ -158,7 +117,6 @@ public HwndWrapper( GC.KeepAlive(initialWndProc); } - ~HwndWrapper() { Dispose(/*disposing = */ false, @@ -184,17 +142,14 @@ private void Dispose(bool disposing, bool isHwndBeingDestroyed) return; } - if(disposing) + if (disposing) { // diposing == false means we're being called from the finalizer // and can't follow any reference types that may themselves be // finalizable - thus don't call the Disposed callback. // Notify listeners that we are being disposed. - if(Disposed != null) - { - Disposed(this, EventArgs.Empty); - } + Disposed?.Invoke(this, EventArgs.Empty); } // We are now considered disposed. @@ -240,13 +195,13 @@ private void Dispose(bool disposing, bool isHwndBeingDestroyed) public void AddHook(HwndWrapperHook hook) { - _hooks ??= []; + _hooks ??= new WeakReferenceList(); _hooks.Insert(0, hook); } internal void AddHookLast(HwndWrapperHook hook) { - _hooks ??= []; + _hooks ??= new WeakReferenceList(); _hooks.Add(hook); } diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapperHook.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapperHook.cs index 5cf212de164..5bec7444d86 100644 --- a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapperHook.cs +++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapperHook.cs @@ -3,19 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Security; - -#if WINDOWS_BASE - using MS.Internal.WindowsBase; -#elif PRESENTATION_CORE - using MS.Internal.PresentationCore; -#elif PRESENTATIONFRAMEWORK - using MS.Internal.PresentationFramework; -#elif DRT - using MS.Internal.Drt; -#else -using MS.Internal.YourAssemblyName; -#endif namespace MS.Win32 { diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/MessageOnlyHwndWrapper.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/MessageOnlyHwndWrapper.cs index 2b2410d3366..a6b174d2147 100644 --- a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/MessageOnlyHwndWrapper.cs +++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/MessageOnlyHwndWrapper.cs @@ -2,19 +2,14 @@ // 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.Threading; -using System.Security ; -using System.Runtime.InteropServices; - namespace MS.Win32 { - // Specialized version of HwndWrapper for message-only windows. - - internal class MessageOnlyHwndWrapper : HwndWrapper + /// + /// Specialized version of for message-only windows. + /// + internal sealed class MessageOnlyHwndWrapper : HwndWrapper { - public MessageOnlyHwndWrapper() : base(0, 0, 0, 0, 0, 0, 0, "", NativeMethods.HWND_MESSAGE, null) - { - } + public MessageOnlyHwndWrapper() : base(0, 0, 0, 0, 0, 0, 0, string.Empty, NativeMethods.HWND_MESSAGE) { } + } }