⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 browsercontextmenuwrappers.cs

📁 C#界面编程
💻 CS
📖 第 1 页 / 共 5 页
字号:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections;
using System.Drawing;
using ShellDll;
using System.Threading;
using System.ComponentModel;
using System.IO;

namespace FileBrowser
{
    /// <summary>
    /// This class takes care of showing ContextMenu's for a BrowserTreeView
    /// </summary>
    internal class BrowserTVContextMenuWrapper : NativeWindow
    {
        #region Fields

        // The browser for which to provide the context menu's
        private Browser br;
        
        // If this bool is true the next time the context menu has to be shown will be cancelled
        private bool suspendContextMenu;

        // The interfaces for the needed context menu's
        private IContextMenu iContextMenu;
        private IContextMenu2 iContextMenu2;
        private IContextMenu3 iContextMenu3;

        private bool contextMenuVisible;

        // The cmd for a custom added menu item
        private enum CMD_CUSTOM
        {
            ExpandCollapse = (int)ShellAPI.CMD_LAST + 1
        }

        #endregion

        /// <summary>
        /// Registers the neccesairy events
        /// </summary>
        /// <param name="br">The browser for which to support the ContextMenu</param>
        public BrowserTVContextMenuWrapper(Browser br)
        {
            this.br = br;

            br.FolderView.MouseUp += new System.Windows.Forms.MouseEventHandler(FolderView_MouseUp);
            br.FolderView.AfterLabelEdit += new NodeLabelEditEventHandler(FolderView_AfterLabelEdit);
            br.FolderView.BeforeLabelEdit += new NodeLabelEditEventHandler(FolderView_BeforeLabelEdit);
            br.FolderView.KeyDown += new KeyEventHandler(FolderView_KeyDown);

            this.CreateHandle(new CreateParams());
        }

        #region Public

        public bool SuspendContextMenu
        {
            get { return suspendContextMenu; }
            set { suspendContextMenu = value; }
        }

        #endregion

        #region Override

        /// <summary>
        /// This method receives WindowMessages. It will make the "Open With" and "Send To" work 
        /// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover 
        /// method of Browser when hovering over a ContextMenu item.
        /// </summary>
        /// <param name="m">the Message of the Browser's WndProc</param>
        /// <returns>true if the message has been handled, false otherwise</returns>
        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)
            {
                string info = string.Empty;

                if (ShellHelper.LoWord(m.WParam) == (int)CMD_CUSTOM.ExpandCollapse)
                    info = "Expands or collapses the current selected item";
                else
                {
                    info = ContextMenuHelper.GetCommandString(
                        iContextMenu,
                        ShellHelper.LoWord(m.WParam) - ShellAPI.CMD_FIRST, 
                        false);
                }

                br.OnContextMenuMouseHover(new ContextMenuMouseHoverEventArgs(info.ToString()));
            }

            #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);
        }

        #endregion

        #region Events

        void FolderView_KeyDown(object sender, KeyEventArgs e)
        {
            ContextMenuHelper.ProcessKeyCommands(br, sender, e);
        }

        void FolderView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            ShellItem item = e.Node.Tag as ShellItem;

            if (!item.CanRename)
            {
                e.CancelEdit = true;
                System.Media.SystemSounds.Beep.Play();
            }
            if (item.IsDisk)
            {
                IntPtr editHandle = ShellAPI.SendMessage(br.FolderView.Handle, ShellAPI.WM.TVM_GETEDITCONTROL, 0, IntPtr.Zero);
                ShellAPI.SendMessage(editHandle, ShellAPI.WM.SETTEXT, 0, 
                    Marshal.StringToHGlobalAuto(item.Text.Substring(0, item.Text.LastIndexOf(' '))) );
            }
        }

        void FolderView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            ShellItem item = e.Node.Tag as ShellItem;

            IntPtr newPidl = IntPtr.Zero;
            if (e.Label != null && !(item.IsDisk && item.Text.Substring(0, item.Text.LastIndexOf(' ')) == e.Label) &&
                item.ParentItem.ShellFolder.SetNameOf(
                    br.Handle,
                    item.PIDLRel.Ptr,
                    e.Label,
                    ShellAPI.SHGNO.NORMAL,
                    out newPidl) == ShellAPI.S_OK)
            {
                item.Update(newPidl, ShellItemUpdateType.Renamed);
            }
            else
            {
                e.CancelEdit = true;
            }

            br.FolderView.LabelEdit = false;
        }

        /// <summary>
        /// When the mouse goes up on an node and suspendContextMenu is true, this method will show the
        /// ContextMenu for that node and after the user selects an item, it will execute that command.
        /// </summary>
        void FolderView_MouseUp(object sender, MouseEventArgs e)
        {
            if (suspendContextMenu || contextMenuVisible)
            {
                suspendContextMenu = false;
                return;
            }

            TreeViewHitTestInfo hitTest = br.FolderView.HitTest(e.Location);

            contextMenuVisible = true;
            if (e.Button == MouseButtons.Right &&
                (hitTest.Location == TreeViewHitTestLocations.Image ||
                hitTest.Location == TreeViewHitTestLocations.Label ||
                hitTest.Location == TreeViewHitTestLocations.StateImage))
            {
                #region Fields
                ShellItem item = (ShellItem)hitTest.Node.Tag;

                IntPtr contextMenu = IntPtr.Zero,
                    iContextMenuPtr = IntPtr.Zero,
                    iContextMenuPtr2 = IntPtr.Zero,
                    iContextMenuPtr3 = IntPtr.Zero;
                IShellFolder parentShellFolder =
                    (item.ParentItem != null) ? item.ParentItem.ShellFolder : item.ShellFolder;

                #endregion

                #region Show / Invoke
                try
                {
                    if (ContextMenuHelper.GetIContextMenu(parentShellFolder, new IntPtr[] { item.PIDLRel.Ptr },
                            out iContextMenuPtr, out iContextMenu))
                    {
                        contextMenu = ShellAPI.CreatePopupMenu();

                        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));

                        string topInvoke = hitTest.Node.IsExpanded ? "Collapse" : "Expand";
                        ShellAPI.MFT extraFlag = (hitTest.Node.Nodes.Count > 0) ? 0 : ShellAPI.MFT.GRAYED;
                        ShellAPI.InsertMenu(contextMenu, 0,
                            ShellAPI.MFT.BYPOSITION | extraFlag,
                            (int)CMD_CUSTOM.ExpandCollapse, topInvoke);
                        ShellAPI.InsertMenu(contextMenu, 1,
                            ShellAPI.MFT.BYPOSITION | ShellAPI.MFT.SEPARATOR,
                            0, "-");

                        ShellAPI.SetMenuDefaultItem(
                            contextMenu,
                            0,
                            true);

                        Marshal.QueryInterface(iContextMenuPtr, ref ShellAPI.IID_IContextMenu2, out iContextMenuPtr2);
                        Marshal.QueryInterface(iContextMenuPtr, ref ShellAPI.IID_IContextMenu3, out iContextMenuPtr3);

                        try
                        {
                            iContextMenu2 =
                                (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2));

                            iContextMenu3 =
                                (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3));
                        }
                        catch (Exception) { }

                        Point ptInvoke = br.FolderView.PointToScreen(e.Location);
                        uint selected = ShellAPI.TrackPopupMenuEx(
                                            contextMenu,
                                            ShellAPI.TPM.RETURNCMD,
                                            ptInvoke.X,
                                            ptInvoke.Y,
                                            this.Handle,
                                            IntPtr.Zero);

                        br.OnContextMenuMouseHover(new ContextMenuMouseHoverEventArgs(string.Empty));

                        if (selected == (int)CMD_CUSTOM.ExpandCollapse)
                        {
                            if (hitTest.Node.IsExpanded)
                                hitTest.Node.Collapse(true);
                            else
                                hitTest.Node.Expand();
                        }
                        else if (selected >= ShellAPI.CMD_FIRST)
                        {
                            string command = ContextMenuHelper.GetCommandString(
                                iContextMenu, 
                                selected - ShellAPI.CMD_FIRST, 
                                true);

                            if (command == "rename")
                            {
                                br.FolderView.LabelEdit = true;
                                hitTest.Node.BeginEdit();
                            }
                            else
                            {
                                ContextMenuHelper.InvokeCommand(
                                    iContextMenu,
                                    selected - ShellAPI.CMD_FIRST,
                                    (item.ParentItem != null) ?
                                    ShellItem.GetRealPath(item.ParentItem) : ShellItem.GetRealPath(item),
                                    ptInvoke);
                            }
                        }
                    }
                }
                #endregion
                catch (Exception) { }
                #region Finally
                finally
                {
                    if (iContextMenu != null)
                    {
                        Marshal.ReleaseComObject(iContextMenu);
                        iContextMenu = null;
                    }

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

                    if (iContextMenu3 != null)
                    {
                        Marshal.ReleaseComObject(iContextMenu3);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -