微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

嗨,当我从外壳上下文菜单获取所有项时,我就在.NET程序中实现了IShellFolder com接口。但是我有一个问题,我的跟踪外壳上下文菜单与资源管理器外壳上下文菜单有一些不同的项目。在下面的图片中,您已经看到在我的程序中我没有查看在程序子菜单中打开。我只有一项“在程序中打开”。在我的上下文菜单中,缺少在“记事本++中打开”功能,此外我还有其他一些项目,例如7-zip项目和子菜单以及7-zip程序中的CRC SHA。

第一张图片是Windows资源管理器中的shell上下文菜单,第二张图片是我的shell上下文菜单代码

您能告诉我哪里有错误吗?非常感谢。

Shell Context Menu from windows explorer

Shell Context Menu from 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,1,30000,CMF.EXPLORE | CMF.CANRENAME | CMF.norMAL | CMF.INCLUDESTATIC | CMF.EXTENDEDVERBS);
            int count = Win32APICaller.GetMenuItemCount(pMenu);

            //contextMenu3.QueryContextMenu(pMenu,/*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,folderName,ref pdwAttributes);
        if (nResult == 0)
        {
            IntPtr pStrRet = Marshal.AllocCoTaskMem(260 * 2 + 4);
            Marshal.WriteInt32(pStrRet,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,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,IID_IContextMenu,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.LParam);
    }

    base.WndProc(ref m);
}

解决方法

在下面的图片中,您已经看到在我的程序中我没有查看 在程序子菜单中打开。我只有一项“在程序中打开”。

enter image description here

原因是这些子菜单是延迟生成的(这说明了为什么在展开它们时它们不包含任何有趣的内容)并由所有者绘制。

所以您需要handle messages associated with owner-drawn menu items

此后,您将获得预期的结果:

enter image description here

以下是您可以参考的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,&id,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,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,lParam))) {
            return 0;
        }
    }


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

我已经找到了无法在上下文菜单中查看“使用记事本++编辑”项的原因。我需要将代码编译为 x64体系结构。完成此操作后,上下文菜单中将显示“使用记事本++编辑”和缺少7个zip的项目。

当我在Internet上找到时,我发现这取决于程序体系结构,并且我已在上下文菜单中将Notepad ++注册为 x64体系结构

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。