vbAccelerator - Contents of code file: FolderBrowser.csusing System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace vbAccelerator.Components.Shell
{
#region FolderBrowserFilter
/// <summary>
/// An object to manage filtering of items displayed
/// in the folder browser
/// </summary>
public class FolderBrowserFilter
{
#region Member Variables
private bool applyFilter = false;
private FileFilterSpecificationCollection items = null;
#endregion
#region Implementation
/// <summary>
/// Gets/sets whether the items shown in the folder
/// will be filtered.
/// </summary>
public bool ApplyFilter
{
get
{
return this.applyFilter;
}
set
{
this.applyFilter = value;
}
}
/// <summary>
/// Returns whether the specified file should be filtered from
/// the view
/// </summary>
/// <param name="file">The file to check.</param>
/// <param name="isFolder">Whether the file is a folder or not.</param>
/// <returns>True to filter the item, False otherwise</returns>
public virtual bool ShouldFilter(string file, bool isFolder)
{
bool ret = false;
if (items.Count > 0)
{
foreach (FileFilterSpecification filter in items)
{
if (isFolder)
{
if (filter.ApplyToFolder)
{
if (filter.RegularExpression.IsMatch(file))
{
ret = false;
break;
}
else
{
ret = true;
}
}
}
else
{
if (filter.ApplyToFile)
{
if (filter.RegularExpression.IsMatch(file))
{
ret = false;
break;
}
else
{
ret = true;
}
}
}
}
}
return ret;
}
/// <summary>
/// Returns the collection of file filters to apply to
/// the Folder Browser View.
/// </summary>
public FileFilterSpecificationCollection Items
{
get
{
return this.items;
}
}
#endregion
#region Constructor and Destructor
/// <summary>
/// Creates a default instance of a Folder Browser filter.
/// </summary>
public FolderBrowserFilter()
{
this.items = new FileFilterSpecificationCollection();
}
/// <summary>
/// Creates an instance of a Folder Browser filter with
/// the specified filters.
/// </summary>
/// <param name="items"></param>
public FolderBrowserFilter(FileFilterSpecificationCollection items)
{
this.items = items;
}
#endregion
}
#endregion
#region FileFilterSpecificationCollection
/// <summary>
/// Contains a collection of filters to be applied to the
/// FolderBrowser.
/// </summary>
public class FileFilterSpecificationCollection : CollectionBase
{
/// <summary>
/// Adds a new file filter to the filter list.
/// </summary>
/// <param name="filter">The filter to add</param>
public void Add(FileFilterSpecification filter)
{
this.InnerList.Add(filter);
}
/// <summary>
/// Returns the filter at the specified index.
/// </summary>
public FileFilterSpecification this[int index]
{
get
{
return (FileFilterSpecification)this.InnerList[index];
}
set
{
this.InnerList[index] = value;
}
}
/// <summary>
/// Creates a new, blank filter collection.
/// </summary>
public FileFilterSpecificationCollection()
{
}
/// <summary>
/// Creates a new filter collection containing the specified
/// filters.
/// </summary>
/// <param name="filters">The filters to add.</param>
public FileFilterSpecificationCollection(FileFilterSpecification[]
filters)
{
foreach (FileFilterSpecification filter in filters)
{
this.InnerList.Add(filter);
}
}
}
#endregion
#region FileFilterSpecification
/// <summary>
/// Specifies a regular expression for filtering
/// a file or folder in the Folder Browser.
/// </summary>
public class FileFilterSpecification
{
private Regex regularExpression = null;
private string filter = "";
private bool applyToFile = true;
private bool applyToFolder = false;
/// <summary>
/// Gets/sets whether this filter should apply to
/// files.
/// </summary>
public bool ApplyToFile
{
get
{
return this.applyToFile;
}
set
{
this.applyToFile = value;
}
}
/// <summary>
/// Gets/sets whether this filter should apply to
/// folders.
/// </summary>
public bool ApplyToFolder
{
get
{
return this.applyToFolder;
}
set
{
this.applyToFolder = value;
}
}
/// <summary>
/// Gets/sets the regular expression to match against
/// filtering items
/// </summary>
public string Filter
{
get
{
return this.filter;
}
set
{
this.filter = value;
regularExpression = new Regex(filter);
}
}
/// <summary>
/// Returns the compiled regular expression for
/// this filter.
/// </summary>
internal Regex RegularExpression
{
get
{
return this.regularExpression;
}
}
/// <summary>
/// Creates a new file filter without specifying
/// its details.
/// </summary>
public FileFilterSpecification()
{
}
/// <summary>
/// Creates a new file filter and initialises all
/// the members.
/// </summary>
/// <param name="filter">The regular expression to use
/// when matching this filter.</param>
/// <param name="applyToFile">Whether this filter should
/// be applied to files.</param>
/// <param name="applyToFolder">Whether this filter should
/// be applied to folders.</param>
public FileFilterSpecification(
string filter,
bool applyToFile,
bool applyToFolder
)
{
Filter = filter;
this.applyToFile = applyToFile;
this.applyToFolder = applyToFolder;
}
}
#endregion
#region ValidationFailed Event Arguments and Delegate
/// <summary>
/// Class to manage arguments for Validation Failure
/// in the Folder Browser.
/// </summary>
public class ValidationFailedEventArgs
{
private string message = "";
private bool cancel = true;
/// <summary>
/// Returns the text from the Edit Box which has caused
/// validation to fail
/// </summary>
public string Message
{
get
{
return this.message;
}
}
/// <summary>
/// Gets/sets whether the dialog should be Cancelled (closed)
/// or not.
/// </summary>
public bool Cancel
{
get
{
return this.cancel;
}
set
{
this.cancel = value;
}
}
internal ValidationFailedEventArgs(
string message
)
{
this.message = message;
}
}
/// <summary>
/// Delegate to allow ValidationFailedEvent to be called.
/// </summary>
public delegate void ValidationFailedEventHandler(object sender,
ValidationFailedEventArgs e);
#endregion
#region SelectionChanged Event Arguments and Delegate
/// <summary>
/// Class to hold details of a selection change for the selection
/// change event.
/// </summary>
public class SelectionChangedEventArgs
{
private FolderBrowser.SafePidl pidl = null;
/// <summary>
/// Gets the pidl of the newly selected item
/// </summary>
public IntPtr Pidl
{
get
{
return this.pidl.Pidl;
}
}
/// <summary>
/// Gets the path of the newly selected item
/// </summary>
public string Path
{
get
{
return this.pidl.Path;
}
}
internal SelectionChangedEventArgs(FolderBrowser.SafePidl pidl)
{
this.pidl = pidl;
}
}
/// <summary>
/// Delegate to allow SelectionChangedEvents to be propagated.
/// </summary>
public delegate void SelectionChangedEventHandler(object sender,
SelectionChangedEventArgs e);
#endregion
#region FolderBrowser
/// <summary>
/// Provides a Shell Folder Browser (not available under .NET
/// Framwork 1.0)
/// </summary>
public class FolderBrowser : IDisposable
{
#region ShellFolder Enumerations
[Flags]
private enum ESTRRET : int
{
STRRET_WSTR = 0x0000, // Use STRRET.pOleStr
STRRET_OFFSET = 0x0001, // Use STRRET.uOffset to Ansi
STRRET_CSTR = 0x0002 // Use STRRET.cStr
}
[Flags]
private enum ESHCONTF : int
{
SHCONTF_FOLDERS = 0x0020,
SHCONTF_NONFOLDERS = 0x0040,
SHCONTF_INCLUDEHIDDEN = 0x0080,
SHCONTF_INIT_ON_FIRST_NEXT = 0x0100, // allow EnumObject() to return
before validating enum
SHCONTF_NETPRINTERSRCH = 0x0200, // hint that client is looking for
printers
SHCONTF_SHAREABLE = 0x0400, // hint that client is looking sharable
resources (remote shares)
SHCONTF_STORAGE = 0x0800, // include all items with accessible
storage and their ancestors
}
[Flags]
private enum ESHGDN : int
{
SHGDN_NORMAL = 0,
SHGDN_INFOLDER = 1,
SHGDN_FORADDRESSBAR = 16384,
SHGDN_FORPARSING = 32768
}
[Flags]
private enum ESFGAO : int
{
SFGAO_CANCOPY = 1,
SFGAO_CANMOVE = 2,
SFGAO_CANLINK = 4,
SFGAO_CANRENAME = 16,
SFGAO_CANDELETE = 32,
SFGAO_HASPROPSHEET = 64,
SFGAO_DROPTARGET = 256,
SFGAO_CAPABILITYMASK = 375,
SFGAO_LINK = 65536,
SFGAO_SHARE = 131072,
SFGAO_READONLY = 262144,
SFGAO_GHOSTED = 524288,
SFGAO_DISPLAYATTRMASK = 983040,
SFGAO_FILESYSANCESTOR = 268435456,
SFGAO_FOLDER = 536870912,
SFGAO_FILESYSTEM = 1073741824,
SFGAO_HASSUBFOLDER = -2147483648,
SFGAO_CONTENTSMASK = -2147483648,
SFGAO_VALIDATE = 16777216,
SFGAO_REMOVABLE = 33554432,
SFGAO_COMPRESSED = 67108864
}
#endregion
#region ShellFolder Structures
[StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0,
CharSet=CharSet.Auto)]
private struct STRRET_CSTR
{
public ESTRRET uType;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray,
SizeConst=520)]
public byte[] cStr;
}
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Auto)]
private struct STRRET_ANY
{
[FieldOffset(0)]
public ESTRRET uType;
[FieldOffset(4)]
public IntPtr pOLEString;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct SIZE
{
public int cx;
public int cy;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
#endregion
#region COM Interop for IEnumIDList
[ComImportAttribute()]
[GuidAttribute("000214F2-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//helpstring("IEnumIDList interface")
private interface IEnumIDList
{
[PreserveSig]
int Next(
int celt,
ref IntPtr rgelt,
out int pceltFetched);
void Skip(
int celt);
void Reset();
void Clone(
ref IEnumIDList ppenum);
};
#endregion
#region Com Interop for IUnknown
[ComImport, Guid("00000000-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IUnknown
{
[PreserveSig]
IntPtr QueryInterface(ref Guid riid, out IntPtr pVoid);
[PreserveSig]
IntPtr AddRef();
[PreserveSig]
IntPtr Release();
}
#endregion
#region COM Interop for IShellFolder
[ComImportAttribute()]
[GuidAttribute("000214E6-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//helpstring("IShellFolder interface")
private interface IShellFolder
{
void ParseDisplayName(
IntPtr hwndOwner,
IntPtr pbcReserved,
[MarshalAs(UnmanagedType.LPWStr)] string lpszDisplayName,
out int pchEaten,
out IntPtr ppidl,
out int pdwAttributes);
void EnumObjects(
IntPtr hwndOwner,
[MarshalAs(UnmanagedType.U4)] ESHCONTF grfFlags,
ref IEnumIDList ppenumIDList
);
void BindToObject(
IntPtr pidl,
IntPtr pbcReserved,
ref Guid riid,
ref IShellFolder ppvOut);
void BindToStorage(
IntPtr pidl,
IntPtr pbcReserved,
ref Guid riid,
IntPtr ppvObj
);
[PreserveSig]
int CompareIDs(
IntPtr lParam,
IntPtr pidl1,
IntPtr pidl2);
void CreateViewObject(
IntPtr hwndOwner,
ref Guid riid,
IntPtr ppvOut);
void GetAttributesOf(
int cidl,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[]
apidl,
[MarshalAs(UnmanagedType.U4)] ref ESFGAO rgfInOut);
void GetUIObjectOf(
IntPtr hwndOwner,
int cidl,
ref IntPtr apidl,
ref Guid riid,
out int prgfInOut,
ref IUnknown ppvOut);
void GetDisplayNameOf(
IntPtr pidl,
[MarshalAs(UnmanagedType.U4)] ESHGDN uFlags,
ref STRRET_CSTR lpName);
void SetNameOf(
IntPtr hwndOwner,
IntPtr pidl,
[MarshalAs(UnmanagedType.LPWStr)] string lpszName,
[MarshalAs(UnmanagedType.U4)] ESHCONTF uFlags,
ref IntPtr ppidlOut);
};
#endregion
#region IFolderFilter Com Interop
[ComImportAttribute()]
[GuidAttribute("9CC22886-DC8E-11d2-B1D0-00C04F8EEB3E")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
private interface IFolderFilter
{
[PreserveSig]
int ShouldShow(
IShellFolder psf,
IntPtr pidlFolder,
IntPtr pidlItem);
[PreserveSig]
int GetEnumFlags(
IShellFolder psf,
IntPtr pidlFolder,
IntPtr phwnd,
[MarshalAs(UnmanagedType.U4)] out ESHCONTF pgrfFlags);
};
#endregion
#region IFolderFilterSite Com Interop
[ComImportAttribute()]
[GuidAttribute("C0A651F5-B48B-11d2-B5ED-006097C686F6")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//helpstring("IFolderFilterSite"),
private interface IFolderFilterSite
{
void SetFilter(
[MarshalAs(UnmanagedType.Interface)] IFolderFilter punk);
}
#endregion
#region FolderBrowser IMalloc Com Interop
[ComImportAttribute()]
[GuidAttribute("00000002-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//helpstring("IMalloc interface")
private interface IMalloc
{
[PreserveSig]
IntPtr Alloc(int cb);
[PreserveSig]
IntPtr Realloc(
IntPtr pv,
int cb);
[PreserveSig]
void Free(IntPtr pv);
[PreserveSig]
int GetSize(IntPtr pv);
[PreserveSig]
int DidAlloc(IntPtr pv);
[PreserveSig]
void HeapMinimize();
};
#endregion
#region SafePidl
/// <summary>
/// Class to manage a Shell Pointer to ID List (Pidl)
/// </summary>
public class SafePidl : IDisposable
{
private IntPtr pidl = IntPtr.Zero;
private bool shouldFree = true;
/// <summary>
/// Returns the Pointer to ID List for this object.
/// </summary>
public IntPtr Pidl
{
get
{
return pidl;
}
}
/// <summary>
/// Returns the path name for this Pidl
/// </summary>
public string Path
{
get
{
StringBuilder path = new StringBuilder(260, 260);
UnManagedMethods.SHGetPathFromIDList(pidl, path);
return path.ToString();
}
}
private IntPtr PathToPidl(string path)
{
IntPtr newPidl = IntPtr.Zero ;
IShellFolder ishFolder = null;
if (UnManagedMethods.SHGetDesktopFolder(out ishFolder) == 0) // S_OK
{
// we have it:
int cParsed = 0;
int afItem = 0;
ishFolder.ParseDisplayName(
IntPtr.Zero,
IntPtr.Zero,
path,
out cParsed,
out newPidl,
out afItem);
Marshal.ReleaseComObject(ishFolder);
}
return newPidl;
}
/// <summary>
/// Enables the Pidl to be freed.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Enables the Pidl to be freed when disposing is true.
/// </summary>
/// <param name="disposing">Whether disposing or not</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (pidl != IntPtr.Zero)
{
if (shouldFree)
{
Allocator.Free(pidl);
}
}
pidl = IntPtr.Zero;
}
}
internal SafePidl(IntPtr pidl, bool shouldFree)
{
this.pidl = pidl;
this.shouldFree = shouldFree;
}
/// <summary>
/// Constructs a new Pidl for the specified path
/// </summary>
/// <param name="path">Path to get Pidl for</param>
public SafePidl(string path)
{
if (path.Length > 0)
{
if (System.IO.Directory.Exists(path))
{
this.pidl = PathToPidl(path);
}
else
{
throw new System.IO.DirectoryNotFoundException(
String.Format("The path {0} could not be found.", path));
}
}
}
}
#endregion
#region Allocator
/// <summary>
/// Class to manage the Shell's IMalloc interface.
/// </summary>
public class Allocator : IDisposable
{
private static IMalloc alloc = null;
private static bool disposed = false;
/// <summary>
/// Frees the specified memory (if allocated by the
/// Shell).
/// </summary>
/// <param name="ptr">Pointer to memory to free</param>
public static void Free(IntPtr ptr)
{
if (!disposed)
{
if (alloc == null)
{
UnManagedMethods.SHGetMalloc(out alloc);
}
if (alloc != null)
{
try
{
alloc.Free(ptr);
}
catch (Exception ex)
{
Console.WriteLine("Problem {0}", ex.Message);
}
}
}
}
/// <summary>
/// Frees the reference to the Shell's IMalloc object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Frees the reference to the SHell's IMalloc object
/// when disposing is true.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (!disposed)
{
if (alloc != null)
{
Marshal.ReleaseComObject(alloc);
alloc = null;
}
disposed = true;
}
}
}
}
#endregion
#region BrowseItemFilter
[ComVisible(true)]
[Guid("43104713-CF18-43d4-8A3F-BC45AD280D57")]
private class BrowseItemFilter : IFolderFilter
{
FolderBrowserFilter filter = null;
public int ShouldShow(
IShellFolder psf, // A pointer to the folder's
IShellFolder interface.
IntPtr pidlFolder, // The folder's PIDL.
IntPtr pidlItem) // The item's PIDL.
{
// Get the display name of the item:
int ret = 0;
if (filter != null)
{
// Get the display name of this item:
STRRET_CSTR name = new STRRET_CSTR();
psf.GetDisplayNameOf(
pidlItem,
ESHGDN.SHGDN_NORMAL | ESHGDN.SHGDN_FORPARSING,
ref name);
string displayName = "";
if (name.uType == ESTRRET.STRRET_WSTR)
{
// first 4 bytes of name.cStr is a pointer
// to a string;
IntPtr strPtr = (IntPtr)(
(((int)name.cStr[3]) << 24) |
(((int)name.cStr[2]) << 16) |
(((int)name.cStr[1]) << 8) |
(int)name.cStr[0]);
displayName = Marshal.PtrToStringAuto(strPtr);
}
else
{
// name.cStr contains the string as ANSI..
// there must be a better way than this?
for (int i = 0; i < 260; i++)
{
if (name.cStr[i] == 0)
{
break;
}
else
{
displayName += Convert.ToChar(name.cStr[i]);
}
}
}
// determine if folder:
ESFGAO attrib = ESFGAO.SFGAO_FOLDER;
IntPtr[] apidl = new IntPtr[1];
apidl[0] = pidlItem;
psf.GetAttributesOf(1, apidl, ref attrib);
bool isFolder = ((attrib & ESFGAO.SFGAO_FOLDER) ==
ESFGAO.SFGAO_FOLDER);
if (filter.ShouldFilter(
displayName,
isFolder)
)
{
ret = 1;
}
}
return ret;
}
public int GetEnumFlags(
IShellFolder psf,
IntPtr pidlFolder,
IntPtr phwnd,
out ESHCONTF pgrfFlags
)
{
//
pgrfFlags = ESHCONTF.SHCONTF_FOLDERS
| ESHCONTF.SHCONTF_NONFOLDERS
| ESHCONTF.SHCONTF_SHAREABLE
| ESHCONTF.SHCONTF_STORAGE ;
return 0;
}
public BrowseItemFilter(FolderBrowserFilter filter)
{
this.filter = filter;
}
}
#endregion
#region Internal Delegates
private delegate int BrowseCallBackProc(IntPtr hwnd, int msg, IntPtr lp,
IntPtr wp);
#endregion
#region FolderBrowser Structs
[StructLayout(LayoutKind.Sequential)]
private struct BrowseInfo
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
[MarshalAs(UnmanagedType.LPTStr)]
public string displayname;
[MarshalAs(UnmanagedType.LPTStr)]
public string title;
public int flags;
[MarshalAs(UnmanagedType.FunctionPtr)]
public BrowseCallBackProc callback;
public IntPtr lparam;
}
#endregion
#region FolderBrowser UnManaged Methods
/// <summary>
/// A class that defines all the unmanaged methods used in the assembly
/// </summary>
private class UnManagedMethods
{
[DllImport("Shell32.dll", CharSet=CharSet.Auto)]
internal extern static System.IntPtr SHBrowseForFolder(ref BrowseInfo
bi);
[DllImport("Shell32.dll", CharSet=CharSet.Auto)]
[return : MarshalAs(UnmanagedType.Bool)]
internal extern static bool SHGetPathFromIDList(IntPtr pidl,
[MarshalAs(UnmanagedType.LPTStr)] System.Text.StringBuilder pszPath);
[DllImport("shell32", CharSet = CharSet.Auto)]
internal extern static int SHGetDesktopFolder(out IShellFolder ppshf);
[DllImport("User32.Dll")]
[return : MarshalAs(UnmanagedType.Bool)]
internal extern static bool SendMessage(IntPtr hwnd, int msg, IntPtr
wp, IntPtr lp);
[DllImport("shell32", CharSet = CharSet.Auto)]
internal extern static int SHGetMalloc(out IMalloc ppMalloc);
internal const int WM_USER = 0x0400;
internal const int BFFM_ENABLEOK = (WM_USER + 101);
internal const int BFFM_SETSELECTIONA = (WM_USER + 102);
internal const int BFFM_SETSELECTIONW = (WM_USER + 103);
internal const int BFFM_SETSTATUSTEXTA = (WM_USER + 100);
internal const int BFFM_SETSTATUSTEXTW = (WM_USER + 104);
internal const int BFFM_SETOKTEXT = (WM_USER + 105);
internal const int BFFM_SETEXPANDED = (WM_USER + 106);
internal const int BFFM_INITIALIZED = 1;
internal const int BFFM_SELCHANGED = 2;
internal const int BFFM_VALIDATEFAILEDA = 3;
internal const int BFFM_VALIDATEFAILEDW = 4;
internal const int BFFM_IUNKNOWN = 5;
internal const int WM_SYSCOMMAND = 0x112;
internal const int SC_CLOSE = 0xF060;
[DllImport("user32")]
internal extern static int GetWindowRect(
IntPtr hwnd,
ref RECT lpRect);
[DllImport("user32")]
internal extern static int SetWindowPos(
IntPtr hwnd,
IntPtr hWndInsertAfter,
int x,
int y,
int cx,
int cy,
int wFlags);
internal const int SWP_FRAMECHANGED = 0x20; // The frame
changed: send WM_NCCALCSIZE
internal const int SWP_HIDEWINDOW = 0x80;
internal const int SWP_NOACTIVATE = 0x10;
internal const int SWP_NOCOPYBITS = 0x100;
internal const int SWP_NOMOVE = 0x2;
internal const int SWP_NOOWNERZORDER = 0x200; // Don't do owner
Z ordering
internal const int SWP_NOREDRAW = 0x8;
internal const int SWP_NOSIZE = 0x1;
internal const int SWP_NOZORDER = 0x4;
internal const int SWP_SHOWWINDOW = 0x40;
}
#endregion
#region Private Enumerations
/// <summary>
/// Shell Folder Browser flags
/// </summary>
[Flags]
private enum BrowseFlags : int
{
BIF_RETURNONLYFSDIRS = 0x0001,
BIF_DONTGOBELOWDOMAIN = 0x0002,
BIF_STATUSTEXT = 0x0004,
BIF_RETURNFSANCESTORS = 0x0008,
BIF_EDITBOX = 0x0010,
BIF_VALIDATE = 0x0020,
BIF_NEWDIALOGSTYLE = 0x0040,
BIF_BROWSEINCLUDEURLS = 0x0080,
BIF_UAHINT = 0x0100,
BIF_NONEWFOLDERBUTTON = 0x0200,
BIF_BROWSEFORCOMPUTER = 0x1000,
BIF_BROWSEFORPRINTER = 0x2000,
BIF_BROWSEINCLUDEFILES = 0x4000,
BIF_SHAREABLE = 0x8000,
}
#endregion
#region Member Variables
private BrowseFlags flags = BrowseFlags.BIF_NEWDIALOGSTYLE |
BrowseFlags.BIF_RETURNFSANCESTORS;
private string statusText = "";
private bool displayed = false;
private bool okEnabled = true;
private string okButtonText = "";
private string selectedPath = "";
private string title = "";
private string rootPath = "";
private string initialPath = "";
private IntPtr handle = IntPtr.Zero;
private string displayName = "";
private SafePidl pidlReturned;
private FolderBrowserFilter filter = null;
#endregion
#region Events
/// <summary>
/// Fired when the dialog is initialized
/// </summary>
public event EventHandler Initialized;
/// <summary>
/// Fired when selection changes
/// </summary>
public event SelectionChangedEventHandler SelectionChanged;
/// <summary>
/// Fired when a TextBox is shown and the user chooses
/// OK but the Textbox contains an invalid filename or
/// path.
/// </summary>
public event ValidationFailedEventHandler ValidationFailed;
#endregion
#region Properties
/// <summary>
/// Gets/sets the filter object which can be used to filter
/// which items appear in the Folder Browser
/// </summary>
public FolderBrowserFilter Filter
{
get
{
return filter;
}
set
{
filter = value;
}
}
/// <summary>
/// Gets the handle of the Folder Browser dialog when it is
/// displayed.
/// </summary>
public IntPtr Handle
{
get
{
return handle;
}
}
/// <summary>
/// Gets/Sets the initially selected folder for the dialog.
/// </summary>
public string InitialPath
{
get
{
return initialPath;
}
set
{
initialPath = value;
}
}
/// <summary>
/// Gets/sets the string that is displayed above the
/// tree view control in the dialog box.
/// </summary>
public string Title
{
get
{
return title;
}
set
{
title = value;
}
}
/// <summary>
/// Gets/sets the root path for the dialog.
/// </summary>
public string RootPath
{
get
{
return rootPath;
}
set
{
rootPath = value;
}
}
private bool FlagSet(BrowseFlags flag)
{
return ((flags & flag) == flag);
}
private void FlagSet(BrowseFlags flag, bool value)
{
if (value)
{
flags |= flag;
}
else
{
flags &= ~flag;
}
}
/// <summary>
/// Gets/sets whether file system directories only are selectable.
/// If set, and the user selects a folder that is not part of the file
system,
/// the OK button is grayed.
/// </summary>
public bool FileSystemDirectoriesOnly
{
get
{
return FlagSet(BrowseFlags.BIF_RETURNONLYFSDIRS);
}
set
{
FlagSet(BrowseFlags.BIF_RETURNONLYFSDIRS, value);
}
}
/// <summary>
/// Gets/sets whether network folders below the domain level
/// are shown in the dialog box's tree view control.
/// </summary>
public bool ShowDomainNetworkFolders
{
get
{
return (FlagSet(BrowseFlags.BIF_DONTGOBELOWDOMAIN) ? false : true);
}
set
{
FlagSet(BrowseFlags.BIF_DONTGOBELOWDOMAIN, (value ? false : true));
}
}
/// <summary>
/// Gets/sets whether a status area is included in the dialog box.
/// The status text can be set using the StatusText property.
/// </summary>
public bool ShowStatusText
{
get
{
return FlagSet(BrowseFlags.BIF_STATUSTEXT);
}
set
{
FlagSet(BrowseFlags.BIF_STATUSTEXT, value);
}
}
/// <summary>
/// Gets/sets the status text shown in the status area. See
/// also ShowStatusText.
/// </summary>
public string StatusText
{
get
{
return statusText;
}
set
{
statusText = value;
if (displayed)
{
setStatusText();
}
}
}
private void setStatusText()
{
int msg = (Environment.OSVersion.Platform == PlatformID.Win32NT) ?
UnManagedMethods.BFFM_SETSTATUSTEXTW :
UnManagedMethods.BFFM_SETSTATUSTEXTA;
IntPtr strptr = Marshal.StringToHGlobalAuto(statusText);
UnManagedMethods.SendMessage(
handle,
msg,
IntPtr.Zero,
strptr);
Marshal.FreeHGlobal(strptr);
}
/// <summary>
/// Gets/sets whether file system ancestors only can be selected.
/// An ancestor is a subfolder that is beneath the root folder in the
/// namespace hierarchy. If set, and the user selects an ancestor of the
root
/// folder that is not part of the file system, the OK button is grayed.
/// </summary>
public bool FileSystemAncestorsOnly
{
get
{
return FlagSet(BrowseFlags.BIF_RETURNFSANCESTORS);
}
set
{
FlagSet(BrowseFlags.BIF_RETURNFSANCESTORS, value);
}
}
/// <summary>
/// Gets/sets whether to include an edit control in the browse dialog
/// box that allows the user to type the name of an item. Requires
/// IE4.0 or above.
/// </summary>
public bool ShowEditBox
{
get
{
return FlagSet(BrowseFlags.BIF_EDITBOX);
}
set
{
FlagSet(BrowseFlags.BIF_EDITBOX, value);
}
}
/// <summary>
/// Gets/sets whether the ValidateFailedEvent is called if the user has
typed an
/// invalid name into the edit box. Ignored if no EditBox.
/// </summary>
public bool ValidateEditBox
{
get
{
return FlagSet(BrowseFlags.BIF_VALIDATE);
}
set
{
FlagSet(BrowseFlags.BIF_VALIDATE, value);
}
}
/// <summary>
/// Gets/sets whether the new FolderBrowser user interface should be
used.
/// Setting this flag provides the user with a larger dialog box that can
/// be resized. The dialog box has several new capabilities including:
drag and
/// drop capability within the dialog box, reordering, shortcut menus,
/// new folders, delete, and other shortcut menu commands.
/// </summary>
public bool NewDialogStyle
{
get
{
return FlagSet(BrowseFlags.BIF_NEWDIALOGSTYLE);
}
set
{
FlagSet(BrowseFlags.BIF_NEWDIALOGSTYLE, value);
}
}
/// <summary>
/// Gets/sets whether to show URLs in folders which support browsing
/// for URLs.
/// </summary>
public bool IncludeUrls
{
get
{
return FlagSet(BrowseFlags.BIF_BROWSEINCLUDEURLS);
}
set
{
FlagSet(BrowseFlags.BIF_BROWSEINCLUDEURLS, value);
}
}
/// <summary>
/// Gets/sets whether a usage hint will be shown in the dialog
/// box in place of the edit box. ShowEditBox overrides this flag.
/// Only valid when NewDialogStyle is set.
/// </summary>
public bool ShowUsageHint
{
get
{
return FlagSet(BrowseFlags.BIF_UAHINT);
}
set
{
FlagSet(BrowseFlags.BIF_UAHINT, value);
}
}
/// <summary>
/// Do not include the "New Folder" button in the browse dialog box.
/// </summary>
public bool NoNewFolderButton
{
get
{
return FlagSet(BrowseFlags.BIF_NONEWFOLDERBUTTON);
}
set
{
FlagSet(BrowseFlags.BIF_NONEWFOLDERBUTTON, value);
}
}
/// <summary>
/// Gets/sets whether the dialog only return computers. When set, if the
/// user selects anything other than a computer, the OK button is grayed.
/// </summary>
public bool BrowseForComputer
{
get
{
return FlagSet(BrowseFlags.BIF_BROWSEFORCOMPUTER);
}
set
{
FlagSet(BrowseFlags.BIF_BROWSEFORCOMPUTER, value);
}
}
/// <summary>
/// Gets/sets whether the dialog only returns printers. When set, if the
/// user selects anything other than a printer, the OK button is grayed.
/// </summary>
public bool BrowseForPrinter
{
get
{
return FlagSet(BrowseFlags.BIF_BROWSEFORPRINTER);
}
set
{
FlagSet(BrowseFlags.BIF_BROWSEFORPRINTER, value);
}
}
/// <summary>
/// Gets/sets whether the browse dialog box will display files
/// as well as folders.
/// </summary>
public bool IncludeFiles
{
get
{
return FlagSet(BrowseFlags.BIF_BROWSEFORPRINTER);
}
set
{
FlagSet(BrowseFlags.BIF_BROWSEFORPRINTER, value);
}
}
/// <summary>
/// Gets/sets whether the browse dialog box displays shareable resources
/// on remote systems. It is intended for applications that want to
expose
/// remote shares on a local system. NewDialogStyle must also be set.
/// </summary>
public bool ShowRemoteShares
{
get
{
return FlagSet(BrowseFlags.BIF_SHAREABLE);
}
set
{
FlagSet(BrowseFlags.BIF_SHAREABLE, value);
}
}
/// <summary>
/// Gets/sets whether the OK button is enabled or not.
/// </summary>
public bool OkButtonEnabled
{
get
{
return okEnabled;
}
set
{
okEnabled = value;
if (displayed)
{
setEnableOkButton();
}
}
}
private void setEnableOkButton()
{
IntPtr lp = (okEnabled ? new IntPtr(1) : IntPtr.Zero);
UnManagedMethods.SendMessage(
handle,
UnManagedMethods.BFFM_ENABLEOK,
IntPtr.Zero,
lp);
}
/// <summary>
/// Gets/sets the selected path
/// </summary>
public string SelectedPath
{
get
{
return selectedPath;
}
set
{
selectedPath = value;
if (displayed)
{
setSelectedPath();
}
}
}
private void setSelectedPath()
{
int msg = (Environment.OSVersion.Platform == PlatformID.Win32NT) ?
UnManagedMethods.BFFM_SETSELECTIONA :
UnManagedMethods.BFFM_SETSELECTIONW;
IntPtr strptr = Marshal.StringToHGlobalAuto(selectedPath);
UnManagedMethods.SendMessage(
handle,
msg,
new IntPtr(1),
strptr);
Marshal.FreeHGlobal(strptr);
}
/// <summary>
/// Gets/sets the text on the OK Button in the dialog.
/// </summary>
public string OkButtonText
{
get
{
return okButtonText;
}
set
{
okButtonText = value;
setOkButtonText();
}
}
private void setOkButtonText()
{
IntPtr strptr = Marshal.StringToHGlobalUni(okButtonText);
UnManagedMethods.SendMessage(
handle,
UnManagedMethods.BFFM_SETOKTEXT,
new IntPtr(1),
strptr);
Marshal.FreeHGlobal(strptr);
}
#endregion
#region BrowseCallback
private int BrowseCallbackProc(
IntPtr hwnd,
int msg,
IntPtr lParam,
IntPtr lpData
)
{
int ret = 0;
switch(msg)
{
case UnManagedMethods.BFFM_INITIALIZED:
handle = hwnd;
if (lpData != IntPtr.Zero)
{ // lpData contains the PIDF:
int selMsg = (Environment.OSVersion.Platform ==
PlatformID.Win32NT) ?
UnManagedMethods.BFFM_SETSELECTIONA :
UnManagedMethods.BFFM_SETSELECTIONW;
UnManagedMethods.SendMessage(
hwnd,
selMsg,
System.IntPtr.Zero,
lpData);
}
if (okButtonText != null)
{
if (okButtonText.Trim().Length > 0)
{
setOkButtonText();
}
}
if (statusText != null)
{
if (statusText.Trim().Length > 0)
{
setStatusText();
}
}
if (Initialized != null)
{
Initialized(this, null);
}
break;
case UnManagedMethods.BFFM_IUNKNOWN:
// IFolderFilter only available under XP:
if ((filter != null) && (isXpOrAbove()))
{
// Check whether the user has asked to apply a filter:
if (filter.ApplyFilter)
{
// connect the filter:
if (lParam != IntPtr.Zero)
{
// lParam is the IUnknown interface:
Guid iidFolderFilterSite = new Guid(
"C0A651F5-B48B-11d2-B5ED-006097C686F6"); //
IID_IFolderFilterSite
IntPtr ptrFolderFilterSite = IntPtr.Zero;
Marshal.QueryInterface(
lParam,
ref iidFolderFilterSite,
out ptrFolderFilterSite);
if (ptrFolderFilterSite != IntPtr.Zero)
{
IFolderFilterSite folderFilterSite =
(IFolderFilterSite)Marshal.GetTypedObjectForIUnkno
wn(
ptrFolderFilterSite,
System.Type.GetType("IFolderFilterSite"));
BrowseItemFilter itemFilter = new
BrowseItemFilter(filter);
folderFilterSite.SetFilter(itemFilter);
}
}
}
}
break;
case UnManagedMethods.BFFM_SELCHANGED:
SafePidl pidl = new SafePidl(lParam, false);
selectedPath = pidl.Path;
if (SelectionChanged != null)
{
SelectionChangedEventArgs e = new
SelectionChangedEventArgs(pidl);
SelectionChanged(this, e);
}
break;
case UnManagedMethods.BFFM_VALIDATEFAILEDA:
if (ValidationFailed != null)
{
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
// platform SDK incorrectly states that the message
// is contained in lpData - it is in lParam
ValidationFailedEventArgs e = new
ValidationFailedEventArgs(
Marshal.PtrToStringAnsi(lParam));
ValidationFailed(this, e);
ret = (e.Cancel ? 0 : 1);
}
}
break;
case UnManagedMethods.BFFM_VALIDATEFAILEDW:
if (ValidationFailed != null)
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
// platform SDK incorrectly states that the message
// is contained in lpData - it is in lParam
ValidationFailedEventArgs e = new
ValidationFailedEventArgs(
Marshal.PtrToStringUni(lParam));
ValidationFailed(this, e);
ret = (e.Cancel ? 0 : 1);
}
}
break;
}
return ret;
}
#endregion BrowseCallback
#region Methods
/// <summary>
/// Shows the dialog
/// </summary>
/// <param name="owner">The window to use as the owner</param>
/// <returns></returns>
public DialogResult ShowDialog(System.Windows.Forms.IWin32Window owner)
{
if (handle != IntPtr.Zero)
throw new InvalidOperationException();
BrowseInfo bi = new BrowseInfo();
if (owner != null)
bi.hwndOwner = owner.Handle;
return showDialog(ref bi);
}
/// <summary>
/// Shows the dialog using active window as the owner
/// </summary>
public DialogResult ShowDialog()
{
return ShowDialog(Form.ActiveForm);
}
/// <summary>
/// Closes the folder browser dialog (if it is displayed)
/// </summary>
public void CloseDialog()
{
if (handle != IntPtr.Zero)
{
UnManagedMethods.SendMessage(
handle,
UnManagedMethods.WM_SYSCOMMAND,
(IntPtr)UnManagedMethods.SC_CLOSE,
IntPtr.Zero);
handle = IntPtr.Zero;
}
}
private DialogResult showDialog(ref BrowseInfo bi)
{
DialogResult dialogResult = DialogResult.Cancel;
// Initialise the BrowseInfo structure:
SafePidl pidlRoot = new SafePidl(rootPath);
SafePidl pidlInitial = new SafePidl(initialPath);
bi.title = title;
bi.displayname = new string('\0', 260);
bi.callback = new BrowseCallBackProc(this.BrowseCallbackProc);
bi.flags = (int)flags;
bi.pidlRoot = pidlRoot.Pidl;
bi.lparam = pidlInitial.Pidl;
// Do the folder browsing:
IntPtr pidl = UnManagedMethods.SHBrowseForFolder(ref bi);
if (pidl != IntPtr.Zero)
{
pidlReturned = new SafePidl(pidl, true);
displayName = bi.displayname;
dialogResult = DialogResult.OK;
}
//Reset the handle
handle = IntPtr.Zero;
// Clear up:
pidlRoot.Dispose();
pidlInitial.Dispose();
return dialogResult;
}
/// <summary>
/// Gets/sets the dialog position when it is shown
/// </summary>
public System.Drawing.Point Position
{
get
{
System.Drawing.Point pos = new System.Drawing.Point(0, 0);
if (this.handle != IntPtr.Zero)
{
RECT rcDialog = new RECT();
UnManagedMethods.GetWindowRect(this.handle, ref rcDialog);
pos.X = rcDialog.left;
pos.Y = rcDialog.top;
}
return pos;
}
set
{
if (this.handle != IntPtr.Zero)
{
UnManagedMethods.SetWindowPos(
this.handle,
IntPtr.Zero,
value.X,
value.Y,
0,
0,
UnManagedMethods.SWP_NOSIZE |
UnManagedMethods.SWP_NOOWNERZORDER |
UnManagedMethods.SWP_NOZORDER);
}
}
}
/// <summary>
/// Gets/sets the size of the dialog
/// </summary>
public System.Drawing.Size Size
{
get
{
System.Drawing.Size size = new System.Drawing.Size(0, 0);
if (this.Handle != IntPtr.Zero)
{
RECT rcDialog = new RECT();
UnManagedMethods.GetWindowRect(this.handle, ref rcDialog);
size.Width = rcDialog.right - rcDialog.left;
size.Height = rcDialog.bottom - rcDialog.top;
}
return size;
}
set
{
if (this.handle != IntPtr.Zero)
{
UnManagedMethods.SetWindowPos(
this.handle,
IntPtr.Zero,
0,
0,
value.Width,
value.Height,
UnManagedMethods.SWP_NOMOVE |
UnManagedMethods.SWP_NOOWNERZORDER |
UnManagedMethods.SWP_NOZORDER);
}
}
}
private bool isXpOrAbove()
{
bool ret = false;
if (Environment.OSVersion.Version.Major > 5)
{
ret = true;
}
else if ((Environment.OSVersion.Version.Major == 5) &&
(Environment.OSVersion.Version.Minor >= 1))
{
ret = true;
}
return ret;
}
#endregion Methods
#region Constructor and Destructor
/// <summary>
/// Releases any objects associated with the
/// FolderBrowser.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases any objects associated with the
/// FolderBrowser when disposing is true.
/// </summary>
/// <param name="disposing">Whether disposing or not</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (pidlReturned != null)
{
pidlReturned.Dispose();
pidlReturned = null;
}
Allocator a = new Allocator();
a.Dispose();
a = null;
}
}
/// <summary>
/// Constructs a new instance of the FolderBrowser
/// class
/// </summary>
public FolderBrowser()
{
filter = new FolderBrowserFilter();
}
#endregion
}
#endregion
}
|
|