[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Windows.Forms;
using static ETCTool.NativeApi;
using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
namespace ETCTool
{
[ClassInterface(ClassInterfaceType.None)]
[Guid("B3F0615C-D04E-41DC-A1EB-4E8B8DCC14A1")]
[ComVisible(true)]
public class FileContextMenuExt : IShellExtInit, IContextMenu
{
private readonly List<NativeApi.MenuItem> ContextItems = new List<NativeApi.MenuItem>();
//用于记录文件数量
private List<string> FilePath = new List<string>();
public FileContextMenuExt()
{
ContextItems.Add(new NativeApi.MenuItem("EtcTool", true, null,
ICO.ICO.System_preferences_tool_tools_128px_581754_easyicon_net1.GetHbitmap(), ""));
ContextItems.Add(new NativeApi.MenuItem("解密打开", true, null, ICO.ICO.Start1.GetHbitmap(), "Open"));
ContextItems.Add(new NativeApi.MenuItem("解密复制", true, null, ICO.ICO.button_purple1.GetHbitmap(),
"Copy"));
ContextItems.Add(new NativeApi.MenuItem("原地解密", true, null, ICO.ICO.circle_yellow1.GetHbitmap(),
"Decrypt"));
}
//注册项目
public int QueryContextMenu(IntPtr hMenu, uint iMenu, uint idCmdFirst, uint idCmdLast, uint uFlags)
{
/* new Mutex(true, "ETCTool", out var Close);
if (!Close)
{
FileDecryptMainFun.FileDecryptFun(false);
UpdateWindow(GetWindowDC(GetDesktopWindow(IntPtr.Zero)));
SHChangeNotify(HChangeNotifyEventID.SHCNE_ALLEVENTS, HChangeNotifyFlags.SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
return 0;
}*/
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
if (((uint)CMF.CMF_DEFAULTONLY & uFlags) != 0) return 0;
// Add a separator.
/* var sep = new MENUITEMINFO();
sep.cbSize = (uint)Marshal.SizeOf(sep);
sep.fMask = MIIM.MIIM_TYPE;
sep.fType = MFT.MFT_SEPARATOR;
if (!InsertMenuItem(hMenu, 0, true, ref sep))
return Marshal.GetHRForLastWin32Error();*/
// Register item 0: Submenu
var hSubMenu = CreatePopupMenu();
var item = ContextItems[0];
RegisterMenuItem(0, idCmdFirst, item.Text, true, item.Bitmap, hSubMenu, 1, hMenu);
// Register item 1: RunDefault
item = ContextItems[1];
RegisterMenuItem(1, idCmdFirst, item.Text, true, item.Bitmap, IntPtr.Zero, 0, hSubMenu);
// Add a separator.
/* sep = new MENUITEMINFO();
sep.cbSize = (uint)Marshal.SizeOf(sep);
sep.fMask = MIIM.MIIM_TYPE;
sep.fType = MFT.MFT_SEPARATOR;
InsertMenuItem(hSubMenu, 1, true, ref sep);*/
// Register item 2 (Submenu->ManageApp).
item = ContextItems[2];
RegisterMenuItem(2, idCmdFirst, item.Text, true, item.Bitmap, IntPtr.Zero, 2, hSubMenu);
// Register item 3 (Submenu->ManageAll).
item = ContextItems[3];
RegisterMenuItem(3, idCmdFirst, item.Text, true, item.Bitmap, IntPtr.Zero, 3, hSubMenu);
/* sep = new MENUITEMINFO();
sep.cbSize = (uint)Marshal.SizeOf(sep);
sep.fMask = MIIM.MIIM_TYPE;
sep.fType = MFT.MFT_SEPARATOR;*/
return MAKE_HRESULT(0, 0, (uint)ContextItems.Count); //3个划线+4个项目
int MAKE_HRESULT(uint sev, uint fac, uint code)
{
return (int)((sev << 31) | (fac << 16) | code);
}
int RegisterMenuItem(uint id,
uint _idCmdFirst,
string text,
bool enabled,
IntPtr bitmap,
IntPtr subMenu,
uint position,
IntPtr registerTo)
{
var sub = new MENUITEMINFO();
sub.cbSize = (uint)Marshal.SizeOf(sub);
var m = MIIM.MIIM_STRING | MIIM.MIIM_FTYPE | MIIM.MIIM_ID |
MIIM.MIIM_STATE;
if (bitmap != IntPtr.Zero)
m |= MIIM.MIIM_BITMAP;
if (subMenu != IntPtr.Zero)
m |= MIIM.MIIM_SUBMENU;
sub.fMask = m;
sub.wID = _idCmdFirst + id;
sub.fType = MFT.MFT_STRING;
sub.dwTypeData = text;
sub.hSubMenu = subMenu;
sub.fState = enabled ? MFS.MFS_ENABLED : MFS.MFS_DISABLED;
sub.hbmpItem = bitmap;
if (!InsertMenuItem(registerTo, position, true, ref sub))
return Marshal.GetHRForLastWin32Error();
return 0;
}
}
//点击后命令回调
public void InvokeCommand(IntPtr pici)
{
try
{
var Index = ContextItems[
LowWord(((CMINVOKECOMMANDINFO)Marshal.PtrToStructure(pici, typeof(CMINVOKECOMMANDINFO))).verb
.ToInt32())];
if (FilePath.Count == 0) return;
try
{
var remoteDataHandle = (RemoteDataHandle)Activator.GetObject(typeof(RemoteDataHandle),
"ipc://EtcToolChannel/RemoteDataHandle");
switch (Index.Commands)
{
case "Open":
{
if (FilePath.Count != 1)
remoteDataHandle.Info("只支持打开一个文件");
else
remoteDataHandle.Open(FilePath.First());
}
break;
case "Copy":
{
remoteDataHandle.Copy(FilePath.ToArray());
}
break;
case "Decrypt":
{
remoteDataHandle.Decrypt(FilePath.ToArray());
}
break;
}
}
finally
{
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
GC.Collect();
int LowWord(int number)
{
return number & 0xffff;
}
}
public void GetCommandString(UIntPtr idCmd, uint uFlags, IntPtr pReserved, StringBuilder pszName,
uint cchMax)
{
}
//在注册菜单之前发生,用于获得各种数据
public void Initialize(IntPtr pidlFolder, IntPtr pDataObj, IntPtr hKeyProgId)
{
if (pDataObj == IntPtr.Zero)
{
Variables.MainForm.OntherLog.Add(new[] { $"{DateTime.Now:hh:mm:ss}->发生未知错误在获得数据时", "" });
return;
}
var fe = new FORMATETC
{
cfFormat = 15,
ptd = IntPtr.Zero,
dwAspect = DVASPECT.DVASPECT_CONTENT,
lindex = -1,
tymed = TYMED.TYMED_HGLOBAL
};
STGMEDIUM stm;
var dataObject = (IDataObject)Marshal.GetObjectForIUnknown(pDataObj);
dataObject.GetData(ref fe, out stm);
try
{
var hDrop = stm.unionmember;
if (hDrop == IntPtr.Zero) throw new ArgumentException();
var nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, null, 0); //获得选中文件数
if (nFiles != 0)
{
FilePath = new List<string>();
for (uint i = 0; i <= nFiles - 1; i++)
{
var fileName = new StringBuilder(1024);
if (DragQueryFile(hDrop,
i,
fileName,
fileName.Capacity) != 0)
FilePath.Add(fileName.ToString());
}
}
}
finally
{
ReleaseStgMedium(ref stm);
}
}
}
#region 右键菜单的接口
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e8-0000-0000-c000-000000000046")]
internal interface IShellExtInit //接收explorer传递的信息
{
void Initialize(
IntPtr /*LPCITEMIDLIST*/ pidlFolder,
IntPtr /*LPDATAOBJECT*/ pDataObj,
IntPtr /*HKEY*/ hKeyProgId);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e4-0000-0000-c000-000000000046")]
internal interface IContextMenu //实现右键扩展
{
[PreserveSig]
int QueryContextMenu(
IntPtr /*HMENU*/ hMenu,
uint iMenu,
uint idCmdFirst,
uint idCmdLast,
uint uFlags);
void InvokeCommand(IntPtr pici);
void GetCommandString(
UIntPtr idCmd,
uint uFlags,
IntPtr pReserved,
StringBuilder pszName,
uint cchMax);
}
#endregion 右键菜单的接口
#region 文件右键管理用API
public class NativeApi
{
#region 各种结构体
[Flags]
internal enum CMF : uint
{
CMF_NORMAL = 0x00000000,
CMF_DEFAULTONLY = 0x00000001,
CMF_VERBSONLY = 0x00000002,
CMF_EXPLORE = 0x00000004,
CMF_NOVERBS = 0x00000008,
CMF_CANRENAME = 0x00000010,
CMF_NODEFAULT = 0x00000020,
CMF_INCLUDESTATIC = 0x00000040,
CMF_ITEMMENU = 0x00000080,
CMF_EXTENDEDVERBS = 0x00000100,
CMF_DISABLEDVERBS = 0x00000200,
CMF_ASYNCVERBSTATE = 0x00000400,
CMF_OPTIMIZEFORINVOKE = 0x00000800,
CMF_SYNCCASCADEMENU = 0x00001000,
CMF_DONOTPICKDEFAULT = 0x00002000,
CMF_RESERVED = 0xFFFF0000
}
[Flags]
internal enum CMIC : uint
{
CMIC_MASK_ICON = 0x00000010,
CMIC_MASK_HOTKEY = 0x00000020,
CMIC_MASK_NOASYNC = 0x00000100,
CMIC_MASK_FLAG_NO_UI = 0x00000400,
CMIC_MASK_UNICODE = 0x00004000,
CMIC_MASK_NO_CONSOLE = 0x00008000,
CMIC_MASK_ASYNCOK = 0x00100000,
CMIC_MASK_NOZONECHECKS = 0x00800000,
CMIC_MASK_FLAG_LOG_USAGE = 0x04000000,
CMIC_MASK_SHIFT_DOWN = 0x10000000,
CMIC_MASK_PTINVOKE = 0x20000000,
CMIC_MASK_CONTROL_DOWN = 0x40000000
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CMINVOKECOMMANDINFO
{
public uint cbSize;
public CMIC fMask;
public IntPtr hwnd;
public IntPtr verb;
[MarshalAs(UnmanagedType.LPStr)] public string parameters;
[MarshalAs(UnmanagedType.LPStr)] public string directory;
public int nShow;
public uint dwHotKey;
public IntPtr hIcon;
}
[Flags]
public enum MIIM : uint
{
MIIM_STATE = 0x00000001,
MIIM_ID = 0x00000002,
MIIM_SUBMENU = 0x00000004,
MIIM_CHECKMARKS = 0x00000008,
MIIM_TYPE = 0x00000010,
MIIM_DATA = 0x00000020,
MIIM_STRING = 0x00000040,
MIIM_BITMAP = 0x00000080,
MIIM_FTYPE = 0x00000100
}
public enum MFT : uint
{
MFT_STRING = 0x00000000,
MFT_BITMAP = 0x00000004,
MFT_MENUBARBREAK = 0x00000020,
MFT_MENUBREAK = 0x00000040,
MFT_OWNERDRAW = 0x00000100,
MFT_RADIOCHECK = 0x00000200,
MFT_SEPARATOR = 0x00000800,
MFT_RIGHTORDER = 0x00002000,
MFT_RIGHTJUSTIFY = 0x00004000
}
[Flags]
public enum MFS : uint
{
MFS_ENABLED = 0x00000000,
MFS_UNCHECKED = 0x00000000,
MFS_UNHILITE = 0x00000000,
MFS_GRAYED = 0x00000003,
MFS_DISABLED = 0x00000003,
MFS_CHECKED = 0x00000008,
MFS_HILITE = 0x00000080,
MFS_DEFAULT = 0x00001000
}
public struct MenuItem
{
internal IntPtr Bitmap;
internal string Commands;
internal bool? ShowInMainMenu;
internal string Text;
internal bool Enabled;
internal MenuItem(string text, bool enabled, bool? showInMainMenu, IntPtr bitmap, string commands)
{
ShowInMainMenu = showInMainMenu;
Text = text;
Enabled = enabled;
Bitmap = bitmap;
Commands = commands;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MENUITEMINFO
{
public uint cbSize;
public MIIM fMask;
public MFT fType;
public MFS fState;
public uint wID;
public IntPtr hSubMenu;
public IntPtr hbmpChecked;
public IntPtr hbmpUnchecked;
public UIntPtr dwItemData;
public string dwTypeData;
public uint cch;
public IntPtr hbmpItem;
}
[Flags]
public enum HChangeNotifyFlags
{
SHCNF_DWORD = 0x0003,
SHCNF_IDLIST = 0x0000,
SHCNF_PATHA = 0x0001,
SHCNF_PATHW = 0x0005,
SHCNF_PRINTERA = 0x0002,
SHCNF_PRINTERW = 0x0006,
SHCNF_FLUSH = 0x1000,
SHCNF_FLUSHNOWAIT = 0x2000
}
[Flags]
public enum HChangeNotifyEventID
{
SHCNE_ALLEVENTS = 0x7FFFFFFF,
SHCNE_ASSOCCHANGED = 0x08000000,
SHCNE_ATTRIBUTES = 0x00000800,
SHCNE_CREATE = 0x00000002,
SHCNE_DELETE = 0x00000004,
SHCNE_DRIVEADD = 0x00000100,
SHCNE_DRIVEADDGUI = 0x00010000,
SHCNE_DRIVEREMOVED = 0x00000080,
SHCNE_EXTENDED_EVENT = 0x04000000,
SHCNE_FREESPACE = 0x00040000,
SHCNE_MEDIAINSERTED = 0x00000020,
SHCNE_MEDIAREMOVED = 0x00000040,
SHCNE_MKDIR = 0x00000008,
SHCNE_NETSHARE = 0x00000200,
SHCNE_NETUNSHARE = 0x00000400,
SHCNE_RENAMEFOLDER = 0x00020000,
SHCNE_RENAMEITEM = 0x00000001,
SHCNE_RMDIR = 0x00000010,
SHCNE_SERVERDISCONNECT = 0x00004000,
SHCNE_UPDATEDIR = 0x00001000,
SHCNE_UPDATEIMAGE = 0x00008000
}
#endregion 各种结构体
[DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InsertMenuItem(IntPtr hMenu, uint uItem,
[MarshalAs(UnmanagedType.Bool)] bool fByPosition,
ref MENUITEMINFO mii);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreatePopupMenu();
[DllImport("shell32", CharSet = CharSet.Unicode)]
public static extern uint DragQueryFile(
IntPtr hDrop,
uint iFile,
StringBuilder pszFile,
int cch);
[DllImport("ole32.dll", CharSet = CharSet.Unicode)]
public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("shell32.dll")]
public static extern void SHChangeNotify(HChangeNotifyEventID wEventId, HChangeNotifyFlags uFlags,
IntPtr dwItem1, IntPtr dwItem2);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
#endregion 文件右键管理用API
}
}