From 61e4e50d3120b6ccac553f233cbdb65d7bce3882 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 6 Sep 2017 13:28:19 +0300 Subject: [PATCH 1/2] Enable win32 file dialog functionality for .NET Standard build --- src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs | 6 ++---- src/Windows/Avalonia.Win32/SystemDialogImpl.cs | 9 +-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 2d739f095d..e7401c19b9 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -841,14 +841,13 @@ namespace Avalonia.Win32.Interop return SetClassLong64(hWnd, nIndex, dwNewLong); } -#if !NETSTANDARD && !NETSTANDARD2_0 + [ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] internal class FileOpenDialogRCW { } [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv); -#endif [DllImport("user32.dll", SetLastError = true)] public static extern bool OpenClipboard(IntPtr hWndOwner); @@ -1183,7 +1182,7 @@ namespace Avalonia.Win32.Interop public int flagsEx; } } -#if !NETSTANDARD && !NETSTANDARD1_3 + [ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IFileDialog { @@ -1283,5 +1282,4 @@ namespace Avalonia.Win32.Interop uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); } -#endif } diff --git a/src/Windows/Avalonia.Win32/SystemDialogImpl.cs b/src/Windows/Avalonia.Win32/SystemDialogImpl.cs index 4d8c375aaf..eef8a4d449 100644 --- a/src/Windows/Avalonia.Win32/SystemDialogImpl.cs +++ b/src/Windows/Avalonia.Win32/SystemDialogImpl.cs @@ -100,17 +100,14 @@ namespace Avalonia.Win32 var pofn = &ofn; // We should save the current directory to restore it later. -#if !NETSTANDARD var currentDirectory = Environment.CurrentDirectory; -#endif + var res = dialog is OpenFileDialog ? UnmanagedMethods.GetOpenFileName(new IntPtr(pofn)) : UnmanagedMethods.GetSaveFileName(new IntPtr(pofn)); // Restore the old current directory, since GetOpenFileName and GetSaveFileName change it after they're called -#if !NETSTANDARD Environment.CurrentDirectory = currentDirectory; -#endif if (!res) return null; @@ -155,9 +152,6 @@ namespace Avalonia.Win32 public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) { -#if NETSTANDARD - throw new NotImplementedException(); -#else return Task.Factory.StartNew(() => { string result = string.Empty; @@ -214,7 +208,6 @@ namespace Avalonia.Win32 return result; }); -#endif } } } From f330132dc3232ebd914a29d095a9a44e9f1f45c5 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 6 Sep 2017 14:40:46 +0300 Subject: [PATCH 2/2] Use CoCreateInstance for .NET Core compatibility --- src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs | 5 +++-- src/Windows/Avalonia.Win32/SystemDialogImpl.cs | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index e7401c19b9..4fed7a34f4 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -842,8 +842,9 @@ namespace Avalonia.Win32.Interop return SetClassLong64(hWnd, nIndex, dwNewLong); } - [ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] - internal class FileOpenDialogRCW { } + [DllImport("ole32.dll", PreserveSig = true)] + internal static extern int CoCreateInstance(ref Guid clsid, + IntPtr ignore1, int ignore2, ref Guid iid, [MarshalAs(UnmanagedType.IUnknown), Out] out object pUnkOuter); [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] diff --git a/src/Windows/Avalonia.Win32/SystemDialogImpl.cs b/src/Windows/Avalonia.Win32/SystemDialogImpl.cs index eef8a4d449..e08fecbbd9 100644 --- a/src/Windows/Avalonia.Win32/SystemDialogImpl.cs +++ b/src/Windows/Avalonia.Win32/SystemDialogImpl.cs @@ -157,7 +157,11 @@ namespace Avalonia.Win32 string result = string.Empty; var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero; - var frm = (IFileDialog)(new UnmanagedMethods.FileOpenDialogRCW()); + var clsid = Guid.Parse("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7"); + var iid = Guid.Parse("42F85136-DB7E-439C-85F1-E4075D135FC8"); + + UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk); + var frm = (IFileDialog)unk; uint options; frm.GetOptions(out options); options |= (uint)(UnmanagedMethods.FOS.FOS_PICKFOLDERS | UnmanagedMethods.FOS.FOS_FORCEFILESYSTEM | UnmanagedMethods.FOS.FOS_NOVALIDATE | UnmanagedMethods.FOS.FOS_NOTESTFILECREATE | UnmanagedMethods.FOS.FOS_DONTADDTORECENT);