【发布时间】:2020-12-26 13:35:46
【问题描述】:
您好,当我从 shell 上下文菜单中获取所有项目时,我在 .NET 程序中实现了 IShellFolder com 接口。但是我有一个问题,我的跟踪外壳上下文菜单与资源管理器外壳上下文菜单有一些不同的项目。在下面的图片中,您已经看到在我的程序中我没有在程序子菜单中查看打开。我只有一项“在程序中打开”。在我的上下文菜单中缺少 Open in Notepad++ 并且我还有一些其他项目,如 7-zip 项目和子菜单以及来自 7-zip 程序的 CRC SHA。
第一张图片是来自 Windows 资源管理器的 shell 上下文菜单,第二张图片来自我的 shell 上下文菜单代码。
你能告诉我哪里出错了吗?非常感谢。
这是我的代码:
private ContextMenu CreateFileContextMenu(FileInfo[] files, Point location)
{
Win32APICaller.CoInitializeEx(IntPtr.Zero, COINIT.MULTITHREADED);
IShellFolder parentFolder = GetParentFolder(files[0].DirectoryName);
IntPtr[] pidls = this.GetPIDLs(parentFolder, files);
IntPtr pMenu = IntPtr.Zero;
IntPtr iContextMenuPtr = IntPtr.Zero;
IntPtr iContextMenuPtr2 = IntPtr.Zero;
IntPtr iContextMenuPtr3 = IntPtr.Zero;
if (pidls != null)
{
IContextMenu contextMenu;
if (this.GetContextMenuInterfaces(parentFolder, pidls, out contextMenu, out iContextMenuPtr))
{
pMenu = Win32APICaller.CreatePopupMenu();
Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu2, out iContextMenuPtr2);
Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu3, out iContextMenuPtr3);
contextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2));
contextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3));
int nResult = contextMenu.QueryContextMenu(pMenu, 0, 1, 30000, CMF.EXPLORE | CMF.CANRENAME | CMF.NORMAL | CMF.INCLUDESTATIC | CMF.EXTENDEDVERBS);
int count = Win32APICaller.GetMenuItemCount(pMenu);
//contextMenu3.QueryContextMenu(pMenu, 0, 1, 30000, /*CMF.EXPLORE | CMF.NORMAL |*/ CMF.EXTENDEDVERBS);
count = Win32APICaller.GetMenuItemCount(pMenu);
Win32APICaller.SendMessage(this.Handle, WM_INITMENUPOPUP, pMenu, 0);
uint nSelected = Win32APICaller.TrackPopupMenuEx(pMenu, 0x0100, location.X, location.Y, this.Handle, IntPtr.Zero);
}
}
}
private IntPtr[] GetPIDLs(IShellFolder parentFolder, FileInfo[] files)
{
if (parentFolder != null)
{
IntPtr[] pidls = new IntPtr[files.Length];
for (int index = 0; index < files.Length; index++)
{
FileInfo fileInfo = files[index];
uint pchEaten = 0;
SFGAO pdwAttributes = 0;
IntPtr pPIDL = IntPtr.Zero;
int nResult = parentFolder.ParseDisplayName(this.Handle, IntPtr.Zero, fileInfo.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
if (nResult == 0)
{
pidls[index] = pPIDL;
}
}
return pidls;
}
return null;
}
private IShellFolder GetParentFolder(string folderName)
{
IShellFolder desktopFolder = this.GetDektopFolder();
if (desktopFolder != null)
{
IntPtr pPIDL = IntPtr.Zero;
uint pchEaten = 0;
SFGAO pdwAttributes = 0;
int nResult = desktopFolder.ParseDisplayName(this.Handle, IntPtr.Zero, folderName, ref pchEaten, out pPIDL, ref pdwAttributes);
if (nResult == 0)
{
IntPtr pStrRet = Marshal.AllocCoTaskMem(260 * 2 + 4);
Marshal.WriteInt32(pStrRet, 0, 0);
nResult = desktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet);
StringBuilder strFolder = new StringBuilder(260);
Win32APICaller.StrRetToBuf(pStrRet, pPIDL, strFolder, 260);
Marshal.FreeCoTaskMem(pStrRet);
pStrRet = IntPtr.Zero;
IntPtr pUnknownParentFolder = IntPtr.Zero;
nResult = desktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref IID_IShellFolder, out pUnknownParentFolder);
Marshal.FreeCoTaskMem(pPIDL);
if (nResult == 0)
{
return (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder));
}
}
}
return null;
}
private IShellFolder GetDektopFolder()
{
IntPtr pUnknownDesktopFolder = IntPtr.Zero;
int nResult = Win32APICaller.SHGetDesktopFolder(out pUnknownDesktopFolder);
if (nResult == 0)
return (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownDesktopFolder, typeof(IShellFolder));
else
return null;
}
private bool GetContextMenuInterfaces(IShellFolder parentFolder, IntPtr[] pidls, out IContextMenu contextMenu, out IntPtr contextMenuPtr)
{
int nResult = parentFolder.GetUIObjectOf(this.Handle, (uint)pidls.Length, pidls, IID_IContextMenu, IntPtr.Zero, out contextMenuPtr);
contextMenu = null;
if (nResult == 0)
{
contextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(contextMenuPtr, typeof(IContextMenu));
return true;
}
return false;
}
protected override void WndProc(ref Message m)
{
if (this.contextMenu3 != null)
{
this.contextMenu3.HandleMenuMsg2((uint)m.Msg, m.WParam, m.LParam, m.Result);
}
else if (this.contextMenu2 != null)
{
this.contextMenu2.HandleMenuMsg((uint)m.Msg, m.WParam, m.LParam);
}
base.WndProc(ref m);
}
【问题讨论】:
-
您是否尝试添加 CMF_EXTENDEDVERBS?
-
对于不同的文件类型,不同的位置,上下文菜单会有所不同。您在说什么文件类型和文件资源管理器位置?
-
确保您的窗口处理像
WM_INITMENUPOPUP这样的菜单消息并将它们传递给IContextMenu2::HandleMenuMsg。 -
两个选项都针对相同的文件和位置。我已经尝试过 CMF_EXTENDEDVERBS 并且只有一个区别是上下文菜单中添加了一项。
-
这可能非常复杂,取决于您的 IShellFolder 是如何实现的,它具有什么类型的项目(SFGAO 标志、FILESYSTEM 等),还有父项目等。您如何创建IContextMenu/2/3,你回答 IQueryAssociations 等。你有最小的完整重现代码吗?
标签: c# .net winapi shell-extensions