FileDialogControlBase.cs 22 KB

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