SystemTrayMenu/UserInterface/Dialogs/FolderDialog.cs

313 lines
12 KiB
C#
Raw Normal View History

// <copyright file="FolderDialog.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
2020-06-06 04:30:26 +12:00
namespace SystemTrayMenu.UserInterface.Dialogs
2020-06-06 04:30:26 +12:00
{
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
2020-06-06 04:30:26 +12:00
public class FolderDialog : IFolderDialog, IDisposable
{
private bool isDisposed;
/// <summary>
/// Gets or sets /sets folder in which dialog will be open.
2020-06-06 04:30:26 +12:00
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets or sets /sets directory in which dialog will be open
2020-06-06 04:30:26 +12:00
/// if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets or sets selected folder.
2020-06-06 04:30:26 +12:00
/// </summary>
public string Folder { get; set; }
2020-06-06 04:30:26 +12:00
public DialogResult ShowDialog()
{
return ShowDialog(owner: new WindowWrapper(IntPtr.Zero));
}
2020-06-06 04:30:26 +12:00
public DialogResult ShowDialog(IWin32Window owner)
{
if (Environment.OSVersion.Version.Major >= 6)
{
return ShowVistaDialog(owner);
}
else
{
return ShowLegacyDialog(owner);
}
}
2020-06-06 04:30:26 +12:00
public DialogResult ShowVistaDialog(IWin32Window owner)
{
NativeMethods.IFileDialog frm = (NativeMethods.IFileDialog)new NativeMethods.FileOpenDialogRCW();
frm.GetOptions(out uint options);
2020-06-06 04:30:26 +12:00
options |= NativeMethods.FOS_PICKFOLDERS |
NativeMethods.FOS_FORCEFILESYSTEM |
NativeMethods.FOS_NOVALIDATE |
NativeMethods.FOS_NOTESTFILECREATE |
NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (InitialFolder != null)
2020-06-06 04:30:26 +12:00
{
Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem
if (NativeMethods.SHCreateItemFromParsingName(
InitialFolder,
IntPtr.Zero,
ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
2020-06-06 04:30:26 +12:00
{
frm.SetFolder(directoryShellItem);
}
}
if (DefaultFolder != null)
2020-06-06 04:30:26 +12:00
{
Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem
if (NativeMethods.SHCreateItemFromParsingName(
DefaultFolder,
IntPtr.Zero,
ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
2020-06-06 04:30:26 +12:00
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if (owner != null && frm.Show(owner.Handle) == NativeMethods.S_OK)
2020-06-06 04:30:26 +12:00
{
if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK)
2020-06-06 04:30:26 +12:00
{
if (shellItem.GetDisplayName(
NativeMethods.SIGDN_FILESYSPATH,
out IntPtr pszString) == NativeMethods.S_OK)
2020-06-06 04:30:26 +12:00
{
if (pszString != IntPtr.Zero)
{
try
{
Folder = Marshal.PtrToStringAuto(pszString);
2020-06-06 04:30:26 +12:00
return DialogResult.OK;
}
finally
{
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
2020-06-06 04:30:26 +12:00
return DialogResult.Cancel;
}
2020-06-06 04:30:26 +12:00
public DialogResult ShowLegacyDialog(IWin32Window owner)
{
using SaveFileDialog frm = new SaveFileDialog
2020-06-06 04:30:26 +12:00
{
CheckFileExists = false,
CheckPathExists = true,
CreatePrompt = false,
Filter = "|" + Guid.Empty.ToString(),
FileName = "any",
};
if (InitialFolder != null)
{
frm.InitialDirectory = InitialFolder;
}
frm.OverwritePrompt = false;
frm.Title = Translator.GetText("Select Folder");
frm.ValidateNames = false;
if (frm.ShowDialog(owner) == DialogResult.OK)
{
Folder = Path.GetDirectoryName(frm.FileName);
return DialogResult.OK;
}
else
{
return DialogResult.Cancel;
2020-06-06 04:30:26 +12:00
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!isDisposed)
{
}
2020-06-06 04:30:26 +12:00
isDisposed = true;
}
}
2020-06-06 04:30:26 +12:00
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
/// <summary>
/// Initializes a new instance of the <see cref="WindowWrapper"/> class.
2020-06-06 04:30:26 +12:00
/// </summary>
/// <param name="handle">Handle to wrap.</param>
2020-06-06 04:30:26 +12:00
public WindowWrapper(IntPtr handle)
{
hwnd = handle;
2020-06-06 04:30:26 +12:00
}
/// <summary>
/// Gets original ptr.
2020-06-06 04:30:26 +12:00
/// </summary>
public IntPtr Handle => hwnd;
private readonly IntPtr hwnd;
2020-06-06 04:30:26 +12:00
}
2020-06-06 04:30:26 +12:00
internal static class NativeMethods
{
public const uint FOS_PICKFOLDERS = 0x00000020;
public const uint FOS_FORCEFILESYSTEM = 0x00000040;
public const uint FOS_NOVALIDATE = 0x00000100;
public const uint FOS_NOTESTFILECREATE = 0x00010000;
public const uint FOS_DONTADDTORECENT = 0x02000000;
public const uint S_OK = 0x0000;
public const uint SIGDN_FILESYSPATH = 0x80058000;
[ComImport]
[ClassInterface(ClassInterfaceType.None)]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
internal class FileOpenDialogRCW
{
}
2020-06-06 04:30:26 +12:00
[ComImport]
[Guid("42F85136-DB7E-439C-85F1-E4075D135FC8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
2020-06-06 04:30:26 +12:00
internal interface IFileDialog
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
uint Show([In, Optional] IntPtr hwndOwner);
2020-06-06 04:30:26 +12:00
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
2020-06-06 04:30:26 +12:00
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise(
[In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde,
2020-06-06 04:30:26 +12:00
out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
2020-06-06 04:30:26 +12:00
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
2020-06-06 04:30:26 +12:00
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)]
string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
}
[ComImport]
[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
2020-06-06 04:30:26 +12:00
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);
2020-06-06 04:30:26 +12:00
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
2020-06-06 04:30:26 +12:00
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);
2020-06-06 04:30:26 +12:00
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string pszPath,
IntPtr pbc,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
2020-06-06 04:30:26 +12:00
}
}