From c4d156a3ca075a3a03fa12481b78fe252ecaa5ee Mon Sep 17 00:00:00 2001 From: Dimitris Trachiotis Date: Thu, 15 Sep 2022 18:42:17 +0300 Subject: [PATCH 1/3] Initial implementation of LibraryImport (.NET 7) --- global.json | 4 +- .../Ookii.Dialogs.Wpf.Sample.csproj | 4 +- src/Ookii.Dialogs.Wpf/NativeMethods.cs | 128 ++++++++++++++---- .../Ookii.Dialogs.Wpf.csproj | 8 +- src/Ookii.Dialogs/Ookii.Dialogs.csproj | 4 +- 5 files changed, 110 insertions(+), 38 deletions(-) diff --git a/global.json b/global.json index cb771af..939e22d 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "allowPrerelease": false, - "version": "6.0.100", + "allowPrerelease": true, + "version": "7.0.*", "rollForward": "latestFeature" } } diff --git a/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj b/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj index 867cb83..6f2e14c 100644 --- a/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj +++ b/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net5.0-windows;netcoreapp3.1;net462 + net7.0-windows;net6.0-windows;net48 WinExe true true @@ -23,6 +23,8 @@ true + 1.0.0.22258 + 1.0.0.22258 diff --git a/src/Ookii.Dialogs.Wpf/NativeMethods.cs b/src/Ookii.Dialogs.Wpf/NativeMethods.cs index 6d88788..21fdb04 100644 --- a/src/Ookii.Dialogs.Wpf/NativeMethods.cs +++ b/src/Ookii.Dialogs.Wpf/NativeMethods.cs @@ -24,7 +24,7 @@ namespace Ookii.Dialogs.Wpf { - static class NativeMethods + static partial class NativeMethods { public const int ErrorFileNotFound = 2; @@ -45,7 +45,19 @@ public static bool IsWindowsXPOrLater } #region LoadLibrary +#if NET7_0_OR_GREATER + [LibraryImport("kernel32", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + public static partial SafeModuleHandle LoadLibraryEx( + string lpFileName, + IntPtr hFile, + LoadLibraryExFlags dwFlags + ); + [LibraryImport("kernel32", SetLastError = true), + ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool FreeLibrary(IntPtr hModule); +#else [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern Ookii.Dialogs.Wpf.SafeModuleHandle LoadLibraryEx( string lpFileName, @@ -57,7 +69,7 @@ LoadLibraryExFlags dwFlags ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool FreeLibrary(IntPtr hModule); - +#endif [Flags] public enum LoadLibraryExFlags : uint { @@ -71,6 +83,23 @@ public enum LoadLibraryExFlags : uint #region Task Dialogs + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist"), DllImport("comctl32.dll", PreserveSig = false)] + public static extern void TaskDialogIndirect([In] ref TASKDIALOGCONFIG pTaskConfig, out int pnButton, out int pnRadioButton, [MarshalAs(UnmanagedType.Bool)] out bool pfVerificationFlagChecked); + +#if NET7_0_OR_GREATER + [LibraryImport("user32.dll")] + public static partial IntPtr GetActiveWindow(); + + [LibraryImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool EnableWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool bEnable); + + [LibraryImport("user32.dll")] + public static partial int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); + + [LibraryImport("kernel32.dll")] + public static partial int GetCurrentThreadId(); +#else [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern IntPtr GetActiveWindow(); @@ -82,9 +111,7 @@ public enum LoadLibraryExFlags : uint [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern int GetCurrentThreadId(); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist"), DllImport("comctl32.dll", PreserveSig = false)] - public static extern void TaskDialogIndirect([In] ref TASKDIALOGCONFIG pTaskConfig, out int pnButton, out int pnRadioButton, [MarshalAs(UnmanagedType.Bool)] out bool pfVerificationFlagChecked); +#endif public delegate uint TaskDialogCallback(IntPtr hwnd, uint uNotification, IntPtr wParam, IntPtr lParam, IntPtr dwRefData); @@ -218,8 +245,13 @@ public struct TASKDIALOGCONFIG public uint cxWidth; } +#if NET7_0_OR_GREATER + [LibraryImport("user32.dll")] + public static partial IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); +#else [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); +#endif #endregion @@ -227,6 +259,17 @@ public struct TASKDIALOGCONFIG [DllImport("Kernel32.dll", SetLastError = true)] public extern static ActivationContextSafeHandle CreateActCtx(ref ACTCTX actctx); +#if NET7_0_OR_GREATER + [LibraryImport("kernel32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + public static partial void ReleaseActCtx(IntPtr hActCtx); + [LibraryImport("Kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool ActivateActCtx(ActivationContextSafeHandle hActCtx, out IntPtr lpCookie); + [LibraryImport("Kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool DeactivateActCtx(uint dwFlags, IntPtr lpCookie); +#else + [DllImport("kernel32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public extern static void ReleaseActCtx(IntPtr hActCtx); [DllImport("Kernel32.dll", SetLastError = true)] @@ -235,6 +278,7 @@ public struct TASKDIALOGCONFIG [DllImport("Kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public extern static bool DeactivateActCtx(uint dwFlags, IntPtr lpCookie); +#endif public const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004; @@ -251,9 +295,9 @@ public struct ACTCTX } - #endregion +#endregion - #region File Operations Definitions +#region File Operations Definitions [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] internal struct COMDLG_FILTERSPEC @@ -336,9 +380,9 @@ internal enum CDCONTROLSTATE CDCS_VISIBLE = 0x00000002 } - #endregion +#endregion - #region KnownFolder Definitions +#region KnownFolder Definitions internal enum FFFP_MODE { @@ -399,9 +443,9 @@ internal struct PROPERTYKEY internal uint pid; } - #endregion +#endregion - #region Shell Parsing Names +#region Shell Parsing Names [DllImport("shell32.dll", CharSet = CharSet.Unicode)] public static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv); @@ -416,9 +460,9 @@ public static Interop.IShellItem CreateItemFromParsingName(string path) return (Interop.IShellItem)item; } - #endregion +#endregion - #region String Resources +#region String Resources [Flags()] public enum FormatMessageFlags @@ -439,9 +483,9 @@ public static extern uint FormatMessage([MarshalAs(UnmanagedType.U4)] FormatMess uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer, uint nSize, string[] Arguments); - #endregion +#endregion - #region Credentials +#region Credentials internal const int CREDUI_MAX_USERNAME_LENGTH = 256 + 1 + 256; internal const int CREDUI_MAX_PASSWORD_LENGTH = 256; @@ -545,17 +589,6 @@ public static extern CredUIReturnCodes CredUIPromptForWindowsCredentials( [MarshalAs(UnmanagedType.Bool)]ref bool pfSave, CredUIWinFlags dwFlags); - [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredReadW", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - extern static internal bool CredRead(string TargetName, CredTypes Type, int Flags, out IntPtr Credential); - - [DllImport("advapi32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - extern static internal void CredFree(IntPtr Buffer); - - [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredDeleteW", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - extern static internal bool CredDelete(string TargetName, CredTypes Type, int Flags); - [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredWriteW", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] extern static internal bool CredWrite(ref CREDENTIAL Credential, int Flags); @@ -568,6 +601,31 @@ public static extern CredUIReturnCodes CredUIPromptForWindowsCredentials( [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CredUnPackAuthenticationBuffer(uint dwFlags, IntPtr pAuthBuffer, uint cbAuthBuffer, StringBuilder pszUserName, ref uint pcchMaxUserName, StringBuilder pszDomainName, ref uint pcchMaxDomainName, StringBuilder pszPassword, ref uint pcchMaxPassword); +#if NET7_0_OR_GREATER + [LibraryImport("advapi32.dll", EntryPoint = "CredReadW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool CredRead(string TargetName, CredTypes Type, int Flags, out IntPtr Credential); + + [LibraryImport("advapi32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static partial void CredFree(IntPtr Buffer); + + [LibraryImport("advapi32.dll", EntryPoint = "CredDeleteW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool CredDelete(string TargetName, CredTypes Type, int Flags); + +#else + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredReadW", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + extern static internal bool CredRead(string TargetName, CredTypes Type, int Flags, out IntPtr Credential); + + [DllImport("advapi32.dll"), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + extern static internal void CredFree(IntPtr Buffer); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "CredDeleteW", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + extern static internal bool CredDelete(string TargetName, CredTypes Type, int Flags); +#endif + // Disable the "Internal field is never assigned to" warning. #pragma warning disable 649 // This type does not own the IntPtr native resource; when CredRead is used, CredFree must be called on the @@ -598,9 +656,9 @@ public struct CREDENTIAL } #pragma warning restore 649 - #endregion +#endregion - #region Downlevel folder browser dialog +#region Downlevel folder browser dialog public enum FolderBrowserDialogMessage { @@ -650,17 +708,27 @@ public struct BROWSEINFO [DllImport("shell32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi); - [DllImport("shell32.dll", SetLastError = true)] - public static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, Environment.SpecialFolder nFolder, ref IntPtr ppidl); [DllImport("shell32.dll", PreserveSig = false)] public static extern IMalloc SHGetMalloc(); [DllImport("shell32.dll", CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath); +#if NET7_0_OR_GREATER + [LibraryImport("shell32.dll", SetLastError = true)] + public static partial int SHGetSpecialFolderLocation(IntPtr hwndOwner, Environment.SpecialFolder nFolder, ref IntPtr ppidl); + + [LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16)] + public static partial IntPtr SendMessage(IntPtr hWnd, FolderBrowserDialogMessage msg, IntPtr wParam, string lParam); + [LibraryImport("user32.dll")] + public static partial IntPtr SendMessage(IntPtr hWnd, FolderBrowserDialogMessage msg, IntPtr wParam, IntPtr lParam); +#else + [DllImport("shell32.dll", SetLastError = true)] + public static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, Environment.SpecialFolder nFolder, ref IntPtr ppidl); [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr SendMessage(IntPtr hWnd, FolderBrowserDialogMessage msg, IntPtr wParam, string lParam); [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, FolderBrowserDialogMessage msg, IntPtr wParam, IntPtr lParam); +#endif #endregion diff --git a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj index 5ae9949..1acee8f 100644 --- a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj +++ b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj @@ -1,13 +1,13 @@ - + - net6.0-windows;net5.0-windows;netcoreapp3.1;net462 + net7.0-windows;net6.0-windows;net48 true true Ookii.Dialogs.Wpf Ookii.Dialogs.Wpf - 3.0.0.0 + 3.0.0.22258 true true true @@ -63,6 +63,8 @@ true + true + 0.0.1.22258 diff --git a/src/Ookii.Dialogs/Ookii.Dialogs.csproj b/src/Ookii.Dialogs/Ookii.Dialogs.csproj index d5cea79..dc701c7 100644 --- a/src/Ookii.Dialogs/Ookii.Dialogs.csproj +++ b/src/Ookii.Dialogs/Ookii.Dialogs.csproj @@ -1,7 +1,7 @@ - + - net6.0-windows;net5.0-windows;netcoreapp3.1;net462 + net7.0-windows;net6.0-windows;net48 true true From c3eed7a3f34de65fd7e7bea79f33d5010e0db4e8 Mon Sep 17 00:00:00 2001 From: Dimitris Trachiotis Date: Fri, 16 Sep 2022 12:32:47 +0300 Subject: [PATCH 2/3] Roll back netfx back to net462. --- sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj | 2 +- src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj | 2 +- src/Ookii.Dialogs/Ookii.Dialogs.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj b/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj index 6f2e14c..6f93f90 100644 --- a/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj +++ b/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj @@ -1,7 +1,7 @@  - net7.0-windows;net6.0-windows;net48 + net7.0-windows;net6.0-windows;net462 WinExe true true diff --git a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj index 1acee8f..93ce706 100644 --- a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj +++ b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj @@ -1,7 +1,7 @@  - net7.0-windows;net6.0-windows;net48 + net7.0-windows;net6.0-windows;net462 true true Ookii.Dialogs.Wpf diff --git a/src/Ookii.Dialogs/Ookii.Dialogs.csproj b/src/Ookii.Dialogs/Ookii.Dialogs.csproj index dc701c7..064f8ac 100644 --- a/src/Ookii.Dialogs/Ookii.Dialogs.csproj +++ b/src/Ookii.Dialogs/Ookii.Dialogs.csproj @@ -1,7 +1,7 @@  - net7.0-windows;net6.0-windows;net48 + net7.0-windows;net6.0-windows;net462 true true From 0c1eeb7944576c56790fe34a6e31c111851301d6 Mon Sep 17 00:00:00 2001 From: Dimitris Trachiotis Date: Fri, 16 Sep 2022 13:08:35 +0300 Subject: [PATCH 3/3] Fix TaskDialog due to bad LibraryImport call. --- .../Ookii.Dialogs.Wpf.Sample.csproj | 4 ++-- src/Ookii.Dialogs.Wpf/NativeMethods.cs | 8 +++----- src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj b/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj index 6f93f90..51f4707 100644 --- a/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj +++ b/sample/Ookii.Dialogs.Wpf.Sample/Ookii.Dialogs.Wpf.Sample.csproj @@ -23,8 +23,8 @@ true - 1.0.0.22258 - 1.0.0.22258 + 1.0.0.22259 + 1.0.0.22259 diff --git a/src/Ookii.Dialogs.Wpf/NativeMethods.cs b/src/Ookii.Dialogs.Wpf/NativeMethods.cs index 21fdb04..4042123 100644 --- a/src/Ookii.Dialogs.Wpf/NativeMethods.cs +++ b/src/Ookii.Dialogs.Wpf/NativeMethods.cs @@ -245,13 +245,11 @@ public struct TASKDIALOGCONFIG public uint cxWidth; } -#if NET7_0_OR_GREATER - [LibraryImport("user32.dll")] - public static partial IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); -#else + //This DllImport doesn't work with LibraryImport. Unless it's re-worked a bit, skip suggestions for it. [DllImport("user32.dll", CharSet = CharSet.Auto)] +#pragma warning disable SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); -#endif +#pragma warning restore SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time #endregion diff --git a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj index 93ce706..e0a38d5 100644 --- a/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj +++ b/src/Ookii.Dialogs.Wpf/Ookii.Dialogs.Wpf.csproj @@ -7,7 +7,7 @@ Ookii.Dialogs.Wpf Ookii.Dialogs.Wpf - 3.0.0.22258 + 3.0.0.22259 true true true @@ -64,7 +64,7 @@ true true - 0.0.1.22258 + 0.0.1.22259