FileDialogControlBase.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using System.Data;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using System.Windows.Forms;
  11. using System.Runtime.InteropServices;
  12. using System.Drawing.Drawing2D;
  13. using PaintDotNet.SystemLayer.FileDlgExtenders.Win32Types;//using Win32Types;
  14. using Win32NativeMethods = PaintDotNet.SystemLayer.FileDlgExtenders.Win32Types.NativeMethods;
  15. namespace PaintDotNet.SystemLayer.FileDlgExtenders.FileDialogExtenders
  16. {
  17. #region Base class
  18. public partial class FileDialogControlBase : UserControl
  19. {
  20. #region Delegates
  21. public delegate void PathChangedEventHandler(IWin32Window sender, string filePath);
  22. public delegate void FilterChangedEventHandler(IWin32Window sender, int index);
  23. #endregion
  24. #region Events
  25. //for weird reasons the designer wants the events public not protected
  26. [Category("FileDialogExtenders")]
  27. public event PathChangedEventHandler EventFileNameChanged;
  28. [Category("FileDialogExtenders")]
  29. public event PathChangedEventHandler EventFolderNameChanged;
  30. [Category("FileDialogExtenders")]
  31. public event FilterChangedEventHandler EventFilterChanged;
  32. [Category("FileDialogExtenders")]
  33. public event CancelEventHandler EventClosingDialog;
  34. #endregion
  35. #region Constants Declaration
  36. private const SetWindowPosFlags UFLAGSHIDE =
  37. SetWindowPosFlags.SWP_NOACTIVATE |
  38. SetWindowPosFlags.SWP_NOOWNERZORDER |
  39. SetWindowPosFlags.SWP_NOMOVE |
  40. SetWindowPosFlags.SWP_NOSIZE |
  41. SetWindowPosFlags.SWP_HIDEWINDOW;
  42. #endregion
  43. #region Variables Declaration
  44. System.Windows.Forms.FileDialog _MSdialog;
  45. NativeWindow _dlgWrapper;
  46. private AddonWindowLocation _StartLocation = AddonWindowLocation.Right;// Bottom/*Right*/;//备注2调试的地方
  47. private FolderViewMode _DefaultViewMode = FolderViewMode.Default;
  48. IntPtr _hFileDialogHandle = IntPtr.Zero;
  49. FileDialogType _FileDlgType;
  50. string _InitialDirectory = string.Empty;
  51. string _Filter = "All files (*.*)|*.*";
  52. string _DefaultExt = "jpg";
  53. string _FileName = string.Empty;
  54. string _Caption = "Save";
  55. string _OKCaption = "&Open";
  56. int _FilterIndex = 1;
  57. bool _AddExtension = true;
  58. bool _CheckFileExists = true;
  59. bool _EnableOkBtn = true;
  60. bool _DereferenceLinks = true;
  61. bool _ShowHelp;
  62. RECT _OpenDialogWindowRect = new RECT();
  63. IntPtr _hOKButton = IntPtr.Zero;
  64. private bool _hasRunInitMSDialog;
  65. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
  66. IntPtr _hListViewPtr;
  67. #endregion
  68. #region Constructors
  69. public FileDialogControlBase()
  70. {
  71. InitializeComponent();
  72. }
  73. #endregion
  74. #region Properties
  75. static uint _originalDlgHeight, _originalDlgWidth;
  76. internal static uint OriginalDlgWidth
  77. {
  78. get { return FileDialogControlBase._originalDlgWidth; }
  79. set { FileDialogControlBase._originalDlgWidth = value; }
  80. }
  81. internal static uint OriginalDlgHeight
  82. {
  83. get { return FileDialogControlBase._originalDlgHeight; }
  84. set { FileDialogControlBase._originalDlgHeight = value; }
  85. }
  86. [Browsable(false)]
  87. public string[] FileDlgFileNames
  88. {
  89. get { return DesignMode ? null : MSDialog.FileNames; }
  90. }
  91. [Browsable(false)]
  92. public FileDialog MSDialog
  93. {
  94. set { _MSdialog = value; }
  95. get { return _MSdialog; }
  96. }
  97. [Category("FileDialogExtenders")]
  98. [DefaultValue(AddonWindowLocation.Right)]
  99. public AddonWindowLocation FileDlgStartLocation
  100. {
  101. get { return _StartLocation; }
  102. set
  103. {
  104. _StartLocation = value;
  105. if (DesignMode)
  106. {
  107. this.Refresh();
  108. }
  109. }
  110. }
  111. Size _OriginalCtrlSize;
  112. internal Size OriginalCtrlSize
  113. {
  114. get { return _OriginalCtrlSize; }
  115. set
  116. {
  117. _OriginalCtrlSize = value;
  118. }
  119. }
  120. [Category("FileDialogExtenders")]
  121. [DefaultValue(FolderViewMode.Default)]
  122. public FolderViewMode FileDlgDefaultViewMode
  123. {
  124. get { return _DefaultViewMode; }
  125. set { _DefaultViewMode = value; }
  126. }
  127. [Category("FileDialogExtenders")]
  128. [DefaultValue(FileDialogType.OpenFileDlg)]
  129. public FileDialogType FileDlgType
  130. {
  131. get { return _FileDlgType; }
  132. set { _FileDlgType = value; }
  133. }
  134. [Category("FileDialogExtenders")]
  135. [DefaultValue("")]
  136. public string FileDlgInitialDirectory
  137. {
  138. get { return DesignMode ? _InitialDirectory : MSDialog.InitialDirectory; }
  139. set
  140. {
  141. _InitialDirectory = value;
  142. if (!DesignMode && MSDialog != null)
  143. MSDialog.InitialDirectory = value;
  144. }
  145. }
  146. [Category("FileDialogExtenders")]
  147. [DefaultValue("")]
  148. public string FileDlgFileName
  149. {
  150. get { return DesignMode ? _FileName : MSDialog.FileName; }
  151. set { _FileName = value; }
  152. }
  153. [Category("FileDialogExtenders")]
  154. [DefaultValue("")]
  155. public string FileDlgCaption
  156. {
  157. get { return _Caption; }
  158. set { _Caption = value; }
  159. }
  160. [Category("FileDialogExtenders")]
  161. [DefaultValue("&Open")]
  162. public string FileDlgOkCaption
  163. {
  164. get { return _OKCaption; }
  165. set { _OKCaption = value; }
  166. }
  167. [Category("FileDialogExtenders")]
  168. [DefaultValue("jpg")]
  169. public string FileDlgDefaultExt
  170. {
  171. get { return DesignMode ? _DefaultExt : MSDialog.DefaultExt; }
  172. set { _DefaultExt = value; }
  173. }
  174. [Category("FileDialogExtenders")]
  175. [DefaultValue("All files (*.*)|*.*")]
  176. public string FileDlgFilter
  177. {
  178. get { return DesignMode ? _Filter : MSDialog.Filter; }
  179. set { _Filter = value; }
  180. }
  181. [Category("FileDialogExtenders")]
  182. [DefaultValue(1)]
  183. public int FileDlgFilterIndex
  184. {
  185. get { return DesignMode ? _FilterIndex : MSDialog.FilterIndex; }
  186. set { _FilterIndex = value; }
  187. }
  188. [Category("FileDialogExtenders")]
  189. [DefaultValue(true)]
  190. public bool FileDlgAddExtension
  191. {
  192. get { return DesignMode ? _AddExtension : MSDialog.AddExtension; }
  193. set { _AddExtension = value; }
  194. }
  195. [Category("FileDialogExtenders")]
  196. [DefaultValue(true)]
  197. public bool FileDlgEnableOkBtn
  198. {
  199. get { return _EnableOkBtn; }
  200. set
  201. {
  202. _EnableOkBtn = value;
  203. if (!DesignMode && MSDialog != null && _hOKButton != IntPtr.Zero)
  204. Win32Types.NativeMethods.EnableWindow(_hOKButton, _EnableOkBtn);
  205. }
  206. }
  207. [Category("FileDialogExtenders")]
  208. [DefaultValue(true)]
  209. public bool FileDlgCheckFileExists
  210. {
  211. get { return DesignMode ? _CheckFileExists : MSDialog.CheckFileExists; }
  212. set
  213. { _CheckFileExists = value; }
  214. }
  215. [Category("FileDialogExtenders")]
  216. [DefaultValue(false)]
  217. public bool FileDlgShowHelp
  218. {
  219. get { return DesignMode ? _ShowHelp : MSDialog.ShowHelp; }
  220. set { _ShowHelp = value; }
  221. }
  222. [Category("FileDialogExtenders")]
  223. [DefaultValue(true)]
  224. public bool FileDlgDereferenceLinks
  225. {
  226. get { return DesignMode ? _DereferenceLinks : MSDialog.DereferenceLinks; }
  227. set { _DereferenceLinks = value; }
  228. }
  229. #endregion
  230. #region Virtuals
  231. //this is a hidden child window dor the whole dialog
  232. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  233. protected override void OnLoad(EventArgs e)
  234. {
  235. base.OnLoad(e);
  236. if (!DesignMode)
  237. {
  238. if (MSDialog != null)
  239. {
  240. MSDialog.FileOk += new CancelEventHandler(FileDialogControlBase_ClosingDialog);
  241. MSDialog.Disposed += new EventHandler(FileDialogControlBase_DialogDisposed);
  242. MSDialog.HelpRequest += new EventHandler(FileDialogControlBase_HelpRequest);
  243. FileDlgEnableOkBtn = _EnableOkBtn;//that's design time value
  244. Win32NativeMethods.SetWindowText(new HandleRef(_dlgWrapper, _dlgWrapper.Handle), _Caption);
  245. //will work only for open dialog, save dialog will be overriden internally by windows
  246. Win32NativeMethods.SetWindowText(new HandleRef(this, _hOKButton), _OKCaption);//SetDlgItemText fails too
  247. //bool res = NativeMethods.SetDlgItemText(NativeMethods.GetParent(Handle), (int)ControlsId.ButtonOk, FileDlgOkCaption);
  248. }
  249. }
  250. }
  251. public void SortViewByColumn(int index)
  252. {
  253. try
  254. {
  255. //handle of the "defView" --> container of the listView
  256. IntPtr hWndWin = Win32NativeMethods.FindWindowEx(_dlgWrapper.Handle, IntPtr.Zero, "SHELLDLL_DefView", "");
  257. if (hWndWin != IntPtr.Zero)
  258. {
  259. //change to details view
  260. Win32NativeMethods.SendMessage(new HandleRef(this, hWndWin), (int)Msg.WM_COMMAND, (IntPtr)(int)DefaultViewType.Details, IntPtr.Zero);
  261. #region sort by date
  262. int HDN_FIRST = (-300);
  263. int HDN_ITEMCLICKW = (HDN_FIRST - 22);
  264. //get the ListView//s hWnd
  265. IntPtr hWndLV = Win32NativeMethods.FindWindowEx(hWndWin, IntPtr.Zero, "SysListView32", IntPtr.Zero);
  266. //get the ColumnHeaders hWnd
  267. IntPtr hWndColHd = Win32NativeMethods.FindWindowEx(hWndLV, IntPtr.Zero, "SysHeader32", IntPtr.Zero);
  268. //now click on column 3 to sort for date
  269. NMHEADER NMH = new NMHEADER();
  270. NMH.hdr.hwndFrom = hWndColHd;
  271. NMH.hdr.code = (uint)HDN_ITEMCLICKW;
  272. NMH.iItem = index;
  273. NMH.iButton = 0;
  274. // Initialize unmanged memory to hold the struct.
  275. IntPtr ptrNMH = Marshal.AllocHGlobal(Marshal.SizeOf(NMH));
  276. try
  277. {
  278. // Copy the struct to unmanaged memory.
  279. Marshal.StructureToPtr(NMH, ptrNMH, false);
  280. Win32NativeMethods.SendMessage(new HandleRef(this, hWndLV), (uint)Msg.WM_NOTIFY, IntPtr.Zero, ptrNMH);
  281. //click again for descending order = newest files first
  282. Win32NativeMethods.SendMessage(new HandleRef(this, hWndLV), (uint)Msg.WM_NOTIFY, IntPtr.Zero, ptrNMH);
  283. }
  284. finally
  285. {
  286. // Free the unmanaged memory.
  287. Marshal.FreeHGlobal(ptrNMH);
  288. }
  289. ////if wanted give the dialog a larger size here
  290. //If DialogXSize > 0 And DialogYSize > 0 Then
  291. // SetWindowPos hWndDlg, 0&, 0&, 0&, DialogXSize, DialogYSize, 0&
  292. //End If
  293. //}
  294. #endregion
  295. }
  296. }
  297. catch
  298. {
  299. }
  300. }
  301. /// <summary>
  302. /// Clean up any resources being used.
  303. /// </summary>
  304. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  305. protected override void Dispose(bool disposing)
  306. {
  307. if (IsDisposed)
  308. return;
  309. if (MSDialog != null)
  310. {
  311. MSDialog.FileOk -= new CancelEventHandler(FileDialogControlBase_ClosingDialog);
  312. MSDialog.Disposed -= new EventHandler(FileDialogControlBase_DialogDisposed);
  313. MSDialog.HelpRequest -= new EventHandler(FileDialogControlBase_HelpRequest);
  314. MSDialog.Dispose();
  315. MSDialog = null;
  316. }
  317. if (disposing && (components != null))
  318. {
  319. components.Dispose();
  320. }
  321. base.Dispose(disposing);
  322. }
  323. public virtual void OnFileNameChanged(IWin32Window sender, string fileName)
  324. {
  325. if (EventFileNameChanged != null)
  326. EventFileNameChanged(sender, fileName);
  327. }
  328. public void OnFolderNameChanged(IWin32Window sender, string folderName)
  329. {
  330. if (EventFolderNameChanged != null)
  331. EventFolderNameChanged(sender, folderName);
  332. UpdateListView();
  333. }
  334. private void UpdateListView()
  335. {
  336. _hListViewPtr = Win32Types.NativeMethods.GetDlgItem(_hFileDialogHandle, (int)ControlsId.DefaultView);
  337. if (FileDlgDefaultViewMode != FolderViewMode.Default && _hFileDialogHandle != IntPtr.Zero)
  338. {
  339. Win32NativeMethods.SendMessage(new HandleRef(this, _hListViewPtr), (int)Msg.WM_COMMAND, (IntPtr)(int)FileDlgDefaultViewMode, IntPtr.Zero);
  340. if (FileDlgDefaultViewMode == FolderViewMode.Details || FileDlgDefaultViewMode == FolderViewMode.List)
  341. SortViewByColumn(0);
  342. }
  343. }
  344. internal void OnFilterChanged(IWin32Window sender, int index)
  345. {
  346. if (EventFilterChanged != null)
  347. EventFilterChanged(sender, index);
  348. }
  349. protected override void OnPaint(PaintEventArgs e)
  350. {
  351. if (DesignMode)
  352. {
  353. Graphics gr = e.Graphics;
  354. {
  355. HatchBrush hb = null;
  356. Pen p = null;
  357. try
  358. {
  359. switch (this.FileDlgStartLocation)
  360. {
  361. case AddonWindowLocation.Right:
  362. hb = new System.Drawing.Drawing2D.HatchBrush(HatchStyle.NarrowHorizontal, Color.Black, Color.Red);
  363. p = new Pen(hb, 5);
  364. gr.DrawLine(p, 0, 0, 0, this.Height);
  365. break;
  366. case AddonWindowLocation.Bottom:
  367. hb = new System.Drawing.Drawing2D.HatchBrush(HatchStyle.NarrowVertical, Color.Black, Color.Red);
  368. p = new Pen(hb, 5);
  369. gr.DrawLine(p, 0, 0, this.Width, 0);
  370. break;
  371. case AddonWindowLocation.BottomRight:
  372. default:
  373. hb = new System.Drawing.Drawing2D.HatchBrush(HatchStyle.Sphere, Color.Black, Color.Red);
  374. p = new Pen(hb, 5);
  375. gr.DrawLine(p, 0, 0, 4, 4);
  376. break;
  377. }
  378. }
  379. finally
  380. {
  381. if (p != null)
  382. p.Dispose();
  383. if (hb != null)
  384. hb.Dispose();
  385. }
  386. }
  387. }
  388. base.OnPaint(e);
  389. }
  390. #endregion
  391. #region Methods
  392. public DialogResult ShowDialog()
  393. {
  394. return ShowDialog(null);
  395. }
  396. protected virtual void OnPrepareMSDialog()
  397. {
  398. InitMSDialog();
  399. }
  400. private void InitMSDialog()
  401. {
  402. MSDialog.InitialDirectory = _InitialDirectory.Length == 0 ? Path.GetDirectoryName(Application.ExecutablePath) : _InitialDirectory;
  403. MSDialog.AddExtension = true;// _AddExtension;
  404. MSDialog.Filter = _Filter;
  405. MSDialog.FilterIndex = _FilterIndex;
  406. MSDialog.CheckFileExists = _CheckFileExists;
  407. MSDialog.DefaultExt = _DefaultExt;
  408. MSDialog.FileName = _FileName;
  409. MSDialog.DereferenceLinks = true;// _DereferenceLinks;
  410. MSDialog.ShowHelp = false;// _ShowHelp;
  411. _hasRunInitMSDialog = true;
  412. }
  413. public DialogResult ShowDialog(IWin32Window owner)
  414. {
  415. DialogResult returnDialogResult = DialogResult.Cancel;
  416. if (this.IsDisposed)
  417. return returnDialogResult;
  418. if (owner == null || owner.Handle == IntPtr.Zero)
  419. {
  420. WindowWrapper wr = new WindowWrapper(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
  421. owner = wr;
  422. }
  423. OriginalCtrlSize = this.Size;
  424. _MSdialog = (FileDlgType == FileDialogType.OpenFileDlg) ? new OpenFileDialog() as FileDialog : new SaveFileDialog() as FileDialog;
  425. _dlgWrapper = new WholeDialogWrapper(this);
  426. OnPrepareMSDialog();
  427. if (!_hasRunInitMSDialog)
  428. InitMSDialog();
  429. try
  430. {
  431. System.Reflection.PropertyInfo AutoUpgradeInfo = MSDialog.GetType().GetProperty("AutoUpgradeEnabled");
  432. if (AutoUpgradeInfo != null)
  433. AutoUpgradeInfo.SetValue(MSDialog, false, null);
  434. returnDialogResult = _MSdialog.ShowDialog(owner);
  435. }
  436. // Sometimes if you open a animated .gif on the preview and the Form is closed, .Net class throw an exception
  437. // Lets ignore this exception and keep closing the form.
  438. catch (ObjectDisposedException)
  439. {
  440. }
  441. catch (Exception ex)
  442. {
  443. MessageBox.Show("unable to get the modal dialog handle", ex.Message);
  444. }
  445. return returnDialogResult;
  446. }
  447. internal DialogResult ShowDialogExt(FileDialog fdlg, IWin32Window owner)
  448. {
  449. DialogResult returnDialogResult = DialogResult.Cancel;
  450. if (this.IsDisposed)
  451. return returnDialogResult;
  452. if (owner == null || owner.Handle == IntPtr.Zero)
  453. {
  454. WindowWrapper wr = new WindowWrapper(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
  455. owner = wr;
  456. }
  457. OriginalCtrlSize = this.Size;
  458. MSDialog = fdlg;
  459. _dlgWrapper = new WholeDialogWrapper(this);
  460. try
  461. {
  462. System.Reflection.PropertyInfo AutoUpgradeInfo = MSDialog.GetType().GetProperty("AutoUpgradeEnabled");
  463. if (AutoUpgradeInfo != null)
  464. AutoUpgradeInfo.SetValue(MSDialog, false, null);
  465. returnDialogResult = _MSdialog.ShowDialog(owner);
  466. }
  467. // Sometimes if you open a animated .gif on the preview and the Form is closed, .Net class throw an exception
  468. // Lets ignore this exception and keep closing the form.
  469. catch (ObjectDisposedException)
  470. {
  471. }
  472. catch (Exception ex)
  473. {
  474. MessageBox.Show("unable to get the modal dialog handle", ex.Message);
  475. }
  476. return returnDialogResult;
  477. }
  478. #endregion
  479. #region event handlers
  480. void FileDialogControlBase_DialogDisposed(object sender, EventArgs e)
  481. {
  482. Dispose(true);
  483. }
  484. private void FileDialogControlBase_ClosingDialog(object sender, CancelEventArgs e)
  485. {
  486. if (EventClosingDialog != null)
  487. {
  488. EventClosingDialog(this, e);
  489. }
  490. }
  491. void FileDialogControlBase_HelpRequest(object sender, EventArgs e)
  492. {
  493. //this is a virtual call that should call the event in the subclass
  494. OnHelpRequested(new HelpEventArgs(new Point()));
  495. }
  496. #endregion
  497. #region helper types
  498. public class WindowWrapper : System.Windows.Forms.IWin32Window
  499. {
  500. public WindowWrapper(IntPtr handle)
  501. {
  502. _hwnd = handle;
  503. }
  504. public IntPtr Handle
  505. {
  506. get { return _hwnd; }
  507. }
  508. private IntPtr _hwnd;
  509. }
  510. #endregion
  511. }
  512. #endregion
  513. }