【问题标题】:ContextMenu Handler in Explorer's left panelExplorer 左侧面板中的 ContextMenu 处理程序
【发布时间】:2023-04-04 16:33:01
【问题描述】:

我正在尝试使用 c++ 编写上下文菜单处理程序。我希望处理程序能够处理所有文件和所有文件夹,以及资源管理器左窗格中的那些。 我开始基于我试图适应我的需求的 CodeProject 项目。我是从here 那里得到的。

到目前为止,一切似乎都按预期工作,除了资源管理器左窗格的文件夹。 在那里我得到一个 AccessViolationException。右键单击和上下文菜单显示之间发生异常。 我删除了不同函数中的代码,直到它再次工作,似乎问题来自 QueryContextMenu 方法。

有人知道我做错了吗?

这是我当前有效的代码(有点明显,因为没有添加任何项目):

STDMETHODIMP ShellExt::Initialize (LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID )
{
    FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    STGMEDIUM stg = { TYMED_HGLOBAL };
    HDROP     hDrop;

    // Look for CF_HDROP data in the data object.
    if ( FAILED( pDataObj->GetData ( &fmt, &stg ) ))
    {
        // Nope! Return an "invalid argument" error back to Explorer.
        return E_INVALIDARG;
    }

    // Get a pointer to the actual data.
    hDrop = (HDROP) GlobalLock ( stg.hGlobal );

    // Make sure it worked.
    if ( NULL == hDrop )
        return E_INVALIDARG;

    // Sanity check - make sure there is at least one filename.
    UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
    HRESULT hr = S_OK;

    if ( 0 == uNumFiles )
    {
        GlobalUnlock ( stg.hGlobal );
        ReleaseStgMedium ( &stg );
        return E_INVALIDARG;
    }

    // Get the name of the first file and store it in our member variable m_szFile.
    if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH ) )
        hr = E_INVALIDARG;

    GlobalUnlock ( stg.hGlobal );
    ReleaseStgMedium ( &stg );

    return hr;
}

STDMETHODIMP ShellExt::QueryContextMenu (HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
    return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
}

STDMETHODIMP ShellExt::GetCommandString (UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
    return E_INVALIDARG;
}

STDMETHODIMP ShellExt::InvokeCommand (LPCMINVOKECOMMANDINFO pCmdInfo)
{
    return S_OK;
}

但是现在如果我在 ShellExt::QueryContextMenu 中添加一个项目,资源管理器的左窗格会引发异常,而右窗格中的文件和文件夹工作得很好。 我尝试了在互联网上找到的以下两个版本,但都有相同的问题:

STDMETHODIMP ShellExt::QueryContextMenu (HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
    // If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
    if ( uFlags & CMF_DEFAULTONLY )
        return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );

    InsertMenu ( hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, _T("Test Item") );

    return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 1 );
}

STDMETHODIMP ShellExt::QueryContextMenu (HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
    // If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
    if ( uFlags & CMF_DEFAULTONLY )
        return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );

    UINT uID = uidFirstCmd;
    UINT pos = uMenuIndex;

    MENUITEMINFO mii = { sizeof(mii) };
    mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
    mii.fType = MFT_STRING;
    mii.dwTypeData = _T("Menu 1");
    mii.fState = MFS_ENABLED;
    mii.wID = uID++;

    if (!InsertMenuItem(hmenu, pos++, TRUE, &mii))
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

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

我在 QueryContextMenu 中得到的参数:
- hmenu = 0x0000000001480405
- uMenuInde​​x = 3
- uidFirstCmd = 148
- uidLastCmd = 32762
- uFlags = 1044

异常详情。

QueryContextMenu 和 GetCommandString 中的代码被执行。异常发生在这之后的某个地方,但仍然在上下文菜单可见之前。不幸的是,这些细节对我来说意义不大:

在 explorer.exe 中的 0x00007FF9B1C4C613 (shell32.dll) 处引发异常:0xC0000005:访问冲突读取位置 0x00007FF9776D9868。发生了

堆栈跟踪:

shell32.dll!00007ff9b1c4c613()  
ExplorerFrame.dll!00007ff98d24993a()  
ExplorerFrame.dll!00007ff98d2c69a4()  
ExplorerFrame.dll!00007ff98d24de6c()  
ExplorerFrame.dll!00007ff98d251286()  
ExplorerFrame.dll!00007ff98d1fbad0()  
ExplorerFrame.dll!00007ff98d1ad5b3()  
ExplorerFrame.dll!00007ff98d180f2e()  
user32.dll!00007ff9b079ca66()  
user32.dll!00007ff9b079c34b()  
comctl32.dll!00007ff99d78b0da()  
comctl32.dll!00007ff99d78b017()  
ExplorerFrame.dll!00007ff98d187521()  
ExplorerFrame.dll!00007ff98d17d2e0()  
comctl32.dll!00007ff99d78b0da()  
comctl32.dll!00007ff99d78aef2()  
user32.dll!00007ff9b079ca66()  
user32.dll!00007ff9b079c34b()  
duser.dll!00007ff98106dff5()  
atlthunk.dll!00007ff983061208()  
user32.dll!00007ff9b079ca66()  
user32.dll!00007ff9b079c78c()  
user32.dll!00007ff9b07afa83()  
ntdll.dll!00007ff9b34833a4()  
win32u.dll!00007ff9b0071184()  
user32.dll!00007ff9b079bfbe()  
user32.dll!00007ff9b079be38()  
comctl32.dll!00007ff99d77a099()  
comctl32.dll!00007ff99d80b556()  
comctl32.dll!00007ff99d7b1302()  
user32.dll!00007ff9b079ca66()  
user32.dll!00007ff9b079c34b()  
comctl32.dll!00007ff99d78b0da()  
comctl32.dll!00007ff99d78b017()  
ExplorerFrame.dll!00007ff98d1bf33b()  
ExplorerFrame.dll!00007ff98d1bf27b()  
comctl32.dll!00007ff99d78b0da()  
comctl32.dll!00007ff99d78aef2()  
user32.dll!00007ff9b079ca66()  
user32.dll!00007ff9b079c582()  
ExplorerFrame.dll!00007ff98d1748a3()  
ExplorerFrame.dll!00007ff98d1747a9()  
ExplorerFrame.dll!00007ff98d1746f6()  
ExplorerFrame.dll!00007ff98d175a12()  
ExplorerFrame.dll!00007ff98d1870c2()  
windows.storage.dll!00007ff9af8db38c()  
windows.storage.dll!00007ff9af8db045()  
windows.storage.dll!00007ff9af8daf25()  
SHCore.dll!00007ff9b164c315()  
kernel32.dll!00007ff9b06281f4()  
ntdll.dll!00007ff9b344a251()

【问题讨论】:

  • 那么这个异常发生在哪一行呢?调用堆栈是什么样的?什么是函数参数?
  • 您可以从 Visual Studio 调试资源管理器进程 (explorer.exe),以便了解错误发生的位置/时间。或者你能提供一个最小的完整重现代码吗?
  • @SimonMourier 我从 CodeProject 下载的项目中已经出现了同样的问题,这个问题已经很小了。所以我只是更改了注册功能以将其注册为文件夹。如何通过该更改传输解决方案?
  • shell 扩展的普遍问题是你不是唯一一个想到它的人。程序员的机器尤其容易出现错误,这是您以前从未注意到的。你需要一个更好的堆栈跟踪,谷歌“visual-c++ 如何启用符号服务器”。
  • 感谢大家花时间考虑我的问题。感谢 Hans 的建议,它肯定会对我遇到的下一个错误有所帮助:)

标签: c++ contextmenu access-violation shell-extensions


【解决方案1】:

看来我解决了这个问题。我重新设计了项目的其余部分,即 IClassFactory 的实现以及 shellextension 类的 IUnknown 接口的实现,目的是了解这些“东西”在该项目中的用途。

这样做时,我发现了一些错误、未初始化的变量、强制类型转换等。我还将一些计数器从 UINT 更改为 LONG,以便我可以使用 InterlockedIncrement 而不是 ++。在那之后,问题似乎消失了。我不能再确切地说是什么错误导致了 AccessViolationException,但最后它不像我想的那样在 QueryContextMenu 方法中......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    • 2021-07-08
    • 1970-01-01
    • 2017-02-01
    • 2016-03-20
    相关资源
    最近更新 更多