Browse Source

Merge branch 'master' into feature/ApplicationExitMode

Benedikt Schroeder 7 years ago
parent
commit
f1ab4a9cc7

+ 207 - 106
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@@ -1194,16 +1194,6 @@ namespace Avalonia.Win32.Interop
             public IntPtr hIconSm;
         }
 
-        [Flags]
-        public enum OpenFileNameFlags
-        {
-            OFN_ALLOWMULTISELECT = 0x00000200,
-            OFN_EXPLORER = 0x00080000,
-            OFN_HIDEREADONLY = 0x00000004,
-            OFN_NOREADONLYRETURN = 0x00008000,
-            OFN_OVERWRITEPROMPT = 0x00000002
-        }
-
         public enum HRESULT : uint
         {
             S_FALSE = 0x0001,
@@ -1223,7 +1213,7 @@ namespace Avalonia.Win32.Interop
         public const uint SIGDN_FILESYSPATH = 0x80058000;
 
         [Flags]
-        internal enum FOS : uint
+        public enum FOS : uint
         {
             FOS_OVERWRITEPROMPT = 0x00000002,
             FOS_STRICTFILETYPES = 0x00000004,
@@ -1247,135 +1237,246 @@ namespace Avalonia.Win32.Interop
             FOS_DEFAULTNOMINIMODE = 0x20000000
         }
 
-        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
-        public struct OpenFileName
+        public static class ShellIds
         {
-            public int lStructSize;
-            public IntPtr hwndOwner;
-            public IntPtr hInstance;
-            public IntPtr lpstrFilter;
-            public IntPtr lpstrCustomFilter;
-            public int nMaxCustFilter;
-            public int nFilterIndex;
-            public IntPtr lpstrFile;
-            public int nMaxFile;
-            public IntPtr lpstrFileTitle;
-            public int nMaxFileTitle;
-            public IntPtr lpstrInitialDir;
-            public IntPtr lpstrTitle;
-            public OpenFileNameFlags Flags;
-            private readonly ushort Unused;
-            private readonly ushort Unused2;
-            public IntPtr lpstrDefExt;
-            public IntPtr lCustData;
-            public IntPtr lpfnHook;
-            public IntPtr lpTemplateName;
-            public IntPtr reservedPtr;
-            public int reservedInt;
-            public int flagsEx;
-        }        
-    }
+            public static readonly Guid OpenFileDialog = Guid.Parse("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7");
+            public static readonly Guid SaveFileDialog = Guid.Parse("C0B4E2F3-BA21-4773-8DBA-335EC946EB8B");
+            public static readonly Guid IFileDialog = Guid.Parse("42F85136-DB7E-439C-85F1-E4075D135FC8");
+            public static readonly Guid IShellItem = Guid.Parse("43826D1E-E718-42EE-BC55-A1E261C37BFE");
+        }
 
-    [ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-    internal interface IFileDialog
-    {
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        [PreserveSig()]
-        uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow 
+        [ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+        public interface IFileDialog
+        {
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            [PreserveSig()]
+            uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow
 
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFileTypes(uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] COMDLG_FILTERSPEC[] rgFilterSpec);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetFileTypeIndex([In] uint iFileType);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFileTypeIndex([In] uint iFileType);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetFileTypeIndex(out uint piFileType);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetFileTypeIndex(out uint piFileType);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint Unadvise([In] uint dwCookie);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint Unadvise([In] uint dwCookie);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetOptions([In] uint fos);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetOptions([In] uint fos);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetOptions(out uint fos);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetOptions(out uint fos);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetClientGuid([In] ref Guid guid);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetClientGuid([In] ref Guid guid);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint ClearClientData();
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint ClearClientData();
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
 
-    }
+        }
 
+        [ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+        public interface IFileOpenDialog
+        {
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            [PreserveSig()]
+            uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow 
 
-    [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-    internal interface IShellItem
-    {
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint BindToHandler([In] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IntPtr ppvOut);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetFileTypeIndex([In] uint iFileType);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetFileTypeIndex(out uint piFileType);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
 
-        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
-        uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
-        
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void Unadvise([In] uint dwCookie);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint SetOptions([In] uint fos);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetOptions(out uint fos);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void Close([MarshalAs(UnmanagedType.Error)] int hr);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetClientGuid([In] ref Guid guid);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void ClearClientData();
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetResults([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppenum);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppsai);
+        }
+
+        [ComImport, Guid("B63EA76D-1F85-456F-A19C-48159EFA858B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+        public interface IShellItemArray
+        {
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid rbhid,
+                         [In] ref Guid riid, out IntPtr ppvOut);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetPropertyStore([In] int Flags, [In] ref Guid riid, out IntPtr ppv);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetPropertyDescriptionList([In] ref PROPERTYKEY keyType, [In] ref Guid riid, out IntPtr ppv);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetAttributes([In] SIATTRIBFLAGS dwAttribFlags, [In] uint sfgaoMask, out uint psfgaoAttribs);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetCount(out uint pdwNumItems);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void GetItemAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenumShellItems);
+        }
+
+        [StructLayout(LayoutKind.Sequential, Pack = 4)]
+        public struct PROPERTYKEY
+        {
+            public Guid fmtid;
+            public uint pid;
+        }
+
+        public enum SIATTRIBFLAGS
+        {
+            SIATTRIBFLAGS_AND = 1,
+            SIATTRIBFLAGS_APPCOMPAT = 3,
+            SIATTRIBFLAGS_OR = 2
+        }
+
+        [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+        public interface IShellItem
+        {
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint BindToHandler([In] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IntPtr ppvOut);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
+
+            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+            uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
+
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public struct COMDLG_FILTERSPEC
+        {
+            [MarshalAs(UnmanagedType.LPWStr)]
+            public string pszName;
+            [MarshalAs(UnmanagedType.LPWStr)]
+            public string pszSpec;
+        }
     }
-    
+
     [Flags]
     internal enum DropEffect : int
     {

+ 88 - 140
src/Windows/Avalonia.Win32/SystemDialogImpl.cs

@@ -1,152 +1,94 @@
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Platform;
+using Avalonia.Win32.Interop;
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
 using System.Linq;
 using System.Runtime.InteropServices;
-using System.Text;
 using System.Threading.Tasks;
-using Avalonia.Controls;
-using Avalonia.Controls.Platform;
-using Avalonia.Platform;
-using Avalonia.Win32.Interop;
 
 namespace Avalonia.Win32
 {
 
     class SystemDialogImpl : ISystemDialogImpl
     {
-        static char[] ToChars(string s)
-        {
-            if (s == null)
-                return null;
-            var chars = new char[s.Length];
-            for (int c = 0; c < s.Length; c++)
-                chars[c] = s[c];
-            return chars;
-        }
-
         public unsafe Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
         {
             var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero;
             return Task.Factory.StartNew(() =>
             {
-                var filters = new StringBuilder();
-                foreach (var filter in dialog.Filters)
-                {
-                    var extMask = string.Join(";", filter.Extensions.Select(e => "*." + e));
-                    filters.Append(filter.Name);
-                    filters.Append(" (");
-                    filters.Append(extMask);
-                    filters.Append(")");
-                    filters.Append('\0');
-                    filters.Append(extMask);
-                    filters.Append('\0');
-                }
-                if (filters.Length == 0)
-                    filters.Append("All files\0*.*\0");
-                filters.Append('\0');
+                var result = new string[0];
 
-                var filterBuffer = new char[filters.Length];
-                filters.CopyTo(0, filterBuffer, 0, filterBuffer.Length);
-
-                var defExt = ToChars((dialog as SaveFileDialog)?.DefaultExtension);
-                var fileBuffer = new char[256];
-                dialog.InitialFileName?.CopyTo(0, fileBuffer, 0, dialog.InitialFileName.Length);
+                Guid clsid = dialog is OpenFileDialog ? UnmanagedMethods.ShellIds.OpenFileDialog : UnmanagedMethods.ShellIds.SaveFileDialog;
+                Guid iid = UnmanagedMethods.ShellIds.IFileDialog;
+                UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk);
+                var frm = (UnmanagedMethods.IFileDialog)unk;
 
-                string userSelectedExt = string.Empty;
+                var openDialog = dialog as OpenFileDialog;
 
+                uint options;
+                frm.GetOptions(out options);
+                options |= (uint)(UnmanagedMethods.FOS.FOS_NOVALIDATE | UnmanagedMethods.FOS.FOS_NOTESTFILECREATE | UnmanagedMethods.FOS.FOS_DONTADDTORECENT);
+                if (openDialog?.AllowMultiple == true)
+                    options |= (uint)UnmanagedMethods.FOS.FOS_ALLOWMULTISELECT;
+                frm.SetOptions(options);
 
-                var title = ToChars(dialog.Title);
-                var initialDir = ToChars(dialog.InitialDirectory);
+                var defaultExtension = (dialog as SaveFileDialog)?.DefaultExtension ?? "";
+                frm.SetDefaultExtension(defaultExtension);
+                frm.SetFileName(dialog.InitialFileName ?? "");
+                frm.SetTitle(dialog.Title);
 
-                fixed (char* pFileBuffer = fileBuffer)
-                fixed (char* pFilterBuffer = filterBuffer)
-                fixed (char* pDefExt = defExt)
-                fixed (char* pInitDir = initialDir)
-                fixed (char* pTitle = title)
+                var filters = new List<UnmanagedMethods.COMDLG_FILTERSPEC>();
+                foreach (var filter in dialog.Filters)
                 {
-                    var ofn = new UnmanagedMethods.OpenFileName()
-                    {
-                        hwndOwner = hWnd,
-                        hInstance = IntPtr.Zero,
-                        lCustData = IntPtr.Zero,
-                        nFilterIndex = 0,
-                        Flags =
-                            UnmanagedMethods.OpenFileNameFlags.OFN_EXPLORER |
-                            UnmanagedMethods.OpenFileNameFlags.OFN_HIDEREADONLY,
-                        nMaxCustFilter = 0,
-                        nMaxFile = fileBuffer.Length - 1,
-                        nMaxFileTitle = 0,
-                        lpTemplateName = IntPtr.Zero,
-                        lpfnHook = IntPtr.Zero,
-                        lpstrCustomFilter = IntPtr.Zero,
-                        lpstrDefExt = new IntPtr(pDefExt),
-                        lpstrFile = new IntPtr(pFileBuffer),
-                        lpstrFileTitle = IntPtr.Zero,
-                        lpstrFilter = new IntPtr(pFilterBuffer),
-                        lpstrInitialDir = new IntPtr(pInitDir),
-                        lpstrTitle = new IntPtr(pTitle),
-
-                    };
-                    ofn.lStructSize = Marshal.SizeOf(ofn);
-                    if ((dialog as OpenFileDialog)?.AllowMultiple == true)
-                        ofn.Flags |= UnmanagedMethods.OpenFileNameFlags.OFN_ALLOWMULTISELECT;
-
-                    if (dialog is SaveFileDialog)
-                        ofn.Flags |= UnmanagedMethods.OpenFileNameFlags.OFN_NOREADONLYRETURN |
-                                     UnmanagedMethods.OpenFileNameFlags.OFN_OVERWRITEPROMPT;
-
-                    var pofn = &ofn;
-
-                    // We should save the current directory to restore it later.
-                    var currentDirectory = Environment.CurrentDirectory;
-
-                    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
-                    Environment.CurrentDirectory = currentDirectory;
-
-                    if (!res)
-                        return null;
-                    if (dialog?.Filters.Count > 0)
-                        userSelectedExt = dialog.Filters[ofn.nFilterIndex - 1].Extensions.FirstOrDefault();
+                    var extMask = string.Join(";", filter.Extensions.Select(e => "*." + e));
+                    filters.Add(new UnmanagedMethods.COMDLG_FILTERSPEC { pszName = filter.Name, pszSpec = extMask });
                 }
-                var cStart = 0;
-                string dir = null;
-                var files = new List<string>();
-                for (var c = 0; c < fileBuffer.Length; c++)
+                if (filters.Count == 0)
+                    filters.Add(new UnmanagedMethods.COMDLG_FILTERSPEC { pszName = "All files", pszSpec = "*.*" });
+
+                frm.SetFileTypes((uint)filters.Count, filters.ToArray());
+                frm.SetFileTypeIndex(0);
+
+                if (dialog.InitialDirectory != null)
                 {
-                    if (fileBuffer[c] == 0)
+                    UnmanagedMethods.IShellItem directoryShellItem;
+                    Guid riid = UnmanagedMethods.ShellIds.IShellItem;
+                    if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.InitialDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
                     {
-                        //Encountered double zero char
-                        if (cStart == c)
-                            break;
-
-                        var s = new string(fileBuffer, cStart, c - cStart);
-                        if (dir == null)
-                            dir = s;
-                        else
-                            files.Add(s);
-                        cStart = c + 1;
+                        frm.SetFolder(directoryShellItem);
+                        frm.SetDefaultFolder(directoryShellItem);
                     }
                 }
-                if (files.Count == 0)
+
+                if (frm.Show(hWnd) == (uint)UnmanagedMethods.HRESULT.S_OK)
                 {
-                    if (dialog is SaveFileDialog)
+                    if (openDialog?.AllowMultiple == true)
                     {
-                        if (string.IsNullOrWhiteSpace(Path.GetExtension(dir)) &&
-                            !string.IsNullOrWhiteSpace(userSelectedExt) &&
-                            !userSelectedExt.Contains("*"))
-                            dir = Path.ChangeExtension(dir, userSelectedExt);
+                        UnmanagedMethods.IShellItemArray shellItemArray;
+                        ((UnmanagedMethods.IFileOpenDialog)frm).GetResults(out shellItemArray);
+                        uint count;
+                        shellItemArray.GetCount(out count);
+                        result = new string[count];
+                        for (uint i = 0; i < count; i++)
+                        {
+                            UnmanagedMethods.IShellItem shellItem;
+                            shellItemArray.GetItemAt(i, out shellItem);
+                            result[i] = GetAbsoluteFilePath(shellItem);
+                        }
+                    }
+                    else
+                    {
+                        UnmanagedMethods.IShellItem shellItem;
+                        if (frm.GetResult(out shellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
+                        {
+                            result = new string[] { GetAbsoluteFilePath(shellItem) };
+                        }
                     }
-
-                    return new[] { dir };
                 }
 
-                return files.Select(f => Path.Combine(dir, f)).ToArray();
+                return result;
             });
         }
 
@@ -157,11 +99,11 @@ namespace Avalonia.Win32
                 string result = string.Empty;
 
                 var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero;
-                var clsid = Guid.Parse("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7");
-                var iid  = Guid.Parse("42F85136-DB7E-439C-85F1-E4075D135FC8");
+                Guid clsid = UnmanagedMethods.ShellIds.OpenFileDialog;
+                Guid iid  = UnmanagedMethods.ShellIds.IFileDialog;
 
                 UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk);
-                var frm = (IFileDialog)unk;
+                var frm = (UnmanagedMethods.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);
@@ -169,8 +111,8 @@ namespace Avalonia.Win32
 
                 if (dialog.InitialDirectory != null)
                 {
-                    IShellItem directoryShellItem;
-                    var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
+                    UnmanagedMethods.IShellItem directoryShellItem;
+                    Guid riid = UnmanagedMethods.ShellIds.IShellItem;
                     if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.InitialDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
                     {
                         frm.SetFolder(directoryShellItem);
@@ -179,8 +121,8 @@ namespace Avalonia.Win32
 
                 if (dialog.DefaultDirectory != null)
                 {
-                    IShellItem directoryShellItem;
-                    var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
+                    UnmanagedMethods.IShellItem directoryShellItem;
+                    Guid riid = UnmanagedMethods.ShellIds.IShellItem;
                     if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.DefaultDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
                     {
                         frm.SetDefaultFolder(directoryShellItem);
@@ -189,29 +131,35 @@ namespace Avalonia.Win32
 
                 if (frm.Show(hWnd) == (uint)UnmanagedMethods.HRESULT.S_OK)
                 {
-                    IShellItem shellItem;
+                    UnmanagedMethods.IShellItem shellItem;
                     if (frm.GetResult(out shellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
                     {
-                        IntPtr pszString;
-                        if (shellItem.GetDisplayName(UnmanagedMethods.SIGDN_FILESYSPATH, out pszString) == (uint)UnmanagedMethods.HRESULT.S_OK)
-                        {
-                            if (pszString != IntPtr.Zero)
-                            {
-                                try
-                                {
-                                    result = Marshal.PtrToStringAuto(pszString);
-                                }
-                                finally
-                                {
-                                    Marshal.FreeCoTaskMem(pszString);
-                                }
-                            }
-                        }
+                        result = GetAbsoluteFilePath(shellItem);
                     }
                 }
 
                 return result;
             });
         }
+
+        private string GetAbsoluteFilePath(UnmanagedMethods.IShellItem shellItem)
+        {
+            IntPtr pszString;
+            if (shellItem.GetDisplayName(UnmanagedMethods.SIGDN_FILESYSPATH, out pszString) == (uint)UnmanagedMethods.HRESULT.S_OK)
+            {
+                if (pszString != IntPtr.Zero)
+                {
+                    try
+                    {
+                        return Marshal.PtrToStringAuto(pszString);
+                    }
+                    finally
+                    {
+                        Marshal.FreeCoTaskMem(pszString);
+                    }
+                }
+            }
+            return "";
+        }
     }
 }