Search code examples
c++shellwinapicontextmenushell-extensions

IContextMenu::QueryContextMenu not called by Shell (Win10)


I have a class called ValidatorContextMenuHandler that implements the IShellExtInit and IContextMenu interfaces.

My DLL is being referenced in the Registry, and gets loaded into Windows Explorer correctly. I check this by creating MessageBoxes whenever a method is being called. When I right click on a file, I also get notified of my ContextMenuHandler being instantiated. So, IShellExtInit::Initialize() is indeed being called (twice, actually). My implementation of IShellExtInit::Initialize() looks like the following:

IFACEMETHODIMP ValidatorContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hKeyProgID)
{
    MessageBox(NULL, L"ContextMenuHandler Initialized!", L"Notice", MB_OK);
    return S_OK;
}

However, after that nothing happens. IContextMenu::QueryContextMenu() is never being called, and I cannot find the cause. The first line of QueryContextMenu() should bring up a MessageBox, but it never gets to that point in the first place.

My implementation of the method looks like the following:

STDMETHODIMP ValidatorContextMenuHandler::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
    MessageBox(NULL, L"QUERYING CONTEXT MENU", L"ValidatorContextMenuHandler::QueryContextMenu()", MB_OK);

    //...Removed the unnecessary code after this, so that the post doesn't get too long
}

There are no compiling errors, and the DLL I tested on is the newest version (unloaded DLL with regsvr32 /u, restarted Windows Explorer, loaded DLL with regsvr32).

For those wanting to see my header file:

#pragma once
#include<Windows.h>
#include<ShlObj.h>

extern UINT g_cObjCount;

class ValidatorContextMenuHandler : public IShellExtInit, IContextMenu
{
protected:
    DWORD m_ObjRefCount;
    ~ValidatorContextMenuHandler();

public:
    ValidatorContextMenuHandler();

    //IUnknown Methods
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
    HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject);

    //IShellExtInit Methods
    IFACEMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hKeyProgID);

    //IContextMenu Methods
    IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax);
    STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici); 
    STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); 
};

Solution

  • I found out why it wasn't working. A lot of frustration for nothing.

    In my ValidatorContextMenuHandler.cpp file, I did a simple mistake. When queried for the IContextMenu interface, I accidentally cast this to IClassFactory when I should cast it to IContextMenu. Mistyped it.

    Before:

    else if (IsEqualIID(riid, IID_IContextMenu))
    {
        *ppvObject = (IClassFactory*)this;
        this->AddRef();
        return S_OK;
    }
    

    After:

    else if (IsEqualIID(riid, IID_IContextMenu)) 
    {
        *ppvObject = (IContextMenu*)this; 
        this->AddRef();
        return S_OK;
    }