📄 browsercontextmenuwrappers.cs
字号:
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 + -