SystemDialogImpl.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using Avalonia.Controls;
  2. using Avalonia.Controls.Platform;
  3. using Avalonia.Platform;
  4. using Avalonia.Win32.Interop;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Runtime.InteropServices;
  9. using System.Threading.Tasks;
  10. namespace Avalonia.Win32
  11. {
  12. class SystemDialogImpl : ISystemDialogImpl
  13. {
  14. private const UnmanagedMethods.FOS DefaultDialogOptions = UnmanagedMethods.FOS.FOS_FORCEFILESYSTEM | UnmanagedMethods.FOS.FOS_NOVALIDATE |
  15. UnmanagedMethods.FOS.FOS_NOTESTFILECREATE | UnmanagedMethods.FOS.FOS_DONTADDTORECENT;
  16. public unsafe Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
  17. {
  18. var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero;
  19. return Task.Factory.StartNew(() =>
  20. {
  21. var result = new string[0];
  22. Guid clsid = dialog is OpenFileDialog ? UnmanagedMethods.ShellIds.OpenFileDialog : UnmanagedMethods.ShellIds.SaveFileDialog;
  23. Guid iid = UnmanagedMethods.ShellIds.IFileDialog;
  24. UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk);
  25. var frm = (UnmanagedMethods.IFileDialog)unk;
  26. var openDialog = dialog as OpenFileDialog;
  27. uint options;
  28. frm.GetOptions(out options);
  29. options |= (uint)(DefaultDialogOptions);
  30. if (openDialog?.AllowMultiple == true)
  31. options |= (uint)UnmanagedMethods.FOS.FOS_ALLOWMULTISELECT;
  32. frm.SetOptions(options);
  33. var defaultExtension = (dialog as SaveFileDialog)?.DefaultExtension ?? "";
  34. frm.SetDefaultExtension(defaultExtension);
  35. frm.SetFileName(dialog.InitialFileName ?? "");
  36. frm.SetTitle(dialog.Title ?? "");
  37. var filters = new List<UnmanagedMethods.COMDLG_FILTERSPEC>();
  38. if (dialog.Filters != null)
  39. {
  40. foreach (var filter in dialog.Filters)
  41. {
  42. var extMask = string.Join(";", filter.Extensions.Select(e => "*." + e));
  43. filters.Add(new UnmanagedMethods.COMDLG_FILTERSPEC { pszName = filter.Name, pszSpec = extMask });
  44. }
  45. }
  46. if (filters.Count == 0)
  47. filters.Add(new UnmanagedMethods.COMDLG_FILTERSPEC { pszName = "All files", pszSpec = "*.*" });
  48. frm.SetFileTypes((uint)filters.Count, filters.ToArray());
  49. frm.SetFileTypeIndex(0);
  50. if (dialog.InitialDirectory != null)
  51. {
  52. UnmanagedMethods.IShellItem directoryShellItem;
  53. Guid riid = UnmanagedMethods.ShellIds.IShellItem;
  54. if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.InitialDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
  55. {
  56. frm.SetFolder(directoryShellItem);
  57. frm.SetDefaultFolder(directoryShellItem);
  58. }
  59. }
  60. if (frm.Show(hWnd) == (uint)UnmanagedMethods.HRESULT.S_OK)
  61. {
  62. if (openDialog?.AllowMultiple == true)
  63. {
  64. UnmanagedMethods.IShellItemArray shellItemArray;
  65. ((UnmanagedMethods.IFileOpenDialog)frm).GetResults(out shellItemArray);
  66. uint count;
  67. shellItemArray.GetCount(out count);
  68. result = new string[count];
  69. for (uint i = 0; i < count; i++)
  70. {
  71. UnmanagedMethods.IShellItem shellItem;
  72. shellItemArray.GetItemAt(i, out shellItem);
  73. result[i] = GetAbsoluteFilePath(shellItem);
  74. }
  75. }
  76. else
  77. {
  78. UnmanagedMethods.IShellItem shellItem;
  79. if (frm.GetResult(out shellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
  80. {
  81. result = new string[] { GetAbsoluteFilePath(shellItem) };
  82. }
  83. }
  84. }
  85. return result;
  86. });
  87. }
  88. public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
  89. {
  90. return Task.Factory.StartNew(() =>
  91. {
  92. string result = string.Empty;
  93. var hWnd = parent?.Handle?.Handle ?? IntPtr.Zero;
  94. Guid clsid = UnmanagedMethods.ShellIds.OpenFileDialog;
  95. Guid iid = UnmanagedMethods.ShellIds.IFileDialog;
  96. UnmanagedMethods.CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out var unk);
  97. var frm = (UnmanagedMethods.IFileDialog)unk;
  98. uint options;
  99. frm.GetOptions(out options);
  100. options |= (uint)(UnmanagedMethods.FOS.FOS_PICKFOLDERS | DefaultDialogOptions);
  101. frm.SetOptions(options);
  102. if (dialog.InitialDirectory != null)
  103. {
  104. UnmanagedMethods.IShellItem directoryShellItem;
  105. Guid riid = UnmanagedMethods.ShellIds.IShellItem;
  106. if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.InitialDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
  107. {
  108. frm.SetFolder(directoryShellItem);
  109. }
  110. }
  111. if (dialog.DefaultDirectory != null)
  112. {
  113. UnmanagedMethods.IShellItem directoryShellItem;
  114. Guid riid = UnmanagedMethods.ShellIds.IShellItem;
  115. if (UnmanagedMethods.SHCreateItemFromParsingName(dialog.DefaultDirectory, IntPtr.Zero, ref riid, out directoryShellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
  116. {
  117. frm.SetDefaultFolder(directoryShellItem);
  118. }
  119. }
  120. if (frm.Show(hWnd) == (uint)UnmanagedMethods.HRESULT.S_OK)
  121. {
  122. UnmanagedMethods.IShellItem shellItem;
  123. if (frm.GetResult(out shellItem) == (uint)UnmanagedMethods.HRESULT.S_OK)
  124. {
  125. result = GetAbsoluteFilePath(shellItem);
  126. }
  127. }
  128. return result;
  129. });
  130. }
  131. private string GetAbsoluteFilePath(UnmanagedMethods.IShellItem shellItem)
  132. {
  133. IntPtr pszString;
  134. if (shellItem.GetDisplayName(UnmanagedMethods.SIGDN_FILESYSPATH, out pszString) == (uint)UnmanagedMethods.HRESULT.S_OK)
  135. {
  136. if (pszString != IntPtr.Zero)
  137. {
  138. try
  139. {
  140. return Marshal.PtrToStringAuto(pszString);
  141. }
  142. finally
  143. {
  144. Marshal.FreeCoTaskMem(pszString);
  145. }
  146. }
  147. }
  148. return "";
  149. }
  150. }
  151. }