Click here to Skip to main content
15,894,740 members
Articles / Web Development / HTML

WPF x FileExplorer x MVVM

Rate me:
Please Sign up or sign in to vote.
4.99/5 (52 votes)
24 Nov 2012LGPL323 min read 290.7K   9.4K   228  
This article describe how to construct FileExplorer controls included DirectoryTree and FileList, using Model-View-ViewModel (MVVM) pattern.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// LYCJ (c) 2009 - http://www.quickzip.org/components                                                            //
// Release under LGPL license.                                                                                   //
//                                                                                                               //
// This code used part of Steven Roebert's work (http://www.codeproject.com/KB/miscctrl/FileBrowser.aspx)    //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using ShellDll;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Diagnostics;


namespace System.IO.Tools
{
    public class MouseHoverEventArgs : EventArgs
    {
        public string Info { get; private set; }
        public string Command { get; private set; }
        public uint CmdID { get; private set; }

        public MouseHoverEventArgs(string command, string info, uint cmdID)
        { Command = command; Info = info; ; CmdID = cmdID; }
    }

    public class InvokeCommandEventArgs : MouseHoverEventArgs
    {
        public bool ContinueInvoke { get; set; }
        public FileSystemInfoEx[] SelectedItems { get; private set; }

        public InvokeCommandEventArgs(string command, string info, uint cmdID,
            FileSystemInfoEx[] selectedItems)
            : base(command, info, cmdID)
        {
            SelectedItems = selectedItems;
            ContinueInvoke = true;
        }
    }

    public class QueryMenuItemsEventArgs : EventArgs
    {
        public bool QueryContextMenu { get; set; }
        public bool QueryContextMenu2 { get; set; }
        public bool QueryContextMenu3 { get; set; }
        public string[] ExtraMenuItems { get; set; }
        public string[] GrayedItems { get; set; }
        public string[] HiddenItems { get; set; }
        public int DefaultItem { get; set; }
        public FileSystemInfoEx[] SelectedItems { get; private set; }
        public QueryMenuItemsEventArgs(FileSystemInfoEx[] selectedItems)
        {
            ExtraMenuItems = new string[] { }; SelectedItems = selectedItems; DefaultItem = -1;
            QueryContextMenu = true; QueryContextMenu2 = true; QueryContextMenu3 = true;
        }
    }

    public class BeforePopupEventArgs : EventArgs
    {
        public IntPtr ptrPopupMenu = IntPtr.Zero;
        public IContextMenu iContextMenu = null;
        public bool ContinuePopup { get; set; }
        public uint DefaultCommandID { get; set; }
        public string DefaultCommand { get; set; }
        public BeforePopupEventArgs(IntPtr ptrPopupMenu, IContextMenu iContextMenu, uint defaultCommandID, string defaultCommand)
        {
            this.ptrPopupMenu = ptrPopupMenu;
            this.iContextMenu = iContextMenu;
            ContinuePopup = true;
            DefaultCommandID = defaultCommandID;
            DefaultCommand = defaultCommand;
        }
    }

    public delegate void MouseHoverEventHandler(object sender, MouseHoverEventArgs args);
    public delegate void InvokeCommandEventHandler(object sender, InvokeCommandEventArgs args);
    public delegate void QueryMenuItemsEventHandler(object sender, QueryMenuItemsEventArgs args);
    public delegate void BeforePopupEventHandler(object sender, BeforePopupEventArgs args);

    public class ContextMenuWrapper : NativeWindow
    {
        /// <summary>
        /// Occur user hover on a menu item in popup menu.
        /// </summary>
        public MouseHoverEventHandler OnMouseHover;
        /// <summary>
        /// Occur to query user (non-shell) items, and allow set query IContextMenu2/IContextMenu3 interface.
        /// </summary>
        public QueryMenuItemsEventHandler OnQueryMenuItems;
        /// <summary>
        /// Occur when context menu is prepared and is about to popup.
        /// </summary>
        public BeforePopupEventHandler OnBeforePopup;
        /// <summary>
        /// Occur when user selected a command from the popup and is about to invoke the command.
        /// </summary>
        public InvokeCommandEventHandler OnBeforeInvokeCommand;

        IContextMenu _iContextMenu;
        IContextMenu2 _iContextMenu2;
        IContextMenu3 _iContextMenu3;

        bool _contextMenuVisible = false;

        public ContextMenuWrapper()
        {
            this.CreateHandle(new CreateParams());
        }

        private string removeCheckedSymbol(string command)
        {
            return command.EndsWith("[*]") ? command.Substring(0, command.Length - 3) : command;
        }

        protected override void WndProc(ref Message m)
        {
            #region IContextMenu

            if (_iContextMenu != null &&
                m.Msg == (int)ShellAPI.WM.MENUSELECT &&
                ((int)ShellHelper.HiWord(m.WParam) & (int)ShellAPI.MFT.SEPARATOR) == 0)
            //&&
            //((int)ShellHelper.HiWord(m.WParam) & (int)ShellAPI.MFT.POPUP) == 0)
            {
                uint cmdID = ShellHelper.LoWord(m.WParam);
                string info = null, command = null;
                if (cmdID == 0)
                {
                    return;
                }
                else
                    if (cmdID > ShellAPI.CMD_LAST)
                    {
                        info = command = removeCheckedSymbol(queryMenuItemsEventArgs.ExtraMenuItems[cmdID - ShellAPI.CMD_LAST - 1]);
                    }
                    else
                    {
                        info = ContextMenuHelper.GetCommandString(
                            _iContextMenu, cmdID - ShellAPI.CMD_FIRST,
                            false);
                        command = ContextMenuHelper.GetCommandString(
                            _iContextMenu, cmdID - ShellAPI.CMD_FIRST,
                            true);
                    }
                if (OnMouseHover != null)
                    OnMouseHover(this, new MouseHoverEventArgs(command, info.ToString(), cmdID));



            }

            #endregion


            #region IContextMenu2

            if (_iContextMenu2 != null &&
                (m.Msg == (int)ShellAPI.WM.INITMENUPOPUP ||
                 m.Msg == (int)ShellAPI.WM.MEASUREITEM ||
                 m.Msg == (int)ShellAPI.WM.DRAWITEM))
            {
                if (_iContextMenu2.HandleMenuMsg(
                    (uint)m.Msg, m.WParam, m.LParam) == ShellAPI.S_OK)
                    return;
            }

            #endregion

            #region IContextMenu3

            if (_iContextMenu3 != null &&
                m.Msg == (int)ShellAPI.WM.MENUCHAR)
            {
                if (_iContextMenu3.HandleMenuMsg2(
                    (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == ShellAPI.S_OK)
                    return;
            }

            #endregion

            base.WndProc(ref m);
        }

        QueryMenuItemsEventArgs queryMenuItemsEventArgs;
        public string Popup(FileSystemInfoEx[] items, Point pt)
        {
            if (items.Length > 0 && !_contextMenuVisible)
            {
                //0.15: Fixed ShellFolder not freed correctly.
                using (ShellFolder2 parentShellFolder = items[0].Parent != null ?
                        items[0].Parent.ShellFolder :
                        DirectoryInfoEx.DesktopDirectory.ShellFolder)
                    try
                    {
                        _contextMenuVisible = true;

                        ///Debug.WriteLine(items[0].Parent.FullName);

                        IntPtr ptrContextMenu = IntPtr.Zero;
                        IntPtr ptrContextMenu2 = IntPtr.Zero;
                        IntPtr PtrContextMenu3 = IntPtr.Zero;
                        IntPtr contextMenu = IntPtr.Zero;
                        List<IntPtr> menuPtrConstructed = new List<IntPtr>();
                        PIDL[] pidls = IOTools.GetPIDL(items, true);

                        if (ContextMenuHelper.GetIContextMenu(parentShellFolder, IOTools.GetPIDLPtr(pidls),
                            out ptrContextMenu, out _iContextMenu))
                            try
                            {

                                queryMenuItemsEventArgs = new QueryMenuItemsEventArgs(items);
                                if (OnQueryMenuItems != null)
                                    OnQueryMenuItems(this, queryMenuItemsEventArgs);

                                contextMenu = ShellAPI.CreatePopupMenu();

                                if (queryMenuItemsEventArgs.QueryContextMenu)
                                    _iContextMenu.QueryContextMenu(contextMenu, 0, ShellAPI.CMD_FIRST,
                                        ShellAPI.CMD_LAST, ShellAPI.CMF.EXPLORE | ShellAPI.CMF.CANRENAME |
                                        ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMF.EXTENDEDVERBS : 0));

                                #region obsolute
                                //for (uint i = 0; i < queryMenuItemsEventArgs.ExtraMenuItems.Length; i++)
                                //{
                                //    string caption = queryMenuItemsEventArgs.ExtraMenuItems[i];
                                //    if (caption != "---")
                                //    {
                                //        ShellAPI.InsertMenu(contextMenu, i, ShellAPI.MFT.BYPOSITION,
                                //            ShellAPI.CMD_LAST + i + 1, caption);
                                //        if (queryMenuItemsEventArgs.DefaultItem == i)
                                //            ShellAPI.SetMenuDefaultItem(contextMenu, i, true);
                                //    }
                                //    else ShellAPI.InsertMenu(contextMenu, i, ShellAPI.MFT.BYPOSITION |
                                //        ShellAPI.MFT.SEPARATOR, 0, "-");
                                //}
                                #endregion

                                //0.11: Added ContextMenuWrapper OnQueryMenuItems event now support multilevel directory. (e.g. @"Tools\Add")
                                ContextMenuHelperEx.ConstructCustomMenu(contextMenu, queryMenuItemsEventArgs.ExtraMenuItems, out menuPtrConstructed);

                                if (queryMenuItemsEventArgs.QueryContextMenu2)
                                    try
                                    {
                                        Marshal.QueryInterface(ptrContextMenu, ref ShellAPI.IID_IContextMenu2,
                                            out ptrContextMenu2);
                                        _iContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(
                                        ptrContextMenu2, typeof(IContextMenu2));
                                    }
                                    catch (Exception) { }

                                if (queryMenuItemsEventArgs.QueryContextMenu3)
                                    try
                                    {
                                        Marshal.QueryInterface(ptrContextMenu, ref ShellAPI.IID_IContextMenu3,
                                    out PtrContextMenu3);

                                        _iContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(
                                         PtrContextMenu3, typeof(IContextMenu3));
                                    }
                                    catch (Exception) { }


                                uint GMDI_USEDISABLED = 0x0001;
                                uint GMDI_GOINTOPOPUPS = 0x0002;
                                uint intDefaultItem = (uint)ShellAPI.GetMenuDefaultItem(contextMenu, false, GMDI_USEDISABLED);

                                string strDefaultCommand = intDefaultItem >= ShellAPI.CMD_FIRST ? 
                                    ContextMenuHelper.GetCommandString(_iContextMenu, intDefaultItem - ShellAPI.CMD_FIRST, true) : null;
                                


                                if (queryMenuItemsEventArgs.QueryContextMenu) //No need to Disable if query is not carried out in first place.
                                {
                                    //0.11: Added queryMenuItemsEventArgs.GrayedItems / HiddenItems
                                    ContextMenuHelperEx.DisableMenuItems(contextMenu, _iContextMenu,
                                        queryMenuItemsEventArgs.GrayedItems, ContextMenuHelperEx.DisabledMethods.Gray);
                                    ContextMenuHelperEx.DisableMenuItems(contextMenu, _iContextMenu,
                                        queryMenuItemsEventArgs.HiddenItems, ContextMenuHelperEx.DisabledMethods.Remove);
                                }

                                //0.17: Added DefaultItem and DefaultCommand in BeforePopup
                                bool cont = true;
                                if (OnBeforePopup != null)
                                {
                                    BeforePopupEventArgs args = new BeforePopupEventArgs
                                        (contextMenu, _iContextMenu, intDefaultItem - ShellAPI.CMD_FIRST, strDefaultCommand);                                    
                                    OnBeforePopup(this, args);
                                    cont = args.ContinuePopup;
                                }

                                if (cont)
                                {
                                    //0.18 Fixed Context menu disappear in some case. (By cwharmon)
                                    //http://www.codeproject.com/KB/files/DirectoryInfoEx.aspx#xx3475961xx 
                                    ShellAPI.SetForegroundWindow(this.Handle);

                                    uint selected = ShellAPI.TrackPopupMenuEx(contextMenu, ShellAPI.TPM.RETURNCMD,
                                                        pt.X, pt.Y, this.Handle, IntPtr.Zero);

                                    uint msg = 0;
                                    ShellAPI.PostMessage(this.Handle, msg, IntPtr.Zero, IntPtr.Zero);

                                    if (OnMouseHover != null)
                                        OnMouseHover(this, new MouseHoverEventArgs("", "", 0));

                                    if (selected > ShellAPI.CMD_LAST)
                                    {
                                        return removeCheckedSymbol(queryMenuItemsEventArgs.ExtraMenuItems[selected - ShellAPI.CMD_LAST - 1]);

                                    }

                                    if (selected >= ShellAPI.CMD_FIRST)
                                    {
                                        string command = ContextMenuHelper.GetCommandString(_iContextMenu,
                                            selected - ShellAPI.CMD_FIRST, true);
                                        if (command == null) return null;

                                        if (OnBeforeInvokeCommand != null)
                                        {
                                            InvokeCommandEventArgs args =
                                                new InvokeCommandEventArgs(command, "", selected, items);
                                            OnBeforeInvokeCommand(this, args);
                                            if (!args.ContinueInvoke)
                                                return command;
                                        }

                                        if (command == "rename")
                                            return "rename";
                                        else
                                        {
                                            //if (items.Length == 1 && items[0] is DirectoryInfoEx)
                                            ContextMenuHelper.InvokeCommand(_iContextMenu,
                                                selected - ShellAPI.CMD_FIRST,
                                                (items[0].Parent != null) ? items[0].Parent.FullName :
                                                items[0].FullName, pt);
                                            //else
                                            //ContextMenuHelper.InvokeCommand(items[0].Parent,
                                            //    IOTools.GetPIDLPtr(items, true), selected - ShellAPI.CMD_FIRST,
                                            //    pt);

                                        }

                                    }
                                }
                            }
                            finally
                            {
                                IOTools.FreePIDL(pidls);

                                if (_iContextMenu != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu);
                                    _iContextMenu = null;
                                }

                                if (_iContextMenu2 != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu2);
                                    _iContextMenu2 = null;
                                }

                                if (_iContextMenu3 != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu3);
                                    _iContextMenu3 = null;
                                }

                                foreach (IntPtr menuPtr in menuPtrConstructed)
                                    ShellAPI.DestroyMenu(menuPtr);
                                menuPtrConstructed.Clear();

                                if (contextMenu != null)
                                    ShellAPI.DestroyMenu(contextMenu);

                                if (ptrContextMenu != IntPtr.Zero)
                                    Marshal.Release(ptrContextMenu);

                                if (ptrContextMenu2 != IntPtr.Zero)
                                    Marshal.Release(ptrContextMenu2);

                                if (PtrContextMenu3 != IntPtr.Zero)
                                    Marshal.Release(PtrContextMenu3);
                            }



                    }
                    finally
                    {

                        _contextMenuVisible = false;
                    }


            }

            return null;
        }


    }

    //Taken from BrowserTVContextMenuWrapper.cs
    #region ContextMenuHelper

    /// <summary>
    /// This class provides static methods which are being used to retrieve IContextMenu's for specific items
    /// and to invoke certain commands.
    /// </summary>
    public static class ContextMenuHelper
    {
        #region GetCommandString

        public static string GetCommandString(IContextMenu iContextMenu, uint idcmd, bool executeString)
        {
            try
            {
                string command = GetCommandStringW(iContextMenu, idcmd, executeString);

                if (string.IsNullOrEmpty(command))
                    command = GetCommandStringA(iContextMenu, idcmd, executeString);

                return command;
            }
            catch (AccessViolationException) { return null; }
        }

        /// <summary>
        /// Retrieves the command string for a specific item from an iContextMenu (Ansi)
        /// </summary>
        /// <param name="iContextMenu">the IContextMenu to receive the string from</param>
        /// <param name="idcmd">the id of the specific item</param>
        /// <param name="executeString">indicating whether it should return an execute string or not</param>
        /// <returns>if executeString is true it will return the executeString for the item, 
        /// otherwise it will return the help info string</returns>
        internal static string GetCommandStringA(IContextMenu iContextMenu, uint idcmd, bool executeString)
        {
            string info = string.Empty;
            byte[] bytes = new byte[256];
            int index;

            iContextMenu.GetCommandString(
                idcmd,
                (executeString ? ShellAPI.GCS.VERBA : ShellAPI.GCS.HELPTEXTA),
                0,
                bytes,
                ShellAPI.MAX_PATH);

            index = 0;
            while (index < bytes.Length && bytes[index] != 0)
            { index++; }

            if (index < bytes.Length)
                info = Encoding.Default.GetString(bytes, 0, index);

            return info;
        }

        /// <summary>
        /// Retrieves the command string for a specific item from an iContextMenu (Unicode)
        /// </summary>
        /// <param name="iContextMenu">the IContextMenu to receive the string from</param>
        /// <param name="idcmd">the id of the specific item</param>
        /// <param name="executeString">indicating whether it should return an execute string or not</param>
        /// <returns>if executeString is true it will return the executeString for the item, 
        /// otherwise it will return the help info string</returns>
        internal static string GetCommandStringW(IContextMenu iContextMenu, uint idcmd, bool executeString)
        {
            string info = string.Empty;
            byte[] bytes = new byte[256];
            int index;

            iContextMenu.GetCommandString(
                idcmd,
                (executeString ? ShellAPI.GCS.VERBW : ShellAPI.GCS.HELPTEXTW),
                0,
                bytes,
                ShellAPI.MAX_PATH);

            index = 0;
            while (index < bytes.Length - 1 && (bytes[index] != 0 || bytes[index + 1] != 0))
            { index += 2; }

            if (index < bytes.Length - 1)
                info = Encoding.Unicode.GetString(bytes, 0, index); //+ 1);

            return info;
        }

        #endregion

        #region Invoke Commands

        /// <summary>
        /// Invokes a specific command from an IContextMenu
        /// </summary>
        /// <param name="iContextMenu">the IContextMenu containing the item</param>
        /// <param name="cmd">the index of the command to invoke</param>
        /// <param name="parentDir">the parent directory from where to invoke</param>
        /// <param name="ptInvoke">the point (in screen co顤dinates) from which to invoke</param>
        public static void InvokeCommand(IContextMenu iContextMenu, uint cmd, string parentDir, Point ptInvoke)
        {
            ShellAPI.CMINVOKECOMMANDINFOEX invoke = new ShellAPI.CMINVOKECOMMANDINFOEX();
            invoke.cbSize = ShellAPI.cbInvokeCommand;
            invoke.lpVerb = (IntPtr)cmd;
            invoke.lpDirectory = parentDir;
            invoke.lpVerbW = (IntPtr)cmd;
            invoke.lpDirectoryW = parentDir;
            invoke.fMask = ShellAPI.CMIC.UNICODE | ShellAPI.CMIC.PTINVOKE |
                ((Control.ModifierKeys & Keys.Control) != 0 ? ShellAPI.CMIC.CONTROL_DOWN : 0) |
                ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMIC.SHIFT_DOWN : 0);
            invoke.ptInvoke = new ShellAPI.POINT(ptInvoke.X, ptInvoke.Y);
            invoke.nShow = ShellAPI.SW.SHOWNORMAL;

            iContextMenu.InvokeCommand(ref invoke);
        }

        /// <summary>
        /// Invokes a specific command from an IContextMenu
        /// </summary>
        /// <param name="iContextMenu">the IContextMenu containing the item</param>
        /// <param name="cmdA">the Ansi execute string to invoke</param>
        /// <param name="cmdW">the Unicode execute string to invoke</param>
        /// <param name="parentDir">the parent directory from where to invoke</param>
        /// <param name="ptInvoke">the point (in screen co顤dinates) from which to invoke</param>
        public static void InvokeCommand(IContextMenu iContextMenu, string cmd, string parentDir, Point ptInvoke)
        {
            ShellAPI.CMINVOKECOMMANDINFOEX invoke = new ShellAPI.CMINVOKECOMMANDINFOEX();
            invoke.cbSize = ShellAPI.cbInvokeCommand;
            invoke.lpVerb = Marshal.StringToHGlobalAnsi(cmd);
            invoke.lpDirectory = parentDir;
            invoke.lpVerbW = Marshal.StringToHGlobalUni(cmd);
            invoke.lpDirectoryW = parentDir;

            invoke.fMask = ShellAPI.CMIC.UNICODE | ShellAPI.CMIC.PTINVOKE |
                ((Control.ModifierKeys & Keys.Control) != 0 ? ShellAPI.CMIC.CONTROL_DOWN : 0) |
                ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMIC.SHIFT_DOWN : 0);
            invoke.ptInvoke = new ShellAPI.POINT(ptInvoke.X, ptInvoke.Y);
            invoke.nShow = ShellAPI.SW.SHOWNORMAL;

            iContextMenu.InvokeCommand(ref invoke);
        }

        /// <summary>
        /// Invokes a specific command for a set of pidls
        /// </summary>
        /// <param name="parent">the parent ShellItem which contains the pidls</param>
        /// <param name="pidls">the pidls from the items for which to invoke</param>
        /// <param name="cmd">the execute string from the command to invoke</param>
        /// <param name="ptInvoke">the point (in screen co顤dinates) from which to invoke</param>
        public static void InvokeCommand(DirectoryInfoEx parent, IntPtr[] pidls, string cmd, Point ptInvoke)
        {
            IntPtr icontextMenuPtr;
            IContextMenu iContextMenu;

            //0.15: Fixed ShellFolder not freed.
            using (ShellFolder2 parentShellFolder = parent.ShellFolder)
                if (GetIContextMenu(parentShellFolder, pidls, out icontextMenuPtr, out iContextMenu))
                {
                    try
                    {
                        InvokeCommand(
                            iContextMenu,
                            cmd,
                            parent.FullName,
                            ptInvoke);
                    }
                    catch (Exception) { }
                    finally
                    {
                        if (iContextMenu != null)
                            Marshal.ReleaseComObject(iContextMenu);

                        if (icontextMenuPtr != IntPtr.Zero)
                            Marshal.Release(icontextMenuPtr);
                    }
                }
        }

        public static void InvokeCommand(DirectoryInfoEx parent, FileSystemInfoEx[] entries, string cmd, Point ptInvoke)
        {          
            PIDL[] pidls = IOTools.GetPIDL(entries, true);
            IntPtr[] ptrs = IOTools.GetPIDLPtr(pidls);            
            using (ShellFolder2 parentShellFolder = parent.ShellFolder)
            {
                try
                {
                    InvokeCommand(parent, ptrs, cmd, ptInvoke);
                }
                finally
                {
                    IOTools.FreePIDL(pidls);
                }
            }
        }

        public static void InvokeCommand(DirectoryInfoEx parent, IntPtr[] pidls, uint cmd, Point ptInvoke)
        {
            IntPtr icontextMenuPtr;
            IContextMenu iContextMenu;

            //0.15: Fixed ShellFolder not freed.
            using (ShellFolder2 parentShellFolder = parent.ShellFolder)
                if (GetIContextMenu(parentShellFolder, pidls, out icontextMenuPtr, out iContextMenu))
                {
                    try
                    {
                        InvokeCommand(
                            iContextMenu,
                            cmd,
                            parent.FullName,
                            ptInvoke);
                    }
                    catch (Exception) { }
                    finally
                    {
                        if (iContextMenu != null)
                            Marshal.ReleaseComObject(iContextMenu);

                        if (icontextMenuPtr != IntPtr.Zero)
                            Marshal.Release(icontextMenuPtr);
                    }
                }
        }

        public static void InvokeCommand(DirectoryInfoEx parent, FileSystemInfoEx[] entries, uint cmd, Point ptInvoke)
        {
            PIDL[] pidls = IOTools.GetPIDL(entries, true);
            IntPtr[] ptrs = IOTools.GetPIDLPtr(pidls);            
            using (ShellFolder2 parentShellFolder = parent.ShellFolder)
            {
                try
                {
                    InvokeCommand(parent, ptrs, cmd, ptInvoke);
                }
                finally
                {
                    IOTools.FreePIDL(pidls);
                }
            }
        }
        #endregion

        /// <summary>
        /// Retrieves the IContextMenu for specific items
        /// </summary>
        /// <param name="parent">the parent IShellFolder which contains the items</param>
        /// <param name="pidls">the pidls of the items for which to retrieve the IContextMenu</param>
        /// <param name="icontextMenuPtr">the pointer to the IContextMenu</param>
        /// <param name="iContextMenu">the IContextMenu for the items</param>
        /// <returns>true if the IContextMenu has been retrieved succesfully, false otherwise</returns>
        public static bool GetIContextMenu(
            IShellFolder2 parent,
            IntPtr[] pidls,
            out IntPtr iContextMenuPtr,
            out IContextMenu iContextMenu)
        {
            if (parent.GetUIObjectOf(
                        IntPtr.Zero,
                        (uint)pidls.Length,
                        pidls,
                        ref ShellAPI.IID_IContextMenu,
                        IntPtr.Zero,
                        out iContextMenuPtr) == ShellAPI.S_OK)
            {
                iContextMenu =
                    (IContextMenu)Marshal.GetTypedObjectForIUnknown(
                        iContextMenuPtr, typeof(IContextMenu));

                return true;
            }
            else
            {
                iContextMenuPtr = IntPtr.Zero;
                iContextMenu = null;

                return false;
            }
        }

        public static bool GetNewContextMenu(DirectoryInfoEx item, out IntPtr iContextMenuPtr, out IContextMenu iContextMenu)
        {
            if (ShellAPI.CoCreateInstance(
                    ref ShellAPI.CLSID_NewMenu,
                    IntPtr.Zero,
                    ShellAPI.CLSCTX.INPROC_SERVER,
                    ref ShellAPI.IID_IContextMenu,
                    out iContextMenuPtr) == ShellAPI.S_OK)
            {
                iContextMenu = Marshal.GetTypedObjectForIUnknown(iContextMenuPtr, typeof(IContextMenu)) as IContextMenu;

                IntPtr iShellExtInitPtr;
                if (Marshal.QueryInterface(
                    iContextMenuPtr,
                    ref ShellAPI.IID_IShellExtInit,
                    out iShellExtInitPtr) == ShellAPI.S_OK)
                {
                    IShellExtInit iShellExtInit = Marshal.GetTypedObjectForIUnknown(
                        iShellExtInitPtr, typeof(IShellExtInit)) as IShellExtInit;

                    PIDL pidlLookup = item.PIDL;
                    try
                    {
                        iShellExtInit.Initialize(pidlLookup.Ptr, IntPtr.Zero, 0);

                        Marshal.ReleaseComObject(iShellExtInit);
                        Marshal.Release(iShellExtInitPtr);

                        return true;
                    }
                    finally
                    {
                        if (pidlLookup != null)
                            pidlLookup.Free();
                        pidlLookup = null;
                    }
                }
                else
                {
                    if (iContextMenu != null)
                    {
                        Marshal.ReleaseComObject(iContextMenu);
                        iContextMenu = null;
                    }

                    if (iContextMenuPtr != IntPtr.Zero)
                    {
                        Marshal.Release(iContextMenuPtr);
                        iContextMenuPtr = IntPtr.Zero;
                    }

                    return false;
                }
            }
            else
            {
                iContextMenuPtr = IntPtr.Zero;
                iContextMenu = null;
                return false;
            }
        }

        ///// <summary>
        ///// When keys are pressed, this method will check for known key combinations. For example copy and past with
        ///// Ctrl + C and Ctrl + V.
        ///// </summary>
        //public static void ProcessKeyCommands(Browser br, object sender, KeyEventArgs e)
        //{
        //    if (e.Control && !e.Shift && !e.Alt)
        //    {
        //        switch (e.KeyCode)
        //        {
        //            case Keys.C:
        //            case Keys.Insert:
        //            case Keys.V:
        //            case Keys.X:
        //                #region Copy/Paste/Cut
        //                {
        //                    Cursor.Current = Cursors.WaitCursor;
        //                    IntPtr[] pidls;
        //                    ShellItem parent;

        //                    pidls = new IntPtr[1];
        //                    pidls[0] = br.SelectedItem.PIDLRel.Ptr;
        //                    parent = (br.SelectedItem.ParentItem != null ? br.SelectedItem.ParentItem : br.SelectedItem);

        //                    if (pidls.Length > 0)
        //                    {
        //                        string cmd;
        //                        if (e.KeyCode == Keys.C || e.KeyCode == Keys.Insert)
        //                            cmd = "copy";
        //                        else if (e.KeyCode == Keys.V)
        //                            cmd = "paste";
        //                        else
        //                            cmd = "cut";

        //                        ContextMenuHelper.InvokeCommand(parent, pidls, cmd, new Point(0, 0));
        //                        Cursor.Current = Cursors.Default;
        //                    }
        //                    e.Handled = true;
        //                    e.SuppressKeyPress = true;
        //                }
        //                #endregion
        //                break;

        //            case Keys.N:
        //                #region Create New Folder
        //                if (!br.CreateNewFolder())
        //                    System.Media.SystemSounds.Beep.Play();

        //                e.Handled = true;
        //                e.SuppressKeyPress = true;
        //                #endregion
        //                break;

        //            case Keys.Z:
        //                break;

        //            case Keys.Y:
        //                break;
        //        }
        //    }
        //    else
        //    {
        //        switch (e.KeyCode)
        //        {
        //            case Keys.Insert:
        //                #region Paste
        //                if (e.Shift && !e.Control && !e.Alt)
        //                {
        //                    IntPtr[] pidls = new IntPtr[1];
        //                    pidls[0] = br.SelectedItem.PIDLRel.Ptr;
        //                    ShellItem parent = (br.SelectedItem.ParentItem != null ? br.SelectedItem.ParentItem : br.SelectedItem);
        //                    ContextMenuHelper.InvokeCommand(parent, pidls, "paste", new Point(0, 0));
        //                }
        //                e.Handled = true;
        //                e.SuppressKeyPress = true;
        //                #endregion
        //                break;

        //            case Keys.Delete:
        //                #region Delete
        //                if (!e.Control && !e.Alt)
        //                {
        //                    IntPtr[] pidls;
        //                    ShellItem parent;
        //                    pidls = new IntPtr[1];
        //                    pidls[0] = br.SelectedItem.PIDLRel.Ptr;
        //                    parent = (br.SelectedItem.ParentItem != null ? br.SelectedItem.ParentItem : br.SelectedItem);

        //                    if (pidls.Length > 0)
        //                        ContextMenuHelper.InvokeCommand(parent, pidls, "delete", new Point(0, 0));
        //                }
        //                e.Handled = true;
        //                e.SuppressKeyPress = true;
        //                #endregion
        //                break;

        //            case Keys.F2:
        //                #region Rename
        //                if (sender.Equals(br.FolderView))
        //                {
        //                    if (br.FolderView.SelectedNode != null)
        //                    {
        //                        br.FolderView.LabelEdit = true;
        //                        br.FolderView.SelectedNode.BeginEdit();
        //                    }
        //                }
        //                #endregion
        //                break;

        //            case Keys.Back:
        //                #region Up
        //                {
        //                    if (br.FolderView.SelectedNode != null && br.FolderView.SelectedNode.Parent != null)
        //                        br.FolderView.SelectedNode = br.FolderView.SelectedNode.Parent;
        //                }
        //                e.Handled = true;
        //                e.SuppressKeyPress = true;
        //                #endregion
        //                break;
        //        }
        //    }
        // }
    }

    #endregion


}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Founder
Hong Kong Hong Kong

Comments and Discussions