Browse Source

Merge branch 'master' into fixes/PathMarkupParser

pull/1661/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
fa71f58915
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 313
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  2. 228
      src/Windows/Avalonia.Win32/SystemDialogImpl.cs

313
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1194,16 +1194,6 @@ namespace Avalonia.Win32.Interop
public IntPtr hIconSm; 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 public enum HRESULT : uint
{ {
S_FALSE = 0x0001, S_FALSE = 0x0001,
@ -1223,7 +1213,7 @@ namespace Avalonia.Win32.Interop
public const uint SIGDN_FILESYSPATH = 0x80058000; public const uint SIGDN_FILESYSPATH = 0x80058000;
[Flags] [Flags]
internal enum FOS : uint public enum FOS : uint
{ {
FOS_OVERWRITEPROMPT = 0x00000002, FOS_OVERWRITEPROMPT = 0x00000002,
FOS_STRICTFILETYPES = 0x00000004, FOS_STRICTFILETYPES = 0x00000004,
@ -1247,135 +1237,246 @@ namespace Avalonia.Win32.Interop
FOS_DEFAULTNOMINIMODE = 0x20000000 FOS_DEFAULTNOMINIMODE = 0x20000000
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public static class ShellIds
public struct OpenFileName
{ {
public int lStructSize; public static readonly Guid OpenFileDialog = Guid.Parse("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7");
public IntPtr hwndOwner; public static readonly Guid SaveFileDialog = Guid.Parse("C0B4E2F3-BA21-4773-8DBA-335EC946EB8B");
public IntPtr hInstance; public static readonly Guid IFileDialog = Guid.Parse("42F85136-DB7E-439C-85F1-E4075D135FC8");
public IntPtr lpstrFilter; public static readonly Guid IShellItem = Guid.Parse("43826D1E-E718-42EE-BC55-A1E261C37BFE");
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;
}
}
[ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog public interface IFileDialog
{ {
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig()] [PreserveSig()]
uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec); uint SetFileTypes(uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] COMDLG_FILTERSPEC[] rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypeIndex([In] uint iFileType); uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileTypeIndex(out uint piFileType); uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie); uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Unadvise([In] uint dwCookie); uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOptions([In] uint fos); uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetOptions(out uint fos); uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi); uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName); uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap); uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Close([MarshalAs(UnmanagedType.Error)] uint hr); uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetClientGuid([In] ref Guid guid); uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint ClearClientData(); uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); 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)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
internal interface IShellItem uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
{
[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)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); void SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName); void GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); 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] [Flags]
internal enum DropEffect : int internal enum DropEffect : int
{ {

228
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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Platform;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
class SystemDialogImpl : ISystemDialogImpl 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) public unsafe Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{ {
var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero; var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero;
return Task.Factory.StartNew(() => return Task.Factory.StartNew(() =>
{ {
var filters = new StringBuilder(); var result = new string[0];
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 filterBuffer = new char[filters.Length]; Guid clsid = dialog is OpenFileDialog ? UnmanagedMethods.ShellIds.OpenFileDialog : UnmanagedMethods.ShellIds.SaveFileDialog;
filters.CopyTo(0, filterBuffer, 0, filterBuffer.Length); Guid iid = UnmanagedMethods.ShellIds.IFileDialog;
UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk);
var defExt = ToChars((dialog as SaveFileDialog)?.DefaultExtension); var frm = (UnmanagedMethods.IFileDialog)unk;
var fileBuffer = new char[256];
dialog.InitialFileName?.CopyTo(0, fileBuffer, 0, dialog.InitialFileName.Length);
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 defaultExtension = (dialog as SaveFileDialog)?.DefaultExtension ?? "";
var initialDir = ToChars(dialog.InitialDirectory); frm.SetDefaultExtension(defaultExtension);
frm.SetFileName(dialog.InitialFileName ?? "");
frm.SetTitle(dialog.Title);
fixed (char* pFileBuffer = fileBuffer) var filters = new List<UnmanagedMethods.COMDLG_FILTERSPEC>();
fixed (char* pFilterBuffer = filterBuffer) foreach (var filter in dialog.Filters)
fixed (char* pDefExt = defExt)
fixed (char* pInitDir = initialDir)
fixed (char* pTitle = title)
{ {
var ofn = new UnmanagedMethods.OpenFileName() var extMask = string.Join(";", filter.Extensions.Select(e => "*." + e));
{ filters.Add(new UnmanagedMethods.COMDLG_FILTERSPEC { pszName = filter.Name, pszSpec = extMask });
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 cStart = 0; if (filters.Count == 0)
string dir = null; filters.Add(new UnmanagedMethods.COMDLG_FILTERSPEC { pszName = "All files", pszSpec = "*.*" });
var files = new List<string>();
for (var c = 0; c < fileBuffer.Length; c++) 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 frm.SetFolder(directoryShellItem);
if (cStart == c) frm.SetDefaultFolder(directoryShellItem);
break;
var s = new string(fileBuffer, cStart, c - cStart);
if (dir == null)
dir = s;
else
files.Add(s);
cStart = c + 1;
} }
} }
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)) && UnmanagedMethods.IShellItemArray shellItemArray;
!string.IsNullOrWhiteSpace(userSelectedExt) && ((UnmanagedMethods.IFileOpenDialog)frm).GetResults(out shellItemArray);
!userSelectedExt.Contains("*")) uint count;
dir = Path.ChangeExtension(dir, userSelectedExt); 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; string result = string.Empty;
var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero; var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero;
var clsid = Guid.Parse("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7"); Guid clsid = UnmanagedMethods.ShellIds.OpenFileDialog;
var iid = Guid.Parse("42F85136-DB7E-439C-85F1-E4075D135FC8"); Guid iid = UnmanagedMethods.ShellIds.IFileDialog;
UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk); UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk);
var frm = (IFileDialog)unk; var frm = (UnmanagedMethods.IFileDialog)unk;
uint options; uint options;
frm.GetOptions(out 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); 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) if (dialog.InitialDirectory != null)
{ {
IShellItem directoryShellItem; UnmanagedMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem Guid riid = UnmanagedMethods.ShellIds.IShellItem;
if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.InitialDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK) if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.InitialDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
{ {
frm.SetFolder(directoryShellItem); frm.SetFolder(directoryShellItem);
@ -179,8 +121,8 @@ namespace Avalonia.Win32
if (dialog.DefaultDirectory != null) if (dialog.DefaultDirectory != null)
{ {
IShellItem directoryShellItem; UnmanagedMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem Guid riid = UnmanagedMethods.ShellIds.IShellItem;
if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.DefaultDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK) if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.DefaultDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
{ {
frm.SetDefaultFolder(directoryShellItem); frm.SetDefaultFolder(directoryShellItem);
@ -189,29 +131,35 @@ namespace Avalonia.Win32
if (frm.Show(hWnd) == (uint)UnmanagedMethods.HRESULT.S_OK) if (frm.Show(hWnd) == (uint)UnmanagedMethods.HRESULT.S_OK)
{ {
IShellItem shellItem; UnmanagedMethods.IShellItem shellItem;
if (frm.GetResult(out shellItem) == (uint)UnmanagedMethods.HRESULT.S_OK) if (frm.GetResult(out shellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
{ {
IntPtr pszString; result = GetAbsoluteFilePath(shellItem);
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);
}
}
}
} }
} }
return result; 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 "";
}
} }
} }

Loading…
Cancel
Save