From e6e884bf1d009d0fde7caf7a2a77c773cbbdc17a Mon Sep 17 00:00:00 2001 From: GH Cao Date: Sun, 11 Aug 2024 21:01:16 +0800 Subject: [PATCH 1/3] .NET 8 support --- .../Interop/ICoreWindowInterop.cs | 15 ++++++++---- .../IDesktopWindowXamlSourceNative2.cs | 12 ++++++++-- .../Interop/IInitializeWithWindow.cs | 11 +++++++-- Mile.Xaml.Managed/Interop/IWindowPrivate.cs | 17 ++++++++++--- .../Interop/InteropExtensions.cs | 15 ++++++++++++ .../Interop/UnsafeNativeMethods.cs | 10 ++++++++ Mile.Xaml.Managed/Mile.Xaml.Managed.csproj | 16 +++++++++++-- .../WindowsXamlHostBase.WndProc.cs | 11 ++++++--- Mile.Xaml.Managed/WindowsXamlHostBase.cs | 2 +- .../XamlApplicationExtensions.cs | 24 ++++++++++++++++--- Mile.Xaml.sln | 7 ++++++ Mile.Xaml/Mile.Xaml.nuspec | 8 +++++++ Mile.Xaml/NuGet/net8.0/Mile.Xaml.props | 16 +++++++++++++ Mile.Xaml/NuGet/net8.0/Mile.Xaml.targets | 21 ++++++++++++++++ 14 files changed, 165 insertions(+), 20 deletions(-) create mode 100644 Mile.Xaml/NuGet/net8.0/Mile.Xaml.props create mode 100644 Mile.Xaml/NuGet/net8.0/Mile.Xaml.targets diff --git a/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs b/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs index 7ff8e2f..2cc3b8d 100644 --- a/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs +++ b/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs @@ -10,15 +10,22 @@ using System; using System.Runtime.InteropServices; +#if NET8_0_OR_GREATER +using System.Runtime.InteropServices.Marshalling; +#endif namespace Mile.Xaml.Interop { +#if NET8_0_OR_GREATER + [GeneratedComInterface] +#else [ComImport] - [Guid("45D64A29-A63E-4CB6-B498-5781D298CB4F")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ICoreWindowInterop +#endif + [Guid("45D64A29-A63E-4CB6-B498-5781D298CB4F")] + public partial interface ICoreWindowInterop { - IntPtr WindowHandle { get; } - bool MessageHandled { set; } + IntPtr GetWindowHandle(); + void SetMessageHandled([MarshalAs(UnmanagedType.I1)]bool messageHandled); } } diff --git a/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs b/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs index 0a962b7..a01610a 100644 --- a/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs +++ b/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs @@ -10,18 +10,26 @@ using System; using System.Runtime.InteropServices; +#if NET8_0_OR_GREATER +using System.Runtime.InteropServices.Marshalling; +#endif namespace Mile.Xaml.Interop { +#if NET8_0_OR_GREATER + [GeneratedComInterface] +#else [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif [Guid("e3dcd8c7-3057-4692-99c3-7b7720afda31")] - public interface IDesktopWindowXamlSourceNative2 + public partial interface IDesktopWindowXamlSourceNative2 { void AttachToWindow(IntPtr parentWnd); - IntPtr WindowHandle { get; } + IntPtr GetWindowHandle(); + [return:MarshalAs(UnmanagedType.I1)] bool PreTranslateMessage(ref System.Windows.Forms.Message message); } } diff --git a/Mile.Xaml.Managed/Interop/IInitializeWithWindow.cs b/Mile.Xaml.Managed/Interop/IInitializeWithWindow.cs index 2250d7d..f974659 100644 --- a/Mile.Xaml.Managed/Interop/IInitializeWithWindow.cs +++ b/Mile.Xaml.Managed/Interop/IInitializeWithWindow.cs @@ -10,13 +10,20 @@ using System; using System.Runtime.InteropServices; +#if NET8_0_OR_GREATER +using System.Runtime.InteropServices.Marshalling; +#endif namespace Mile.Xaml.Interop { +#if NET8_0_OR_GREATER + [GeneratedComInterface] +#else [ComImport] - [Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IInitializeWithWindow +#endif + [Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")] + public partial interface IInitializeWithWindow { void Initialize(IntPtr hwnd); } diff --git a/Mile.Xaml.Managed/Interop/IWindowPrivate.cs b/Mile.Xaml.Managed/Interop/IWindowPrivate.cs index 768dd2e..34a3ee9 100644 --- a/Mile.Xaml.Managed/Interop/IWindowPrivate.cs +++ b/Mile.Xaml.Managed/Interop/IWindowPrivate.cs @@ -10,14 +10,25 @@ using System; using System.Runtime.InteropServices; +#if NET8_0_OR_GREATER +using System.Runtime.InteropServices.Marshalling; +#endif namespace Mile.Xaml.Interop { +#if NET8_0_OR_GREATER + [GeneratedComInterface] +#else [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif [Guid("06636C29-5A17-458D-8EA2-2422D997A922")] - [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)] - public interface IWindowPrivate + public partial interface IWindowPrivate { - bool TransparentBackground { get; set; } + void GetIids(out int iidCount, out IntPtr iids); + void GetRuntimeClassName(out IntPtr className); + void GetTrustLevel(out int trustLevel); + [return: MarshalAs(UnmanagedType.I1)] bool GetTransparentBackground(); + void SetTransparentBackground([MarshalAs(UnmanagedType.I1)] bool transparentBackground); } } diff --git a/Mile.Xaml.Managed/Interop/InteropExtensions.cs b/Mile.Xaml.Managed/Interop/InteropExtensions.cs index c00c4f8..1dc36e9 100644 --- a/Mile.Xaml.Managed/Interop/InteropExtensions.cs +++ b/Mile.Xaml.Managed/Interop/InteropExtensions.cs @@ -21,6 +21,10 @@ public static class InteropExtensions public static IDesktopWindowXamlSourceNative2 GetInterop( this DesktopWindowXamlSource BaseObject) { +#if NET8_0_OR_GREATER + IDesktopWindowXamlSourceNative2 InteropObject = (IDesktopWindowXamlSourceNative2)(object)BaseObject; + return InteropObject; +#else IntPtr BaseObjectIntPtr = Marshal.GetIUnknownForObject(BaseObject); try { @@ -33,11 +37,16 @@ public static IDesktopWindowXamlSourceNative2 GetInterop( { Marshal.Release(BaseObjectIntPtr); } +#endif } public static ICoreWindowInterop GetInterop( this CoreWindow BaseObject) { +#if NET8_0_OR_GREATER + ICoreWindowInterop InteropObject = (ICoreWindowInterop)(object)BaseObject; + return InteropObject; +#else IntPtr BaseObjectIntPtr = Marshal.GetIUnknownForObject(BaseObject); try { @@ -50,10 +59,15 @@ public static ICoreWindowInterop GetInterop( { Marshal.Release(BaseObjectIntPtr); } +#endif } public static IWindowPrivate GetInterop(this Window BaseObject) { +#if NET8_0_OR_GREATER + IWindowPrivate InteropObject = (IWindowPrivate)(object)BaseObject; + return InteropObject; +#else IntPtr BaseObjectIntPtr = Marshal.GetIUnknownForObject(BaseObject); try { @@ -66,6 +80,7 @@ public static IWindowPrivate GetInterop(this Window BaseObject) { Marshal.Release(BaseObjectIntPtr); } +#endif } } } diff --git a/Mile.Xaml.Managed/Interop/UnsafeNativeMethods.cs b/Mile.Xaml.Managed/Interop/UnsafeNativeMethods.cs index e62a51d..efcd70f 100644 --- a/Mile.Xaml.Managed/Interop/UnsafeNativeMethods.cs +++ b/Mile.Xaml.Managed/Interop/UnsafeNativeMethods.cs @@ -19,8 +19,13 @@ internal static partial class UnsafeNativeMethods /// SecurityCritical: This code happens to return a critical resource and causes unmanaged code elevation /// /// handle +#if NET8_0_OR_GREATER + [LibraryImport(ExternDll.User32, SetLastError = true, EntryPoint = "SetFocus")] + internal static partial IntPtr IntSetFocus(IntPtr hWnd); +#else [DllImport(ExternDll.User32, EntryPoint = "SetFocus", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)] internal static extern IntPtr IntSetFocus(IntPtr hWnd); +#endif /// /// Changes an attribute of the specified window. The function also sets the 32-bit (long) value at the specified offset into the extra window memory. @@ -29,7 +34,12 @@ internal static partial class UnsafeNativeMethods /// Zero-based offset /// The replacement value /// A positive integer indicates success; zero indicates failure +#if NET8_0_OR_GREATER + [LibraryImport(ExternDll.User32, SetLastError = true, EntryPoint = "SetWindowLongW", StringMarshalling = StringMarshalling.Utf16)] + internal static partial int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong); +#else [DllImport(ExternDll.User32, SetLastError = true)] internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong); +#endif } } diff --git a/Mile.Xaml.Managed/Mile.Xaml.Managed.csproj b/Mile.Xaml.Managed/Mile.Xaml.Managed.csproj index 797002b..4b73c2c 100644 --- a/Mile.Xaml.Managed/Mile.Xaml.Managed.csproj +++ b/Mile.Xaml.Managed/Mile.Xaml.Managed.csproj @@ -1,7 +1,7 @@  - net48 + net48;net8.0-windows 10.0.22621.0 10.0.19041.0 latest @@ -11,9 +11,21 @@ © Project Mile. All rights reserved. 2.2.$([System.DateTime]::Today.Subtract($([System.DateTime]::Parse('2021-09-12'))).TotalDays).0 true + true + disable - + + Windows + true + $([System.Version]::Parse('$(TargetPlatformMinVersion)').ToString(3)).39 + + + + + + + diff --git a/Mile.Xaml.Managed/WindowsXamlHostBase.WndProc.cs b/Mile.Xaml.Managed/WindowsXamlHostBase.WndProc.cs index f4e22ab..4eb901f 100644 --- a/Mile.Xaml.Managed/WindowsXamlHostBase.WndProc.cs +++ b/Mile.Xaml.Managed/WindowsXamlHostBase.WndProc.cs @@ -64,8 +64,13 @@ protected override void OnPaintBackground(PaintEventArgs pevent) // Do not draw the background } +#if NET8_0_OR_GREATER + [LibraryImport("user32.dll", EntryPoint = "SendMessageW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + internal static partial IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); +#else [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); +#endif /// /// Processes Windows messages for XamlContentHost control window (not XAML window) @@ -88,7 +93,7 @@ protected override void WndProc(ref Message m) SetDesktopWindowXamlSourceWindowPos(); IntPtr CoreWindowHandle = - CoreWindow.GetForCurrentThread().GetInterop().WindowHandle; + CoreWindow.GetForCurrentThread().GetInterop().GetWindowHandle(); Message CurrentMessage = m; // Use Delay execution for improving the resizing for ContentDialogs. @@ -133,7 +138,7 @@ protected override void WndProc(ref Message m) case NativeDefines.WM_KILLFOCUS: // If focus is being set on the UWP XAML island window then we should prevent LostFocus by // handling this message. - if (_xamlIslandWindowHandle == null || _xamlIslandWindowHandle != m.WParam || _xamlSource.HasFocus) + if (_xamlIslandWindowHandle != IntPtr.Zero || _xamlIslandWindowHandle != m.WParam || _xamlSource.HasFocus) { base.WndProc(ref m); } @@ -141,7 +146,7 @@ protected override void WndProc(ref Message m) break; case NativeDefines.WM_DPICHANGED_AFTERPARENT: - if (_xamlIslandWindowHandle != null) + if (_xamlIslandWindowHandle != IntPtr.Zero) { UpdateDpiScalingFactor(); PerformLayout(); diff --git a/Mile.Xaml.Managed/WindowsXamlHostBase.cs b/Mile.Xaml.Managed/WindowsXamlHostBase.cs index 8be4c79..55db0dd 100644 --- a/Mile.Xaml.Managed/WindowsXamlHostBase.cs +++ b/Mile.Xaml.Managed/WindowsXamlHostBase.cs @@ -226,7 +226,7 @@ protected override void OnHandleCreated(EventArgs e) // Attach window to DesktopWindowXamSource as a render target var XamlSourceNative = _xamlSource.GetInterop(); XamlSourceNative.AttachToWindow(Handle); - _xamlIslandWindowHandle = XamlSourceNative.WindowHandle; + _xamlIslandWindowHandle = XamlSourceNative.GetWindowHandle(); // Set window style required by container control to support Focus and background refresh if (Interop.UnsafeNativeMethods.SetWindowLong(Handle, Interop.NativeDefines.GWL_EXSTYLE, Interop.NativeDefines.WS_EX_CONTROLPARENT | Interop.NativeDefines.WS_EX_LAYERED) == 0) diff --git a/Mile.Xaml.Managed/XamlApplicationExtensions.cs b/Mile.Xaml.Managed/XamlApplicationExtensions.cs index 78591ff..7bffe62 100644 --- a/Mile.Xaml.Managed/XamlApplicationExtensions.cs +++ b/Mile.Xaml.Managed/XamlApplicationExtensions.cs @@ -16,12 +16,22 @@ namespace Mile.Xaml { - public static class XamlApplicationExtensions + public static partial class XamlApplicationExtensions { private const uint PM_NOREMOVE = 0x0000; private const uint PM_REMOVE = 0x0001; private const uint PM_NOYIELD = 0x0002; +#if NET8_0_OR_GREATER + [LibraryImport("user32.dll", EntryPoint = "PeekMessageW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool PeekMessage( + out System.Windows.Forms.Message lpMsg, + IntPtr hWnd, + uint wMsgFilterMin, + uint wMsgFilterMax, + uint wRemoveMsg); +#else [DllImport("user32.dll", CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool PeekMessage( @@ -30,10 +40,18 @@ private static extern bool PeekMessage( uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); +#endif +#if NET8_0_OR_GREATER + [LibraryImport("user32.dll", EntryPoint = "DispatchMessageW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + private static partial IntPtr DispatchMessage( + ref System.Windows.Forms.Message lpMsg); +#else [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr DispatchMessage( ref System.Windows.Forms.Message lpMsg); +#endif + [ThreadStatic] private static WindowsXamlManager XamlManager = null; @@ -84,14 +102,14 @@ public static void ThreadUninitialize( public static bool GetTransparentBackgroundAttribute( this Application BaseObject) { - return Window.Current.GetInterop().TransparentBackground; + return Window.Current.GetInterop().GetTransparentBackground(); } public static void SetTransparentBackgroundAttribute( this Application BaseObject, bool AttributeValue) { - Window.Current.GetInterop().TransparentBackground = AttributeValue; + Window.Current.GetInterop().SetTransparentBackground(AttributeValue); } } } diff --git a/Mile.Xaml.sln b/Mile.Xaml.sln index f9c88e1..955fbc7 100644 --- a/Mile.Xaml.sln +++ b/Mile.Xaml.sln @@ -34,6 +34,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net48", "net48", "{14C8B3F2 Mile.Xaml\NuGet\net48\Mile.Xaml.targets = Mile.Xaml\NuGet\net48\Mile.Xaml.targets EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net8.0", "net8.0", "{2B753308-E55A-491B-B2FE-3CC4422864D6}" + ProjectSection(SolutionItems) = preProject + Mile.Xaml\NuGet\net8.0\Mile.Xaml.props = Mile.Xaml\NuGet\net8.0\Mile.Xaml.props + Mile.Xaml\NuGet\net8.0\Mile.Xaml.targets = Mile.Xaml\NuGet\net8.0\Mile.Xaml.targets + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -80,6 +86,7 @@ Global {EB76F0B3-3CE0-4517-8BF2-367C53D745AA} = {931D228C-8E9D-47E5-A535-3F356CA96E78} {1A7C0865-004B-454E-9AB7-35D593AFAF25} = {EB76F0B3-3CE0-4517-8BF2-367C53D745AA} {14C8B3F2-E47B-49F5-9EA3-EB207CBECFCC} = {EB76F0B3-3CE0-4517-8BF2-367C53D745AA} + {2B753308-E55A-491B-B2FE-3CC4422864D6} = {EB76F0B3-3CE0-4517-8BF2-367C53D745AA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7988428E-156C-4D84-8DEE-989B06041193} diff --git a/Mile.Xaml/Mile.Xaml.nuspec b/Mile.Xaml/Mile.Xaml.nuspec index 7544d5e..f5db9ed 100644 --- a/Mile.Xaml/Mile.Xaml.nuspec +++ b/Mile.Xaml/Mile.Xaml.nuspec @@ -25,6 +25,9 @@ + + + @@ -38,6 +41,8 @@ + + @@ -49,6 +54,9 @@ + + + diff --git a/Mile.Xaml/NuGet/net8.0/Mile.Xaml.props b/Mile.Xaml/NuGet/net8.0/Mile.Xaml.props new file mode 100644 index 0000000..98d588c --- /dev/null +++ b/Mile.Xaml/NuGet/net8.0/Mile.Xaml.props @@ -0,0 +1,16 @@ + + + + + + $(DefineConstants);DISABLE_XAML_GENERATED_MAIN + + diff --git a/Mile.Xaml/NuGet/net8.0/Mile.Xaml.targets b/Mile.Xaml/NuGet/net8.0/Mile.Xaml.targets new file mode 100644 index 0000000..44a25ab --- /dev/null +++ b/Mile.Xaml/NuGet/net8.0/Mile.Xaml.targets @@ -0,0 +1,21 @@ + + + + + + + + + + + + + \ No newline at end of file From 4d76b4a099f722ed349d1aa6e3b41deea569cf4e Mon Sep 17 00:00:00 2001 From: GH Cao Date: Sun, 11 Aug 2024 23:00:05 +0800 Subject: [PATCH 2/3] Add comments about the COM interop interface changes --- Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs | 3 +++ Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs | 1 + Mile.Xaml.Managed/Interop/IWindowPrivate.cs | 3 +++ 3 files changed, 7 insertions(+) diff --git a/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs b/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs index 2cc3b8d..f76dbd9 100644 --- a/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs +++ b/Mile.Xaml.Managed/Interop/ICoreWindowInterop.cs @@ -25,7 +25,10 @@ namespace Mile.Xaml.Interop [Guid("45D64A29-A63E-4CB6-B498-5781D298CB4F")] public partial interface ICoreWindowInterop { + // Original declaration: IntPtr WindowHandle { get; } IntPtr GetWindowHandle(); + + // Original declaration: bool MessageHandled { set; } void SetMessageHandled([MarshalAs(UnmanagedType.I1)]bool messageHandled); } } diff --git a/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs b/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs index a01610a..0d9137e 100644 --- a/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs +++ b/Mile.Xaml.Managed/Interop/IDesktopWindowXamlSourceNative2.cs @@ -27,6 +27,7 @@ public partial interface IDesktopWindowXamlSourceNative2 { void AttachToWindow(IntPtr parentWnd); + // Original declaration: IntPtr WindowHandle { get; } IntPtr GetWindowHandle(); [return:MarshalAs(UnmanagedType.I1)] diff --git a/Mile.Xaml.Managed/Interop/IWindowPrivate.cs b/Mile.Xaml.Managed/Interop/IWindowPrivate.cs index 34a3ee9..21a3a7c 100644 --- a/Mile.Xaml.Managed/Interop/IWindowPrivate.cs +++ b/Mile.Xaml.Managed/Interop/IWindowPrivate.cs @@ -25,9 +25,12 @@ namespace Mile.Xaml.Interop [Guid("06636C29-5A17-458D-8EA2-2422D997A922")] public partial interface IWindowPrivate { + // IInspectable methods void GetIids(out int iidCount, out IntPtr iids); void GetRuntimeClassName(out IntPtr className); void GetTrustLevel(out int trustLevel); + + // Original declaration: bool TransparentBackground { get; set; } [return: MarshalAs(UnmanagedType.I1)] bool GetTransparentBackground(); void SetTransparentBackground([MarshalAs(UnmanagedType.I1)] bool transparentBackground); } From c650f95cc43a198a6d92d039d2b3164c93f39ef0 Mon Sep 17 00:00:00 2001 From: GH Cao Date: Sun, 11 Aug 2024 23:02:47 +0800 Subject: [PATCH 3/3] Update credits in README --- ReadMe.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ReadMe.md b/ReadMe.md index 08067b7..ca39824 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -58,5 +58,6 @@ in your project configuration file. Note: This list sort in alphabetical order. - AndromedaMelody, https://github.com/AndromedaMelody +- driver1998, https://github.com/driver1998 - Kenji Mouri, https://github.com/MouriNaruto - Yifei Gao (高怡飞), https://github.com/Gaoyifei1011