Winapi shell扩展覆盖Windows命令

时间:2012-07-11 23:56:35

标签: c++ c windows winapi contextmenu

我为我正在开发的一个小应用程序开发了一个非常基本的shell扩展。我已经使用它一段时间没有任何问题,但我只是注意到在Windows XP中,在开始菜单中 - >所有程序,如果我右键单击那里的文件夹并选择“打开”或“浏览”,我的小应用程序将显示而不是浏览器窗口。你可以想象当我看到这个时,我是多么高兴和自豪。我觉得很奇怪,因为这是它发生的唯一地方(到目前为止......)。我在“目录”注册表项下注册了shell扩展,因此只有在右键单击文件夹时才会显示。

我发现了一些关于shell扩展的好文章,到目前为止,我已经发现了这些文章,但是我在这个winapi的东西中远远不及我的舒适区域。我做了很多摆弄id,但我无法弄清楚问题是什么。

这是我的querycontextmenu实现,我希望我在那里犯了一个愚蠢的错误,一个c ++大师可以马上发现。任何帮助将不胜感激。

STDMETHODIMP ShellExtension::QueryContextMenu(HMENU hMenu,  UINT indexMenu,  UINT idCmdFirst,  UINT idCmdLast, UINT uFlags){
if (CMF_DEFAULTONLY & uFlags)
{
    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
}

UINT uID = idCmdFirst;

if (!InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
{
    return HRESULT_FROM_WIN32(GetLastError());
}

HMENU hSubmenu = CreatePopupMenu();

InsertMenu (hSubmenu, 0, MF_BYPOSITION, uID++, (this->isFrench ? SET_REF_TEXT : SET_REF_TEXT_EN));
InsertMenu (hSubmenu, 1, MF_BYPOSITION, uID++, (this->isFrench ? SET_COMP_TEXT : SET_COMP_TEXT_EN));

MENUITEMINFO mii = { sizeof(mii) };
mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP | MIIM_SUBMENU | MIIM_DATA | MIIM_STRING;
mii.hSubMenu = hSubmenu;
mii.fType = MFT_STRING;
mii.dwTypeData = (this->isFrench ? MAIN_TEXT : MAIN_TEXT_EN);
mii.hbmpItem = IsRequirePainting() ? HBMMENU_CALLBACK : m_hMenuBmp;
mii.wID = uID++;

if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
{
    return HRESULT_FROM_WIN32(GetLastError());
}

if (!InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
{
    return HRESULT_FROM_WIN32(GetLastError());
}

return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uID - idCmdFirst);}

谢谢!

编辑:

这个解决方案对我有用......对于任何在这里磕磕绊绊的人:

STDMETHODIMP ShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
    if (!HIWORD(lpcmi->lpVerb))
    {
        UINT idCmd = LOWORD(lpcmi->lpVerb);

        switch (idCmd)
        {
        case 0:
            doStuffForFirstCommand();
            break;
        case 1:
            doStuffForSecondCommand();
            break;
        }

        return S_OK;
    }
    else
    {
        return E_INVALIDARG; //this is what I forgot...
    }
}

感谢帮助和对不起代码缩进,好像我无法弄清楚代码标签。

1 个答案:

答案 0 :(得分:3)

我将在一个真实的答案中总结上面的讨论:

除了由直接用户操作调用外,还可以通过其他几种方式调用上下文菜单扩展。当用户在Windows资源管理器中右键单击某个项目时,如果选择其中一个shell的内置动词(如“打开”或“打印”),Windows将依次查询每个已注册的shell扩展以找到处理它的那个。如果用户调用ShellExecute以编程方式调用动词,则会发生同样的事情。

这允许第三方开发人员在shell的词汇表中添加新动词,但如果shell扩展不处理这种情况也会产生问题。

当上下文菜单处理程序的InvokeCommand方法未检查其参数时,会出现问题。以下是CMINVOKECOMMANDINFO关于lpVerb成员(强调我的)的文档的说明:

  

如果高位字不为零,则此成员是以空字符结尾的字符串的地址,该字符串指定要执行的命令的与语言无关的名称。当应用程序激活命令时,此成员通常是一个字符串。系统为以下命令字符串提供预定义的常量值。

     

这不是一个固定的集合;新的规范动词可以由上下文菜单处理程序发明,应用程序可以调用它们。

     

如果存在规范动词且菜单处理程序未实现规范动词,则必须返回失败代码以使下一个处理程序能够处理此动词。如果不这样做,将会破坏系统中的功能,包括ShellExecute

Raymond Chen的博客文章"Sure, we do that: Context menu edition"描述了在这种情况下可能发生的事情。他还指出了一个不幸的事实,即足够的shell扩展表现出这种不礼貌的行为,Windows团队创建了special registry key来帮助处理这些错误。

当然,如果您是开发人员,则应确保检查InvokeCommand的参数并返回正确的代码,而不是依赖于注册表解决方法。