How can I present a control to the user that allows him/her to select a directory?
There doesn't seem to be any native .net controls which do this?
string folderPath = "";
FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) {
folderPath = folderBrowserDialog1.SelectedPath ;
}
The FolderBrowserDialog class is the best option.
Note: there is no guarantee this code will work in future versions of the .Net framework. Using private .Net framework internals as done here through reflection is probably not good overall. Use the interop solution mentioned at the bottom, as the Windows API is less likely to change.
If you are looking for a Folder picker that looks more like the Windows 7 dialog, with the ability to copy and paste from a textbox at the bottom and the navigation pane on the left with favorites and common locations, then you can get access to that in a very lightweight way.
The FolderBrowserDialog UI is very minimal:
But you can have this instead:
Here's a class that opens a Vista-style folder picker using the .Net private IFileDialog interface, without directly using interop in the code (.Net takes care of that for you). It falls back to the pre-Vista dialog if not in a high enough Windows version. Should work in Windows 7, 8, 9, 10 and higher (theoretically).
using System;
using System.Reflection;
using System.Windows.Forms;
namespace MyCoolCompany.Shuriken {
/// <summary>
/// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions
/// </summary>
public class FolderSelectDialog {
private string _initialDirectory;
private string _title;
private string _fileName = "";
public string InitialDirectory {
get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
set { _initialDirectory = value; }
}
public string Title {
get { return _title ?? "Select a folder"; }
set { _title = value; }
}
public string FileName { get { return _fileName; } }
public bool Show() { return Show(IntPtr.Zero); }
/// <param name="hWndOwner">Handle of the control or window to be the parent of the file dialog</param>
/// <returns>true if the user clicks OK</returns>
public bool Show(IntPtr hWndOwner) {
var result = Environment.OSVersion.Version.Major >= 6
? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
: ShowXpDialog(hWndOwner, InitialDirectory, Title);
_fileName = result.FileName;
return result.Result;
}
private struct ShowDialogResult {
public bool Result { get; set; }
public string FileName { get; set; }
}
private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title) {
var folderBrowserDialog = new FolderBrowserDialog {
Description = title,
SelectedPath = initialDirectory,
ShowNewFolderButton = false
};
var dialogResult = new ShowDialogResult();
if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK) {
dialogResult.Result = true;
dialogResult.FileName = folderBrowserDialog.SelectedPath;
}
return dialogResult;
}
private static class VistaDialog {
private const string c_foldersFilter = "Folders|\n";
private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
private readonly static uint s_fosPickFoldersBitFlag = (uint) s_windowsFormsAssembly
.GetType("System.Windows.Forms.FileDialogNative+FOS")
.GetField("FOS_PICKFOLDERS")
.GetValue(null);
private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
.GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
.GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");
public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title) {
var openFileDialog = new OpenFileDialog {
AddExtension = false,
CheckFileExists = false,
DereferenceLinks = true,
Filter = c_foldersFilter,
InitialDirectory = initialDirectory,
Multiselect = false,
Title = title
};
var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint) s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);
try {
int retVal = (int) s_showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle });
return new ShowDialogResult {
Result = retVal == 0,
FileName = openFileDialog.FileName
};
}
finally {
s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
}
}
}
// Wrap an IWin32Window around an IntPtr
private class WindowWrapper : IWin32Window {
private readonly IntPtr _handle;
public WindowWrapper(IntPtr handle) { _handle = handle; }
public IntPtr Handle { get { return _handle; } }
}
}
}
I developed this as a cleaned up version of .NET Win 7-style folder select dialog by Bill Seddon of lyquidity.com (I have no affiliation). I wrote my own because his solution requires an additional Reflection class that isn't needed for this focused purpose, uses exception-based flow control, doesn't cache the results of its reflection calls. Note that the nested static VistaDialog class is so that its static reflection variables don't try to get populated if the Show method is never called.
It is used like so in a Windows Form:
var dialog = new FolderSelectDialog {
InitialDirectory = musicFolderTextBox.Text,
Title = "Select a folder to import music from"
};
if (dialog.Show(Handle)) {
musicFolderTextBox.Text = dialog.FileName;
}
You can of course play around with its options and what properties it exposes. For example, it allows multiselect in the Vista-style dialog.
Also, please note that Simon Mourier gave an answer that shows how to do the exact same job using interop against the Windows API directly, though his version would have to be supplemented to use the older style dialog if in an older version of Windows. Unfortunately, I hadn't found his post yet when I worked up my solution. Name your poison!
You could just use the FolderBrowserDialog class from the System.Windows.Forms namespace.
Please don't try and roll your own with a TreeView/DirectoryInfo class. For one thing there are many nice features you get for free (icons/right-click/networks) by using SHBrowseForFolder. For another there are a edge cases/catches you will likely not be aware of.
or even more better, you can put this code in a class file
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;
internal class OpenFolderDialog : IDisposable {
/// <summary>
/// Gets/sets folder in which dialog will be open.
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets/sets directory in which dialog will be open if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets selected folder.
/// </summary>
public string Folder { get; private set; }
internal DialogResult ShowDialog(IWin32Window owner) {
if (Environment.OSVersion.Version.Major >= 6) {
return ShowVistaDialog(owner);
} else {
return ShowLegacyDialog(owner);
}
}
private DialogResult ShowVistaDialog(IWin32Window owner) {
var frm = (NativeMethods.IFileDialog)(new NativeMethods.FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (this.InitialFolder != null) {
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.InitialFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK) {
frm.SetFolder(directoryShellItem);
}
}
if (this.DefaultFolder != null) {
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.DefaultFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK) {
frm.SetDefaultFolder(directoryShellItem);
}
}
if (frm.Show(owner.Handle) == NativeMethods.S_OK) {
NativeMethods.IShellItem shellItem;
if (frm.GetResult(out shellItem) == NativeMethods.S_OK) {
IntPtr pszString;
if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH, out pszString) == NativeMethods.S_OK) {
if (pszString != IntPtr.Zero) {
try {
this.Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
} finally {
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
return DialogResult.Cancel;
}
private DialogResult ShowLegacyDialog(IWin32Window owner) {
using (var frm = new SaveFileDialog()) {
frm.CheckFileExists = false;
frm.CheckPathExists = true;
frm.CreatePrompt = false;
frm.Filter = "|" + Guid.Empty.ToString();
frm.FileName = "any";
if (this.InitialFolder != null) { frm.InitialDirectory = this.InitialFolder; }
frm.OverwritePrompt = false;
frm.Title = "Select Folder";
frm.ValidateNames = false;
if (frm.ShowDialog(owner) == DialogResult.OK) {
this.Folder = Path.GetDirectoryName(frm.FileName);
return DialogResult.OK;
} else {
return DialogResult.Cancel;
}
}
}
public void Dispose() { } //just to have possibility of Using statement.
}
internal static class NativeMethods {
#region Constants
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;
#endregion
#region COM
[ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
internal class FileOpenDialogRCW { }
[ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog {
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig()]
uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
}
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
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);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
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);
}
#endregion
[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);
}
And use it like this
using (var frm = new OpenFolderDialog()) {
if (frm.ShowDialog(this)== DialogResult.OK) {
MessageBox.Show(this, frm.Folder);
}
}
Related
how to delete multi-items via C# or windows api, I have search for this for a long time and no solution. I used FolderItemVerb in Shell32.dll to delete file one by one, but it would pop a dialog at same time. I will be appreciated if you know how to solve this problem. Thank you.
It isn't for the faint of heart!
Code compatible with Windows >= Vista, no XP! The XP code is at the end
This is the first time I take a look at the Shell32 interfaces... Wow... Even the most simple things are complex :-) But then, COM is always complex... Now... There are 2.5 competing data structures/interfaces for manipulating files in Shell... IShellFolder (the old COM interface, not used in this sample), IShellItem (the new COM interface, used in this sample), IDLIST (here used as a PIDLIST_ABSOLUTE, used for "collecting" multiple files together. I count it as 0.5 😀). I hope there is no memory leak anywhere (always complex). Note that .NET will free COM objects automatically. I've even added some code that I've written to help me debug (like the code to get the list of verbs supported).
Now, here there are the COM interfaces plus some Shell32.dll PInvoke methods.
[StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_ABSOLUTE
{
public IntPtr Ptr;
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(int sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
[PreserveSig]
int Compare(IShellItem psi, uint hint, out int piOrder);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("70629033-e363-4a28-a567-0db78006e6d7")]
public interface IEnumShellItems
{
void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] IShellItem[] rgelt, out int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(out IEnumShellItems ppenum);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b63ea76d-1f85-456f-a19c-48159efa858b")]
public interface IShellItemArray
{
void BindToHandler(
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppvOut);
void GetPropertyStore(
uint flags,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetPropertyDescriptionList(
IntPtr keyType,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetAttributes(uint AttribFlags, uint sfgaoMask, out uint psfgaoAttribs);
void GetCount(out int pdwNumItems);
void GetItemAt(int dwIndex, out IShellItem ppsi);
void EnumItems(out IEnumShellItems ppenumShellItems);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e4-0000-0000-c000-000000000046")]
public interface IContextMenu
{
[PreserveSig]
int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, uint uFlags);
void InvokeCommand([In] ref CMINVOKECOMMANDINFOEX pici);
[PreserveSig]
int GetCommandString(UIntPtr idCmd, uint uType, IntPtr pReserved, IntPtr pszName, int cchMax);
}
[StructLayout(LayoutKind.Sequential)]
public struct CMINVOKECOMMANDINFOEX
{
public int cbSize;
public uint fMask;
public IntPtr hwnd;
// Non-unicode verbs (are there unicode verbs?)
[MarshalAs(UnmanagedType.LPStr)]
public string lpVerb;
[MarshalAs(UnmanagedType.LPStr)]
public string lpParameters;
[MarshalAs(UnmanagedType.LPStr)]
public string lpDirectory;
public int nShow;
public uint dwHotKey;
public IntPtr hIcon;
[MarshalAs(UnmanagedType.LPStr)]
public string lpTitle;
// Use CMIC_MASK_UNICODE
[MarshalAs(UnmanagedType.LPWStr)]
public string lpVerbW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpParametersW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpDirectoryW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpTitleW;
public int ptInvokeX;
public int ptInvokeY;
}
// Windows >= Vista
public static class ShellItemUtilities
{
public static readonly Guid FOLDERID_RecycleBinFolder = new Guid("b7534046-3ecb-4c18-be4e-64cd4cb7d6ac");
public static readonly Guid BHID_EnumItems = new Guid("94f60519-2850-4924-aa5a-d15e84868039");
public static readonly Guid BHID_SFUIObject = new Guid("3981e225-f559-11d3-8e3a-00c04f6837d5");
// From Windows 7
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetKnownFolderItem(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags,
IntPtr hToken,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IShellItem ppv);
// For Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHCreateItemFromIDList(PIDLIST_ABSOLUTE pidl, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);
// For Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetKnownFolderIDList(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags,
IntPtr hToken,
out PIDLIST_ABSOLUTE ppidl);
// From Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetIDListFromObject([MarshalAs(UnmanagedType.Interface)] object punk, out PIDLIST_ABSOLUTE ppidl);
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHCreateShellItemArrayFromIDLists(int cidl, [In] PIDLIST_ABSOLUTE[] rgpidl, out IShellItemArray ppsiItemArray);
public static IEnumerable<IShellItem> Enumerate(this IShellItem si)
{
object pesiTemp;
si.BindToHandler(IntPtr.Zero, BHID_EnumItems, typeof(IEnumShellItems).GUID, out pesiTemp);
var pesi = (IEnumShellItems)pesiTemp;
var items = new IShellItem[10];
while (true)
{
int fetched;
pesi.Next(1, items, out fetched);
if (fetched == 0)
{
break;
}
yield return items[0];
}
}
}
public static class ContextMenuUtilities
{
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern IntPtr CreateMenu();
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool DestroyMenu(IntPtr hMenu);
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern uint GetMenuItemID(IntPtr hMenu, int nPos);
[DllImport("User32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetMenuStringW", ExactSpelling = true, SetLastError = true)]
public static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out] StringBuilder lpString, int nMaxCount, uint uFlag);
public static string[] GetVerbs(IContextMenu cm, bool ansi = true)
{
IntPtr menu = IntPtr.Zero;
try
{
menu = CreateMenu();
// It isn't clear why short.MaxValue, but 0x7FFF is very used around the .NET!
int res = cm.QueryContextMenu(menu, 0, 0, short.MaxValue, 0);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
//var sb = new StringBuilder(128);
int count = GetMenuItemCount(menu);
var verbs = new List<string>(count);
var handle = default(GCHandle);
try
{
var bytes = new byte[ansi ? 128 : 256];
handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
for (int i = 0; i < count; i++)
{
uint id = GetMenuItemID(menu, i);
if (id == uint.MaxValue)
{
continue;
}
//GetMenuString(menu, (uint)i, sb, sb.Capacity, 0x00000400 /* MF_BYPOSITION */);
//string description = sb.ToString();
//sb.Clear();
res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000002 /* GCS_VALIDATEA */ : 0x00000006 /* GCS_VALIDATEW */, IntPtr.Zero, ptr, bytes.Length);
if (res < 0)
{
continue;
}
if (res == 0)
{
res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000000 /* GCS_VERBA */ : 0x00000004 /* GCS_VERBW */, IntPtr.Zero, ptr, bytes.Length);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
verbs.Add(ansi ? Marshal.PtrToStringAnsi(ptr) : Marshal.PtrToStringUni(ptr));
}
}
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
return verbs.ToArray();
}
finally
{
if (menu != IntPtr.Zero)
{
DestroyMenu(menu);
}
}
}
}
And then finally a small example program that uses it... It is a small console method that will list all the files that are present in the recycle bin, put 10 of them in an array and delete them in a single operation (verb). The SHGetKnownFolderItem is from Windows 7 on, so I'm using SHGetKnownFolderIDList + SHCreateItemFromIDList that are from Windows Vista.
The code here enumerates the IShellItem files contained in the recycle bin, saves their PIDL_ABSOLUTE in a List<>, from that List<> creates a IShellItemArray, on that IShellItemArray binds a IContextMenu, for that IContextMenu executes the delete verb. Clearly by adding/not adding all the PIDL_ABSOLUTE to the List<> you can control which files will be deleted.
private static void TestShellItem()
{
IShellItem recyleBin;
string str;
IntPtr ptr = IntPtr.Zero;
int res;
//// From Windows 7
//res = ShellItemUtilities.SHGetKnownFolderItem(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, typeof(IShellItem).GUID, out recyleBin);
//if (res < 0)
//{
// Marshal.ThrowExceptionForHR(res);
//}
// Windows >= Vista equivalent
var pidl = default(PIDLIST_ABSOLUTE);
try
{
res = ShellItemUtilities.SHGetKnownFolderIDList(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
res = ShellItemUtilities.SHCreateItemFromIDList(pidl, typeof(IShellItem).GUID, out recyleBin);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
}
finally
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
//// Example of use of GetDisplayName
//try
//{
// recyleBin.GetDisplayName(2, out ptr);
// str = Marshal.PtrToStringUni(ptr);
//}
//finally
//{
// if (ptr != IntPtr.Zero)
// {
// Marshal.FreeCoTaskMem(ptr);
// ptr = IntPtr.Zero;
// }
//}
var pids = new List<PIDLIST_ABSOLUTE>();
try
{
foreach (IShellItem si in recyleBin.Enumerate())
{
try
{
si.GetDisplayName(0, out ptr);
str = Marshal.PtrToStringUni(ptr);
// Some condition to include/exclude...
if (pids.Count < 10)
{
Console.WriteLine(str);
// Remember to free the pidl!
res = ShellItemUtilities.SHGetIDListFromObject(si, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
pids.Add(pidl);
}
}
finally
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(ptr);
ptr = IntPtr.Zero;
}
}
}
var pids2 = pids.ToArray();
IShellItemArray sia;
res = ShellItemUtilities.SHCreateShellItemArrayFromIDLists(pids2.Length, pids2, out sia);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
object cmTemp;
sia.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp);
var cm = (IContextMenu)cmTemp;
// To see verbs
//var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
var cmd = new CMINVOKECOMMANDINFOEX
{
cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
lpVerb = "delete",
};
cm.InvokeCommand(ref cmd);
}
finally
{
foreach (var pid in pids)
{
Marshal.FreeCoTaskMem(pid.Ptr);
}
}
//// Verb executed one by one
//foreach (var item in recyleBin.Enumerate())
//{
// object cmTemp;
// item.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp);
// var cm = (IContextMenu)cmTemp;
////// To see verbs
//// var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//// var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
// var cmd = new CMINVOKECOMMANDINFOEX
// {
// cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
// fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
// lpVerb = "delete",
// };
// cm.InvokeCommand(ref cmd);
//}
}
Code for Windows XP, uses some code from the other version, you have to take what is needed
It uses the IShellFolder interface. Note that the IContextMenu handling is exactly the same.
[StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_RELATIVE
{
public IntPtr Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct LPITEMIDLIST
{
public IntPtr Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct PITEMID_CHILD
{
public IntPtr Ptr;
}
public enum STRRET_TYPE
{
WSTR = 0,
OFFSET = 0x1,
CSTR = 0x2
};
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 268)]
public sealed class STRRET : IDisposable
{
public STRRET_TYPE uType;
public IntPtr pOleStr;
[DllImport("Shlwapi.dll", ExactSpelling = true, SetLastError = false)]
private static extern int StrRetToBSTR(STRRET pstr, PITEMID_CHILD pidl, [MarshalAs(UnmanagedType.BStr)] out string pbstr);
~STRRET()
{
Dispose(false);
}
public override string ToString()
{
return ToString(default(PITEMID_CHILD));
}
public string ToString(PITEMID_CHILD pidl)
{
if (uType == STRRET_TYPE.WSTR)
{
if (pOleStr == IntPtr.Zero)
{
return null;
}
string str = Marshal.PtrToStringUni(pOleStr);
return str;
}
else
{
string str;
int res = StrRetToBSTR(this, pidl, out str);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
return str;
}
}
#region IDisposable Support
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
private void Dispose(bool disposing)
{
Marshal.FreeCoTaskMem(pOleStr);
pOleStr = IntPtr.Zero;
}
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e6-0000-0000-c000-000000000046")]
public interface IShellFolder
{
void ParseDisplayName(
IntPtr hwnd,
IntPtr pbc,
[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
out int pchEaten,
out PIDLIST_RELATIVE ppidl,
ref uint pdwAttributes);
void EnumObjects(IntPtr hwnd, uint grfFlags, out IEnumIDList ppenumIDList);
void BindToObject(
PIDLIST_RELATIVE pidl,
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void BindToStorage(
PIDLIST_RELATIVE pidl,
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
[PreserveSig]
int CompareIDs(IntPtr lParam, PIDLIST_RELATIVE pidl1, PIDLIST_RELATIVE pidl2);
void CreateViewObject(
IntPtr hwndOwner,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetAttributesOf(
int cidl,
[In, MarshalAs(UnmanagedType.LPArray)] LPITEMIDLIST[] apidl,
ref uint rgfInOut);
void GetUIObjectOf(
IntPtr hwndOwner,
int cidl,
[In, MarshalAs(UnmanagedType.LPArray)] PITEMID_CHILD[] apidl,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
IntPtr rgfReserved,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetDisplayNameOf(
PITEMID_CHILD pidl,
uint uFlags,
STRRET pName);
void SetNameOf(
IntPtr hwnd,
PITEMID_CHILD pidl,
[MarshalAs(UnmanagedType.LPWStr)] string pszName,
uint uFlags,
out PITEMID_CHILD ppidlOut);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214f2-0000-0000-c000-000000000046")]
public interface IEnumIDList
{
void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] PITEMID_CHILD[] rgelt, out int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(out IEnumIDList ppenum);
}
// Windows >= XP
public static class ShellFolderUtilities
{
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out PIDLIST_ABSOLUTE ppidl);
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetDesktopFolder(out IShellFolder ppshf);
public static readonly int CSIDL_DESKTOP = 0x0000;
public static readonly int CSIDL_BITBUCKET = 0x000a;
// https://blogs.msdn.microsoft.com/oldnewthing/20110830-00/?p=9773
public static void BindToCsidl(int csidl, Guid riid, out object ppv)
{
var pidl = default(PIDLIST_ABSOLUTE);
try
{
int res;
if (csidl != CSIDL_DESKTOP)
{
res = SHGetSpecialFolderLocation(IntPtr.Zero, csidl, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
}
IShellFolder psfDesktop;
res = SHGetDesktopFolder(out psfDesktop);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
if (csidl == CSIDL_DESKTOP)
{
ppv = psfDesktop;
return;
}
psfDesktop.BindToObject(new PIDLIST_RELATIVE { Ptr = pidl.Ptr }, IntPtr.Zero, riid, out ppv);
}
finally
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
}
public static IEnumerable<PITEMID_CHILD> Enumerate(this IShellFolder sf)
{
IEnumIDList ppenumIDList;
sf.EnumObjects(IntPtr.Zero, 0x00020 /* SHCONTF_FOLDERS */ | 0x00040 /* SHCONTF_NONFOLDERS */, out ppenumIDList);
if (ppenumIDList == null)
{
yield break;
}
var items = new PITEMID_CHILD[1];
while (true)
{
int fetched;
ppenumIDList.Next(items.Length, items, out fetched);
if (fetched == 0)
{
break;
}
yield return items[0];
}
}
}
And then finally a small example program that uses it...
private static void TestShellFolder()
{
object recycleBinTemp;
ShellFolderUtilities.BindToCsidl(ShellFolderUtilities.CSIDL_BITBUCKET, typeof(IShellFolder).GUID, out recycleBinTemp);
var recycleBin = (IShellFolder)recycleBinTemp;
var pids = new List<PITEMID_CHILD>();
try
{
foreach (PITEMID_CHILD pidl in recycleBin.Enumerate())
{
// Remember to free the pidl!
string str;
using (var ret = new STRRET { uType = STRRET_TYPE.CSTR })
{
recycleBin.GetDisplayNameOf(pidl, 0, ret);
str = ret.ToString(pidl);
}
// Some condition to include/exclude...
if (pids.Count < 10)
{
Console.WriteLine(str);
pids.Add(pidl);
}
else
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
}
var pids2 = pids.ToArray();
object cmTemp;
recycleBin.GetUIObjectOf(IntPtr.Zero, pids2.Length, pids2, typeof(IContextMenu).GUID, IntPtr.Zero, out cmTemp);
var cm = (IContextMenu)cmTemp;
// To see verbs
//var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
var cmd = new CMINVOKECOMMANDINFOEX
{
cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
lpVerb = "delete",
};
cm.InvokeCommand(ref cmd);
}
finally
{
foreach (var pid in pids)
{
Marshal.FreeCoTaskMem(pid.Ptr);
}
}
}
First of all add System.Runtime.InteropService to your project. We will use SHEmptyRecycleBin method, which accepts 3 parameters.
After that import the Shell32.dll in your class by using DllImport.
[DllImport("Shell32.dll")]
static extern int SHEmptyRecycleBin(IntPtr hwnd, string pszRootPath, RecycleFlag dwFlags);
Then define an enum for the RecycleBin flags(dwFlags). The values are in Hexadecimal.
enum RecycleFlag : int
{
SHERB_NOCONFIRMATION = 0x00000001, // No confirmation
SHERB_NOPROGRESSUI = 0x00000001, // No progress tracking window
SHERB_NOSOUND = 0x00000004 // No sound played
}
Place the following code in empty recycle bin button which calls the system method in Shell32.dll as:
SHEmptyRecycleBin(IntPtr.Zero, null, RecycleFlag.SHERB_NOSOUND | RecycleFlag.SHERB_NOCONFIRMATION);
reference: here
In my application, I want the folderBrowserDialog to allow selection of My Computer. But the OK button gets disabled after selecting My Computer from the dialog box.
Is there any way to allow the selection of My Computer in Browse Dialog?
My Computer (or This PC in more recent Windows versions) is a special folder (not a file system folder), and the standard FolderBrowserDialog class does not support it.
Here is a replacement sample FolderBrowser class that allows the user to select any folder. This is an example that uses it in a Windows form app:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// other special GUIDs are defined in Windows SDK's ShlGuid.h
Guid CLSID_MyComputer = new Guid("20D04FE0-3AEA-1069-A2D8-08002B30309D");
FolderBrowser dlg = new FolderBrowser();
dlg.Title = "Choose any folder you want";
// optionally uncomment the following line to start from a folder
//dlg.SelectedPath = #"c:\temp";
// optionally uncomment the following line to start from My Computer/This PC
//dlg.SelectedDesktopAbsoluteParsing = "::" + CLSID_MyComputer.ToString("B");
if (dlg.ShowDialog(null) == DialogResult.OK)
{
MessageBox.Show(dlg.SelectedDesktopAbsoluteParsing + Environment.NewLine +
dlg.SelectedNormalDisplay + Environment.NewLine +
dlg.SelectedPath + Environment.NewLine +
dlg.SelectedUrl);
if (dlg.SelectedDesktopAbsoluteParsing == "::" + CLSID_MyComputer.ToString("B").ToUpperInvariant())
{
MessageBox.Show("My Computer was selected!");
}
}
}
}
And at the bottom of this answer you'll find the FolderBrowser replacement class. The interesting part is this line:
dialog.SetOptions(FOS.FOS_PICKFOLDERS | FOS.FOS_ALLNONSTORAGEITEMS);
which will instruct the code to pick only folders and allow non file system items.
For normal folders, the returned SelectedPath property will contain the folder path. For special folders without a storage, it will be empty.
But the shell provides us a canonical moniker that contains the folder path for normal folders and a special values for other folders that will be defined in the SelectedDesktopAbsoluteParsing property.
In the case of My Computer, the value will always be "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}".
This special syntax is somewhat defined officially here: Specifying a Namespace Extension's Location.
public class FolderBrowser
{
public string SelectedPath { get; set; }
public string SelectedDesktopAbsoluteParsing { get; set; }
public string Title { get; set; }
public string SelectedNormalDisplay { get; private set; }
public string SelectedUrl { get; private set; }
public DialogResult ShowDialog(IWin32Window owner)
{
var dialog = (IFileOpenDialog)new FileOpenDialog();
if (!string.IsNullOrEmpty(SelectedPath))
{
SelectInitialPath(dialog, SelectedPath);
}
else if (!string.IsNullOrEmpty(SelectedDesktopAbsoluteParsing))
{
SelectInitialPath(dialog, SelectedDesktopAbsoluteParsing);
}
if (!string.IsNullOrWhiteSpace(Title))
{
dialog.SetTitle(Title);
}
dialog.SetOptions(FOS.FOS_PICKFOLDERS | FOS.FOS_ALLNONSTORAGEITEMS);
uint hr = dialog.Show(owner != null ? owner.Handle : IntPtr.Zero);
if (hr == ERROR_CANCELLED)
return DialogResult.Cancel;
if (hr != 0)
return DialogResult.Abort;
dialog.GetResult(out IShellItem result);
SelectedPath = GetDisplayName(result, SIGDN.SIGDN_FILESYSPATH);
SelectedNormalDisplay = GetDisplayName(result, SIGDN.SIGDN_NORMALDISPLAY);
SelectedDesktopAbsoluteParsing = GetDisplayName(result, SIGDN.SIGDN_DESKTOPABSOLUTEPARSING);
SelectedUrl = GetDisplayName(result, SIGDN.SIGDN_URL);
return DialogResult.OK;
}
private static string GetDisplayName(IShellItem item, SIGDN sigdnName)
{
item.GetDisplayName(sigdnName, out var ptr);
var name = Marshal.PtrToStringUni(ptr);
Marshal.FreeCoTaskMem(ptr);
return name;
}
private void SelectInitialPath(IFileOpenDialog dialog, string path)
{
uint atts = 0;
IntPtr idl = IntPtr.Zero;
if (SHILCreateFromPath(path, out idl, ref atts) == 0)
{
if (SHCreateShellItem(IntPtr.Zero, IntPtr.Zero, idl, out IShellItem initial) == 0)
{
dialog.SetFolder(initial);
}
Marshal.FreeCoTaskMem(idl);
}
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHILCreateFromPath(string pszPath, out IntPtr ppIdl, ref uint rgflnOut);
[DllImport("shell32.dll")]
private static extern int SHCreateShellItem(IntPtr pidlParent, IntPtr psfParent, IntPtr pidl, out IShellItem ppsi);
private const uint ERROR_CANCELLED = 0x800704C7;
[ComImport]
[Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")]
private class FileOpenDialog
{
}
[Guid("42f85136-db7e-439c-85f1-e4075d135fc8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IFileOpenDialog
{
[PreserveSig]
uint Show(IntPtr parent); // IModalWindow
void SetFileTypes(); // not fully defined
void SetFileTypeIndex(uint iFileType);
void GetFileTypeIndex(out uint piFileType);
void Advise(); // not fully defined
void Unadvise();
void SetOptions(FOS fos);
void GetOptions(out FOS pfos);
void SetDefaultFolder(IShellItem psi);
void SetFolder(IShellItem psi);
void GetFolder(out IShellItem ppsi);
void GetCurrentSelection(out IShellItem ppsi);
void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
void GetFileName(out IntPtr pszName);
void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
void GetResult(out IShellItem ppsi);
void AddPlace(IShellItem psi, int alignment);
void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
void Close(int hr);
void SetClientGuid(); // not fully defined
void ClearClientData();
void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
void GetResults([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenum); // not fully defined
void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppsai); // not fully defined
}
[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IShellItem
{
void BindToHandler(); // not fully defined
void GetParent(); // not fully defined
[PreserveSig]
int GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
void GetAttributes(); // not fully defined
void Compare(); // not fully defined
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762544.aspx
private enum SIGDN : uint
{
SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
SIGDN_FILESYSPATH = 0x80058000,
SIGDN_NORMALDISPLAY = 0,
SIGDN_PARENTRELATIVE = 0x80080001,
SIGDN_PARENTRELATIVEEDITING = 0x80031001,
SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001,
SIGDN_PARENTRELATIVEPARSING = 0x80018001,
SIGDN_URL = 0x80068000
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282.aspx
[Flags]
private enum FOS
{
FOS_ALLNONSTORAGEITEMS = 0x80,
FOS_ALLOWMULTISELECT = 0x200,
FOS_CREATEPROMPT = 0x2000,
FOS_DEFAULTNOMINIMODE = 0x20000000,
FOS_DONTADDTORECENT = 0x2000000,
FOS_FILEMUSTEXIST = 0x1000,
FOS_FORCEFILESYSTEM = 0x40,
FOS_FORCESHOWHIDDEN = 0x10000000,
FOS_HIDEMRUPLACES = 0x20000,
FOS_HIDEPINNEDPLACES = 0x40000,
FOS_NOCHANGEDIR = 8,
FOS_NODEREFERENCELINKS = 0x100000,
FOS_NOREADONLYRETURN = 0x8000,
FOS_NOTESTFILECREATE = 0x10000,
FOS_NOVALIDATE = 0x100,
FOS_OVERWRITEPROMPT = 2,
FOS_PATHMUSTEXIST = 0x800,
FOS_PICKFOLDERS = 0x20,
FOS_SHAREAWARE = 0x4000,
FOS_STRICTFILETYPES = 4
}
}
The documentation says:
If the user selects a folder that
does not have a physical path (for example, My Computer),
the OK button on the dialog box will be disabled.
You ask:
Is there any way to enable the OK button for My Computer?
There is not.
There is a possibility:
Using the function:
[StructLayout(LayoutKind.Sequential)]
public struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
//public IntPtr pszDisplayName;
public string pszDisplayName;
public string lpszTitle;
public uint ulFlags;
public BrowseCallbackProc lpfn;
public IntPtr lParam;
public int iImage;
}
[DllImport("shell32.dll")]
public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi);
[DllImport("shell32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SHGetPathFromIDListW(IntPtr pidl, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszPath);
[DllImport("shell32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SHGetPathFromIDListW(IntPtr pidl, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszPath);
The call back can be set to:
private int _callback(IntPtr hDlg, int msg, IntPtr lParam, IntPtr lpData)
{
switch (msg)
{
case 2://BFFM_SELCHANGED:
StringBuilder sb1 = new StringBuilder();
Win32.SHGetPathFromIDListW((IntPtr)lParam, sb);
Win32.EnableWindow(Win32.GetDlgItem(hDlg, CtlIds.IDOK), true);
break;
}
return 0;
}
Call the:
BROWSEINFO bi = new Win32.BROWSEINFO();
bi.lpfn = new Win32.BrowseCallbackProc(callback);
string selected = SHBrowseForFolder(ref bi);
The OK will be clickable.
The only problem that I have not yet foundout, is how to be sure that my computer is selected.
Some sources were obtained from:
http://www.codeproject.com/Articles/159352/FolderBrowserDialogEx-A-C-customization-of-FolderB
The FolderBrowserDialog does allow me to browse computers on the network, but it displays other unnecessary folders (I don't want local folders). Also, I don't want to have to select a folder - just the computer name.
Simple:
private void button1_Click(object sender, EventArgs e)
{
var folderName = GetNetworkFolders(new FolderBrowserDialog());
}
private string GetNetworkFolders(FolderBrowserDialog oFolderBrowserDialog)
{
Type type = oFolderBrowserDialog.GetType();
FieldInfo fieldInfo = type.GetField("rootFolder", BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(oFolderBrowserDialog, 18);
if (oFolderBrowserDialog.ShowDialog() == DialogResult.OK)
{
return oFolderBrowserDialog.SelectedPath.ToString();
}
else
{
return "";
}
}
ComputerBrowser.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class ComputerBrowser
{
private FolderBrowserFolder _startLocation = FolderBrowserFolder.NetworkNeighborhood;
private BrowseInfos _options = BrowseInfos.BrowseForComputer;
private static readonly int MAX_PATH;
private string _title;
private string _displayName;
private string _path;
static ComputerBrowser()
{
MAX_PATH = 260;
}
public bool ShowDialog()
{
return ShowDialog(null);
}
public bool ShowDialog(IWin32Window owner)
{
_path = string.Empty;
IntPtr handle;
IntPtr zero = IntPtr.Zero;
if (owner != null)
handle = owner.Handle;
else
handle = UnmanagedMethods.GetActiveWindow();
UnmanagedMethods.SHGetSpecialFolderLocation(handle, (int)_startLocation, ref zero);
if (zero == IntPtr.Zero)
return false;
int num = (int)_options;
if ((num & 0x40) != 0)
Application.OleRequired();
IntPtr pidl = IntPtr.Zero;
try
{
BrowseInfo lpbi = new BrowseInfo();
//IntPtr pszPath = Marshal.AllocHGlobal(MAX_PATH);
lpbi.pidlRoot = zero;
lpbi.hwndOwner = handle;
lpbi.displayName = new string('\0', MAX_PATH);
lpbi.title = _title;
lpbi.flags = num;
lpbi.callback = null;
lpbi.lparam = IntPtr.Zero;
pidl = UnmanagedMethods.SHBrowseForFolder(ref lpbi);
if (pidl == IntPtr.Zero)
return false;
_displayName = lpbi.displayName;
StringBuilder pathReturned = new StringBuilder(MAX_PATH);
UnmanagedMethods.SHGetPathFromIDList(pidl, pathReturned);
_path = pathReturned.ToString();
UnmanagedMethods.SHMemFree(pidl);
}
finally
{
UnmanagedMethods.SHMemFree(zero);
}
return true;
}
protected enum FolderBrowserFolder
{
Desktop = 0,
Favorites = 6,
MyComputer = 0x11,
MyDocuments = 5,
MyPictures = 0x27,
NetAndDialUpConnections = 0x31,
NetworkNeighborhood = 0x12,
Printers = 4,
Recent = 8,
SendTo = 9,
StartMenu = 11,
Templates = 0x15
}
[Flags]
public enum BrowseInfos
{
AllowUrls = 0x80,
BrowseForComputer = 0x1000,
BrowseForEverything = 0x4000,
BrowseForPrinter = 0x2000,
DontGoBelowDomain = 2,
ShowTextBox = 0x10,
NewDialogStyle = 0x40,
RestrictToSubfolders = 8,
RestrictToFilesystem = 1,
ShowShares = 0x8000,
StatusText = 4,
UseNewUI = 80,
Validate = 0x20
}
public static string GetComputerName(string title)
{
ComputerBrowser browser = new ComputerBrowser();
browser._title = title;
if (browser.ShowDialog())
return browser._displayName;
else
return string.Empty;
}
}
Unmanaged.cs:
using System;
using System.Runtime.InteropServices;
namespace ActivityMonitor.Monitor.Utils
{
internal delegate int BrowseCallBackProc(IntPtr hwnd, int msg, IntPtr lp, IntPtr wp);
[StructLayout(LayoutKind.Sequential)]
internal 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;
}
[ComImport]
[Guid("00000002-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMalloc
{
[PreserveSig]
IntPtr Alloc(IntPtr cb);
[PreserveSig]
IntPtr Realloc(IntPtr pv, IntPtr cb);
[PreserveSig]
void Free(IntPtr pv);
[PreserveSig]
IntPtr GetSize(IntPtr pv);
[PreserveSig]
int DidAlloc(IntPtr pv);
[PreserveSig]
void HeapMinimize();
}
/// <summary>
/// A class that defines all the unmanaged methods used in the assembly
/// </summary>
internal 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("User32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal extern static bool SendMessage(IntPtr hwnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("Shell32.dll")]
internal extern static int SHGetMalloc([MarshalAs(UnmanagedType.IUnknown)]out object shmalloc);
[DllImport("user32.dll")]
internal extern static IntPtr GetActiveWindow();
[DllImport("shell32.dll")]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, ref IntPtr ppidl);
//Helper routine to free memory allocated using shells malloc object
internal static void SHMemFree(IntPtr ptr)
{
object shmalloc = null;
if (SHGetMalloc(out shmalloc) == 0)
{
IMalloc malloc = (IMalloc)shmalloc;
(malloc).Free(ptr);
}
}
}
}
From: FolderBrowserDialog Unmasked: Everything You Wanted To Know About The Folder Browser Component From .Net Framework
No Filtering
The FolderBrowserDialog has no support for filtering. For example, it
is not possible to display only network folders or only shared folders
or only folders starting with the string "Documents" or files having a
particular extension.
try using the openFileDialog and setup your filters.
Found the answer:
The ComputerBrowserDialog
http://discoveringdotnet.alexeyev.org/2008/04/how-to-browse-for-computer-name.html
I tweeked it a bit to behave more like the FolderBrowserDialog (only took a few min). Works just how I want it to.
I wanted to add custom properties for my application file type, just like Microsoft Word file tyep .docx has properties on Details Pane in vista and window 7 that show author property and e.t.c trying to do the same for my application but have no clue yet. working in .net2.0 .i dont know what i am doing wrong,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Win32;
namespace TestShell
{
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b7d14566-0509-4cce-a71f-0a554233bd9b")]
interface IInitializeWithFile
{
[PreserveSig]
int Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, uint grfMode);
}
[StructLayout(LayoutKind.Sequential)]
public struct PROPERTYKEY
{
public Guid fmtid;
public UIntPtr pid;
}
[ComImport]
[Guid("c8e2d566-186e-4d49-bf41-6909ead56acc")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStoreCapabilities
{
[PreserveSig]
int IsPropertyWritable([In] ref PROPERTYKEY key);
}
[ComImport]
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStore
{
[PreserveSig]
int GetCount([Out] out uint cProps);
[PreserveSig]
int GetAt([In] uint iProp, out PROPERTYKEY pkey);
[PreserveSig]
int GetValue([In] ref PROPERTYKEY key, out PropVariant pv);
[PreserveSig]
int SetValue([In] ref PROPERTYKEY key, [In] ref object pv);
[PreserveSig]
int Commit();
}
[StructLayout(LayoutKind.Sequential)]
public struct PropVariant
{
public short variantType;
public short Reserved1, Reserved2, Reserved3;
public IntPtr pointerValue;
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("TestShell.PropertyHandler")]
[Guid("9BC59AF4-41E3-49B1-9A62-17F4C92D081F")]
public class PropertyHandler : IInitializeWithFile, IPropertyStore, IPropertyStoreCapabilities
{
private const int S_OK = 0, S_FALSE = 1;
private string path = null;
public int Initialize(string pszFilePath, uint grfMode)
{
System.Windows.Forms.MessageBox.Show(pszFilePath);
path = pszFilePath;
return S_OK;
}
public int IsPropertyWritable(ref PROPERTYKEY key)
{
System.Windows.Forms.MessageBox.Show("Writable");
return S_OK;
}
public int GetCount(out uint cProps)
{
System.Windows.Forms.MessageBox.Show("GetCount");
cProps = 1;
return S_OK;
}
public int GetAt(uint iProp, out PROPERTYKEY pkey)
{
System.Windows.Forms.MessageBox.Show(iProp.ToString());
pkey = new PROPERTYKEY();
pkey.fmtid = PKEY_Title;
pkey.pid = (UIntPtr)0x2;
return S_OK;
}
private Guid PKEY_Title = new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9");
public int GetValue(ref PROPERTYKEY key, out PropVariant pv)
{
System.Windows.Forms.MessageBox.Show(key.fmtid.ToString());
pv = new PropVariant();
if (key.fmtid == PKEY_Title) {
pv.variantType = 31;
pv.pointerValue = Marshal.StringToHGlobalUni("Test");
return S_OK;
} else {
pv.variantType = 0; //VT_EMPTY
pv.pointerValue = IntPtr.Zero;
return S_OK;
}
}
public int SetValue(ref PROPERTYKEY key, ref object pv)
{
return S_OK;
}
public int Commit()
{
return S_OK;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type t)
{
try {
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR = regHKCR.CreateSubKey(".test");
regHKCR.SetValue(null, "TestShell.PropertyHandler");
regHKCR = Registry.ClassesRoot;
regHKCR = regHKCR.CreateSubKey("CLSID\\{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
regHKCR.SetValue(null, "Test Property");
regHKCR.SetValue("ManualSafeSave", 1);
regHKCR = regHKCR.CreateSubKey("InProcServer32");
regHKCR.SetValue(null, System.Reflection.Assembly.GetExecutingAssembly().Location);
regHKCR.SetValue("ThreadingModel", "Apartment");
RegistryKey regHKLM;
regHKLM = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\.test");
regHKLM.SetValue(null, "{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
regHKLM = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved");
regHKLM.SetValue("{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}", "Test Property");
} catch (Exception ex) {
#if DEBUG
System.Windows.Forms.MessageBox.Show(ex.Message + System.Environment.NewLine + ex.StackTrace);
#endif
}
#if DEBUG
//SHShellRestart();
#endif
}
[ComUnregisterFunctionAttribute]
public static void UnRegisterFunction(Type t)
{
try {
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR.DeleteSubKey(".test");
regHKCR.DeleteSubKeyTree("CLSID\\{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
RegistryKey regHKLM = Registry.LocalMachine;
regHKLM.DeleteSubKeyTree("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\.test");
regHKLM = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", true);
regHKLM.DeleteValue("{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
} catch (Exception ex) {
#if DEBUG
System.Windows.Forms.MessageBox.Show(ex.Message + System.Environment.NewLine + ex.StackTrace);
#endif
}
#if DEBUG
//SHShellRestart();
#endif
}
#if DEBUG
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("shell32.dll")]
static extern IntPtr ShellExecute(
IntPtr hwnd, string lpOperation, string lpFile,
string lpParameters, string lpDirectory, int nShowCmd);
private static void SHShellRestart()
{
PostMessage(FindWindow("Progman", null), 0x0012, IntPtr.Zero, IntPtr.Zero);
ShellExecute(IntPtr.Zero, null, "explorer.exe", null, null, 5);
return;
}
#endif
}
}
do i need to instatiate the propert handler class too. if yes than how should i do it, any ideas someone, i have been stuck here for 3 days now.
when i register this dll the property handler gets registered but no custom property appears on the .test file.
i have managed to register my property handler as COM and explorer is calling my code when i click on file tyep (.test) against whcih i am trying to custom add properties. Below is the code, now the only thing left is to somehow create new properties, i have no idea how to create new properties, any help is appreciated
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Win32;
using System.Windows.Forms;
namespace TestShell
{
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b7d14566-0509-4cce-a71f-0a554233bd9b")]
interface IInitializeWithFile
{
[PreserveSig]
int Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, uint grfMode);
}
[StructLayout(LayoutKind.Sequential)]
public struct PROPERTYKEY
{
public Guid fmtid;
public UIntPtr pid;
}
[ComImport]
[Guid("c8e2d566-186e-4d49-bf41-6909ead56acc")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStoreCapabilities
{
[PreserveSig]
int IsPropertyWritable([In] ref PROPERTYKEY key);
}
[ComImport]
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStore
{
[PreserveSig]
int GetCount([Out] out uint cProps);
[PreserveSig]
int GetAt([In] uint iProp, out PROPERTYKEY pkey);
[PreserveSig]
int GetValue([In] ref PROPERTYKEY key, out PropVariant pv);
[PreserveSig]
int SetValue([In] ref PROPERTYKEY key, [In] ref object pv);
[PreserveSig]
int Commit();
}
[StructLayout(LayoutKind.Sequential)]
public struct PropVariant
{
public short variantType;
public short Reserved1, Reserved2, Reserved3;
public IntPtr pointerValue;
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("TestShell.PropertyHandler")]
[Guid("9BC59AF4-41E3-49B1-9A62-17F4C92D081F")]
public class PropertyHandler : IInitializeWithFile, IPropertyStore, IPropertyStoreCapabilities
{
private const int S_OK = 0, S_FALSE = 1;
private string path = null;
public int Initialize(string pszFilePath, uint grfMode)
{
//System.Windows.Forms.MessageBox.Show(pszFilePath);
path = pszFilePath;
return S_OK;
}
public int IsPropertyWritable(ref PROPERTYKEY key)
{
//System.Windows.Forms.MessageBox.Show("Writable");
return S_OK;
}
public int GetCount(out uint cProps)
{
//System.Windows.Forms.MessageBox.Show("GetCount");
cProps = 1;
return S_OK;
}
public int GetAt(uint iProp, out PROPERTYKEY pkey)
{
System.Windows.Forms.MessageBox.Show(iProp.ToString());
pkey = new PROPERTYKEY();
pkey.fmtid = PKEY_Title;
pkey.pid = (UIntPtr)0x2;
return S_OK;
}
private Guid PKEY_Title = new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9");
public int GetValue(ref PROPERTYKEY key, out PropVariant pv)
{
System.Windows.Forms.MessageBox.Show(key.fmtid.ToString());
pv = new PropVariant();
if (key.fmtid == PKEY_Title)
{
pv.variantType = 31;
pv.pointerValue = Marshal.StringToHGlobalUni("Test");
return S_OK;
}
else
{
pv.variantType = 0; //VT_EMPTY
pv.pointerValue = IntPtr.Zero;
return S_OK;
}
}
public int SetValue(ref PROPERTYKEY key, ref object pv)
{
return S_OK;
}
public int Commit()
{
return S_OK;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type t)
{
try
{
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR = regHKCR.CreateSubKey(".test");
regHKCR.SetValue(null, "TestShell.PropertyHandler");
regHKCR = Registry.ClassesRoot;
regHKCR = regHKCR.CreateSubKey("CLSID\\{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
regHKCR.SetValue(null, "Test Property");
regHKCR.SetValue("ManualSafeSave", 1);
regHKCR.SetValue("Title", 2);
regHKCR.SetValue("Whatever", 3);
regHKCR = regHKCR.CreateSubKey("InProcServer32");
regHKCR.SetValue(null, #"C:\Windows\System32\mscoree.dll");
//regHKCR.SetValue(null, System.Reflection.Assembly.GetExecutingAssembly().Location);
regHKCR.SetValue("ThreadingModel", "Apartment");
RegistryKey regHKLM;
regHKLM = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\.test");
regHKLM.SetValue(null, "{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
regHKLM = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved");
regHKLM.SetValue("{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}", "Test Property");
//SHShellRestart();---------------------------------------------------------------------------------------------
// string propertyID = "VolumeName";
// //PROPSPEC propSpec = new PROPSPEC();
// //propSpec.ulKind = 0;
//// propSpec.__unnamed.lpwstr = (char*)Marshal.StringToCoTaskMemUni(propertyID);
// PropVariant propVar = new PropVariant();
// propVar.__unnamed.__unnamed.__unnamed.bstrVal = (char*)Marshal.StringToCoTaskMemUni(value);
// //delcare un safe variables
// PROPSPEC[] rgSpecs = new PROPSPEC[1];
// rgSpecs[0] = propSpec;
// PROPVARIANT[] rgVar = new PROPVARIANT[1];
// rgVar[0] = propVar;
// object val = value;
// ppPropStg.WriteMultiple(1, ref propSpec, ref val, 3);
// ppPropStg.Commit(0x8);
// fDataDiscWriter.SetJolietProperties(ppPropStg);
}
catch (Exception ex)//HKEY_CLASSES_ROOT\CLSID\{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}
{
#if DEBUG
System.Windows.Forms.MessageBox.Show(ex.Message + System.Environment.NewLine + ex.StackTrace);
#endif
}
#if DEBUG
//SHShellRestart();
#endif
}
[ComUnregisterFunctionAttribute]
public static void UnRegisterFunction(Type t)
{
try
{
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR.DeleteSubKey(".test");
regHKCR.DeleteSubKeyTree("CLSID\\{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
RegistryKey regHKLM = Registry.LocalMachine;
regHKLM.DeleteSubKeyTree("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\.test");
regHKLM = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", true);
regHKLM.DeleteValue("{9BC59AF4-41E3-49B1-9A62-17F4C92D081F}");
}
catch (Exception ex)
{
#if DEBUG
System.Windows.Forms.MessageBox.Show(ex.Message + System.Environment.NewLine + ex.StackTrace);
#endif
}
#if DEBUG
//SHShellRestart();
#endif
}
//#if DEBUG
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("shell32.dll")]
static extern IntPtr ShellExecute(
IntPtr hwnd, string lpOperation, string lpFile,
string lpParameters, string lpDirectory, int nShowCmd);
private static void SHShellRestart()
{
PostMessage(FindWindow("Progman", null), 0x0012, IntPtr.Zero, IntPtr.Zero);
ShellExecute(IntPtr.Zero, null, "explorer.exe", null, null, 5);
return;
}
//#endif
}
}
his code is prety much from msdn link d except there was a mistake in the code coz of which the handler was not being register, In the InProc32 registy key the value should be the path to mscoree.dll, when i added that the application started working.
I know this much the custom properties will be added using 2 ways. just a guess
1 - IPropertyStrore.SetValue
2 - Adding registry key entries to F29F85E0-4FF9-1068-AB91-08002B27B3D9 key in registry
As Jakob mentioned, take a look at Windows API Code Pack (the old link is deprecated).
Here is a simple code snippet using it:
public static void PreventPinning(Window window)
{
var preventPinningProperty = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 9);
WindowProperties.SetWindowProperty(window, preventPinningProperty, "1");
}
Example above is setting System.AppUserModel.PreventPinning defined by its Guid and PropertyId.
Have you had a look at the Windows API Code Pack? I am not sure if the Code Pack can add properties to file types but I know it can be used for editing existing properties so it may be worth a look.
Alternative:
If I understand your problem correctly, this might be what you are looking for
How to set custom attributes / file properties on a file in C# .Net - by Rod Howarth
While Saving the file, you could just set the custom property on it.
This question already has answers here:
C#: How to open Windows Explorer windows with a number of files selected
(5 answers)
Closed 4 years ago.
Could someone give an example on how to use the shell function SHOpenFolderAndSelectItems from C#? I don't quite get how to use these kind of functions and couldn't find it on pinvoke.net... =/
Say I have three files called
X:\Pictures\a.jpg
X:\Pictures\s.jpg
X:\Pictures\d.jpg
I then want to open up the X:\Pictures folder with a.jpg, s.jpg and d.jpg selected.
As you seem to have asked twice the same question (the other being C#: How to open Windows Explorer windows with a number of files selected that had no answer) I post my solution to both questions I don't know if I should make one a community wiki.
Searching for an answer after a coworker had the issue I found none so I wrote a small class to do this. The code is on Gist and I will paste the current version at the end of this post.
With your sample files, the syntax will be :
ShowSelectedInExplorer.FilesOrFolders(
#"X:\Pictures\a.jpg",
#"X:\Pictures\s.jpg",
#"X:\Pictures\d.jpg"
);
There are some limitations to my code compared to the low level API, mainly :
Selecting on the desktop is not implemented
The parent directory must be a directory or a drive, so you can't select multiple drives in the My Computer folder for example.
Anyway, here is the ShowSelectedInExplorer class source code :
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
static class ShowSelectedInExplorer
{
[Flags]
internal enum SHCONT : ushort
{
SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
SHCONTF_FOLDERS = 0x0020,
SHCONTF_NONFOLDERS = 0x0040,
SHCONTF_INCLUDEHIDDEN = 0x0080,
SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
SHCONTF_NETPRINTERSRCH = 0x0200,
SHCONTF_SHAREABLE = 0x0400,
SHCONTF_STORAGE = 0x0800,
SHCONTF_NAVIGATION_ENUM = 0x1000,
SHCONTF_FASTITEMS = 0x2000,
SHCONTF_FLATLIST = 0x4000,
SHCONTF_ENABLE_ASYNC = 0x8000
}
[ComImport,
Guid("000214E6-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComConversionLoss]
internal interface IShellFolder
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAttributes);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int EnumObjects([In] IntPtr hwnd, [In] SHCONT grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenumIDList);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int BindToObject([In] IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void BindToStorage([In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CompareIDs([In] IntPtr lParam, [In] ref IntPtr pidl1, [In] ref IntPtr pidl2);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetAttributesOf([In] uint cidl, [In] IntPtr apidl, [In, Out] ref uint rgfInOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetUIObjectOf([In] IntPtr hwndOwner, [In] uint cidl, [In] IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDisplayNameOf([In] ref IntPtr pidl, [In] uint uFlags, out IntPtr pName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetNameOf([In] IntPtr hwnd, [In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, [In] uint uFlags, [Out] IntPtr ppidlOut);
}
[ComImport,
Guid("000214F2-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEnumIDList
{
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Next(uint celt, IntPtr rgelt, out uint pceltFetched);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Skip([In] uint celt);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Reset();
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Clone([MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum);
}
class NativeMethods
{
static readonly int pointerSize = Marshal.SizeOf(typeof(IntPtr));
[DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
public static extern int CreateBindCtx_(int reserved, out IBindCtx ppbc);
public static IBindCtx CreateBindCtx()
{
IBindCtx result;
Marshal.ThrowExceptionForHR(CreateBindCtx_(0, out result));
return result;
}
[DllImport("shell32.dll", EntryPoint = "SHGetDesktopFolder", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int SHGetDesktopFolder_([MarshalAs(UnmanagedType.Interface)] out IShellFolder ppshf);
public static IShellFolder SHGetDesktopFolder()
{
IShellFolder result;
Marshal.ThrowExceptionForHR(SHGetDesktopFolder_(out result));
return result;
}
[DllImport("shell32.dll", EntryPoint = "SHOpenFolderAndSelectItems")]
static extern int SHOpenFolderAndSelectItems_(
[In] IntPtr pidlFolder, uint cidl, [In, Optional, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, int dwFlags
);
public static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, int dwFlags)
{
var cidl = (apidl != null) ? (uint)apidl.Length : 0U;
var result = NativeMethods.SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags);
Marshal.ThrowExceptionForHR(result);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath);
[DllImport("shell32.dll")]
public static extern void ILFree([In] IntPtr pidl);
}
static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName)
{
var bindCtx = NativeMethods.CreateBindCtx();
uint pchEaten;
uint pdwAttributes = 0;
IntPtr ppidl;
parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAttributes);
return ppidl;
}
static IntPtr PathToAbsolutePIDL(string path)
{
var desktopFolder = NativeMethods.SHGetDesktopFolder();
return GetShellFolderChildrenRelativePIDL(desktopFolder, path);
}
static Guid IID_IShellFolder = typeof(IShellFolder).GUID;
static int pointerSize = Marshal.SizeOf(typeof(IntPtr));
static IShellFolder PIDLToShellFolder(IShellFolder parent, IntPtr pidl)
{
IShellFolder folder;
var result = parent.BindToObject(pidl, null, ref IID_IShellFolder, out folder);
Marshal.ThrowExceptionForHR((int)result);
return folder;
}
static IShellFolder PIDLToShellFolder(IntPtr pidl)
{
return PIDLToShellFolder(NativeMethods.SHGetDesktopFolder(), pidl);
}
static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, bool edit)
{
NativeMethods.SHOpenFolderAndSelectItems(pidlFolder, apidl, edit ? 1 : 0);
}
public static void FileOrFolder(string path, bool edit = false)
{
if (path == null) throw new ArgumentNullException("path");
var pidl = PathToAbsolutePIDL(path);
try
{
SHOpenFolderAndSelectItems(pidl, null, edit);
}
finally
{
NativeMethods.ILFree(pidl);
}
}
static IEnumerable<FileSystemInfo> PathToFileSystemInfo(IEnumerable<string> paths)
{
foreach (var path in paths)
{
string fixedPath = path;
if (fixedPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || fixedPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
{
fixedPath = fixedPath.Remove(fixedPath.Length - 1);
}
if (Directory.Exists(fixedPath)) yield return new DirectoryInfo(fixedPath);
else if (File.Exists(fixedPath)) yield return new FileInfo(fixedPath);
else
{
throw new FileNotFoundException("The specified file or folder doesn't exists : " + fixedPath, fixedPath);
}
}
}
public static void FilesOrFolders(string parentDirectory, ICollection<string> filenames)
{
if (filenames == null) throw new ArgumentNullException("filenames");
if (filenames.Count == 0) return;
var parentPidl = PathToAbsolutePIDL(parentDirectory);
try
{
var parent = PIDLToShellFolder(parentPidl);
List<IntPtr> filesPidl = new List<IntPtr>(filenames.Count);
foreach (var filename in filenames)
{
filesPidl.Add(GetShellFolderChildrenRelativePIDL(parent, filename));
}
try
{
SHOpenFolderAndSelectItems(parentPidl, filesPidl.ToArray(), false);
}
finally
{
foreach (var pidl in filesPidl)
{
NativeMethods.ILFree(pidl);
}
}
}
finally
{
NativeMethods.ILFree(parentPidl);
}
}
public static void FilesOrFolders(params string[] paths)
{
FilesOrFolders((IEnumerable<string>)paths);
}
public static void FilesOrFolders(IEnumerable<string> paths)
{
FilesOrFolders(PathToFileSystemInfo(paths));
}
public static void FilesOrFolders(IEnumerable<FileSystemInfo> paths)
{
if (paths == null) throw new ArgumentNullException("paths");
if (paths.Count() == 0) return;
var explorerWindows = paths.GroupBy(p => Path.GetDirectoryName(p.FullName));
foreach (var explorerWindowPaths in explorerWindows)
{
var parentDirectory = Path.GetDirectoryName(explorerWindowPaths.First().FullName);
FilesOrFolders(parentDirectory, explorerWindowPaths.Select(fsi => fsi.Name).ToList());
}
}
}
Not a 100% answer, but this snippet shows how to select a single item in the explorer from C#.
private void SelectInFileExplorer(string fullPath)
{
if (string.IsNullOrEmpty(fullPath))
throw new ArgumentNullException("fullPath");
fullPath = Path.GetFullPath(fullPath);
IntPtr pidlList = NativeMethods.ILCreateFromPathW(fullPath);
if (pidlList != IntPtr.Zero)
try
{
// Open parent folder and select item
Marshal.ThrowExceptionForHR(NativeMethods.SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
}
finally
{
NativeMethods.ILFree(pidlList);
}
}
static class NativeMethods
{
[DllImport("shell32.dll", ExactSpelling=true)]
public static extern void ILFree(IntPtr pidlList);
[DllImport("shell32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
public static extern IntPtr ILCreateFromPathW(string pszPath);
[DllImport("shell32.dll", ExactSpelling=true)]
public static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);
}
Check http://www.cnblogs.com/qiuyi21/archive/2009/06/24/1510592.html. The example uses IShellLink to get pidls from path before launching SHOpenFolderAndSelectItems, I would use ILCreateFromPath instead.
Most of the needs would of SHOpoenFolderSelectedItems would be handled by:
For file selection in C# you would normally use: System.Windows.Forms.OpenFileDialog.
For folder selection in C# you would normally use: System.Windows.Forms.FolderBrowserDialog.
You would set an appropriate filter and you can set a selected item initially.
Perhaps this is close enough to what you need?