简体   繁体   English

不同的 Shell 上下文菜单与 Windows 资源管理器上下文菜单

[英]Different Shell Context Menu versus windows explorer context menu

Hi I have implementation of the IShellFolder com interface in my .NET program when I have get all items from shell context menu.嗨,当我从 shell 上下文菜单中获取所有项目时,我在我的 .NET 程序中实现了 IShellFolder com 接口。 But I have a problem where my tracking shell context menu have some different items versus explorer shell context menu.但是我有一个问题,我的跟踪 shell 上下文菜单与资源管理器 shell 上下文菜单有一些不同的项目。 In the pictures below you have seen that in my program I do not view Open in program sub menu.在下面的图片中,您已经看到在我的程序中我没有在程序子菜单中查看打开。 I have only one item "Open in program".我只有一项“在程序中打开”。 And in my context menu missing Open in Notepad++ and I have in addition some other items like 7-zip item and submenu and CRC SHA from 7-zip program too.在我的上下文菜单中缺少在 Notepad++ 中打开,我还有一些其他项目,如 7-zip 项目和子菜单以及来自 7-zip 程序的 CRC SHA。

The first picture is shell context menu from windows explorer and the second picture is from my shell context menu code.第一张图片是来自 Windows 资源管理器的 shell 上下文菜单,第二张图片来自我的 shell 上下文菜单代码。

Can you tell me where I have an error?你能告诉我哪里有错误吗? Thank you very much.非常感谢。

Windows 资源管理器中的 Shell 上下文菜单

我的代码中的 Shell 上下文菜单

And this is my code:这是我的代码:

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

In the pictures below you have seen that in my program I do not view Open in program sub menu.在下面的图片中,您已经看到在我的程序中我没有在程序子菜单中查看打开。 I have only one item "Open in program".我只有一项“在程序中打开”。

在此处输入图片说明

The reason for this is that these submenus are delay-generated (which explains why they don't contain anything interesting when you expand them) and owner-drawn.这样做的原因是这些子菜单是延迟生成的(这解释了为什么当您展开它们时它们不包含任何有趣的内容)并且是所有者绘制的。

So you need tohandle messages associated with owner-drawn menu items .所以你需要处理与自绘菜单项相关的消息

After that you will get what you expected like this:之后你会得到你所期望的:

在此处输入图片说明

The following is an Win32 C++ sample code you can refer to:以下是Win32 C++示例代码,大家可以参考:

#define SCRATCH_QCM_FIRST 1
#define SCRATCH_QCM_LAST  0x7FFF

IContextMenu2* g_pcm2;
IContextMenu3* g_pcm3;

//...

void OnContextMenu(HWND hwnd, int xPos, int yPos)
{
    WCHAR pszFilePath[] = L"C:\\Users\\me\\Desktop\\test1.txt";
    IShellFolder* psfDesktop = NULL;
    ITEMIDLIST* id = 0;
    LPCITEMIDLIST idChild = 0;
    IContextMenu* pcm = NULL;
    int iCmdTemp = 0;

    POINT pt = { xPos, yPos };
    if (pt.x == -1 && pt.y == -1) {
        pt.x = pt.y = 0;
        ClientToScreen(hwnd, &pt);
    }

    SHParseDisplayName(pszFilePath, 0, &id, 0, 0);
    SHBindToParent(id, IID_IShellFolder, (void**)& psfDesktop, &idChild);

    psfDesktop->GetUIObjectOf(hwnd, 1, (const ITEMIDLIST **)&idChild, __uuidof(IContextMenu), NULL, (void **)&pcm);

    if (pcm) {
        HMENU hmenu = CreatePopupMenu();
        if (hmenu) {
            if (SUCCEEDED(pcm->QueryContextMenu(hmenu, 0,
                SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST,
                CMF_NORMAL))) {

                pcm->QueryInterface(IID_IContextMenu2, (void**)& g_pcm2);
                pcm->QueryInterface(IID_IContextMenu3, (void**)& g_pcm3);

                int iCmd = TrackPopupMenuEx(hmenu, TPM_RETURNCMD,
                    pt.x, pt.y, hwnd, NULL);
                if (g_pcm2) {
                    g_pcm2->Release();
                    g_pcm2 = NULL;
                }
                if (g_pcm3) {
                    g_pcm3->Release();
                    g_pcm3 = NULL;
                }
                if (iCmd > 0) {
                    CMINVOKECOMMANDINFOEX info = { 0 };
                    info.cbSize = sizeof(info);
                    info.fMask = 0x00004000;
                    info.hwnd = hwnd;
                    iCmdTemp = iCmd - SCRATCH_QCM_FIRST;
                    info.lpVerb = MAKEINTRESOURCEA(iCmdTemp);
                    info.lpVerbW = MAKEINTRESOURCEW(iCmdTemp);
                    info.nShow = SW_SHOWNORMAL;
                    pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)& info);
                }

            }
            DestroyMenu(hmenu);
        }
        pcm->Release();
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int xPos;
    int yPos;

    if (g_pcm3) {
        LRESULT lres;
        if (SUCCEEDED(g_pcm3->HandleMenuMsg2(message, wParam, lParam, &lres))) {
            return lres;
        }
    }
    else if (g_pcm2) {
        if (SUCCEEDED(g_pcm2->HandleMenuMsg(message, wParam, lParam))) {
            return 0;
        }
    }


    switch (message)
    {
    case WM_CONTEXTMENU:
        xPos = GET_X_LPARAM(lParam);
        yPos = GET_Y_LPARAM(lParam);
        OnContextMenu(hWnd, xPos, yPos);
        break;
//...

I have found the reason why could not view the Edit with Notepad++ item in the Context Menu.我找到了无法在上下文菜单中查看使用 Notepad++ 编辑项的原因。 I need compile my code as the x64 architecture .我需要将我的代码编译为x64 架构 And when I have done this the context menu view the Edit with Notepad++ and the 7-zip items missing.当我完成此操作后,上下文菜单会查看使用 Notepad++ 进行编辑和缺少的 7-zip 项目。

When I find on the internet I have found that depends on the program architecture and I have registered the Notepad++ in the context menu as x64 architecture only .当我在互联网上找到时,我发现这取决于程序体系结构,并且我已在上下文菜单中将 Notepad++ 注册为x64 体系结构 only

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM