admin管理员组

文章数量:1123224

I am trying to register IExecuteCommand for the context menu of a text file. To do this, I created a COM server in a DLL and registered it in Windows. For registration, I used the following .reg file

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{0DF1F277-A2CD-4202-86AA-4C0BF1B8C5E4}\InProcServer32]
@="C:\Users\Username\OneDrive\Desktop\COM\COMIExecuteCommand.dll"
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\txtfile\shell\printnamestodebugger]
@="Print names to debugger"
[HKEY_CLASSES_ROOT\txtfile\shell\printnamestodebugger\command]
"DelegateExecute"="{0DF1F277-A2CD-4202-86AA-4C0BF1B8C5E4}"

As a result, the "Print names to debugger" menu item appears in the context menu for text files, but when I try to select this menu, I get the following error: "Class not registered" despite the fact that all the necessary instructions for registering the COM component are written in the .reg file.

I am testing on Windows 10 64 bit (DLL also 64 bit)

How can I make the "Print names to debugger" menu work? You can see the COM component code below:


#include "pch.h"

#include <windows.h>
#include <unknwn.h>
#include <new>

#include <shobjidl.h>
CLSID CLSID_ShellExtension = { 0xdf1f277, 0xa2cd, 0x4202, { 0x86, 0xaa, 0x4c, 0xb, 0xf1, 0xb8, 0xc5, 0xe4 } };// {0DF1F277-A2CD-4202-86AA-4C0BF1B8C5E4}
LONG g_cObjs;
void DllAddRef() { InterlockedIncrement(&g_cObjs); }
void DllRelease() { InterlockedDecrement(&g_cObjs); }

class CShellExtension
    : public IExecuteCommand
    , public IInitializeCommand
    , public IObjectWithSelection
{
public:
    CShellExtension();
    // *** IUnknown ***
    STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();
    // *** IInitializeCommand ***
    STDMETHODIMP Initialize(PCWSTR pszCommandName, IPropertyBag* ppb);
    // *** IObjectWithSelection ***
    STDMETHODIMP SetSelection(IShellItemArray* psia);
    STDMETHODIMP GetSelection(REFIID riid, void** ppv);
    // *** IExecuteCommand ***
    STDMETHODIMP SetKeyState(DWORD grfKeyState) { return S_OK; }
    STDMETHODIMP SetParameters(LPCWSTR pszParameters) { return S_OK; }
    STDMETHODIMP SetPosition(POINT pt) { return S_OK; }
    STDMETHODIMP SetShowWindow(int nShow) { return S_OK; }
    STDMETHODIMP SetNoShowUI(BOOL fNoShowUI) { return S_OK; }
    STDMETHODIMP SetDirectory(LPCWSTR pszDirectory) { return S_OK; }
    STDMETHODIMP Execute();
private:
    ~CShellExtension();
private:
    LONG m_cRef;
    IShellItemArray* m_psia;
};
CShellExtension::CShellExtension()
    : m_cRef(1), m_psia(NULL)
{
    DllAddRef();
}
CShellExtension::~CShellExtension()
{
    if (m_psia) m_psia->Release();
    DllRelease();
}


// guts of shell extension go in here eventually
class CFactory : public IClassFactory
{
public:
    // *** IUnknown ***
    STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
    STDMETHODIMP_(ULONG) AddRef() { return 2; }
    STDMETHODIMP_(ULONG) Release() { return 1; }
    // *** IClassFactory ***
    STDMETHODIMP CreateInstance(IUnknown* punkOuter,
        REFIID riid, void** ppv);
    STDMETHODIMP LockServer(BOOL fLock);
};
CFactory c_Factory;
STDMETHODIMP CFactory::QueryInterface(REFIID riid, void** ppv)
{
    IUnknown* punk = NULL;
    if (riid == IID_IUnknown || riid == IID_IClassFactory) {
        punk = static_cast<IClassFactory*>(this);
    }
    *ppv = punk;
    if (punk) {
        punk->AddRef();
        return S_OK;
    }
    else {
        return E_NOINTERFACE;
    }
}
STDMETHODIMP CFactory::CreateInstance(
    IUnknown* punkOuter, REFIID riid, void** ppv)
{
    *ppv = NULL;
    if (punkOuter) return CLASS_E_NOAGGREGATION;
    CShellExtension* pse = new(std::nothrow) CShellExtension();
    if (!pse) return E_OUTOFMEMORY;
    HRESULT hr = pse->QueryInterface(riid, ppv);
    pse->Release();
    return hr;
}
STDMETHODIMP CFactory::LockServer(BOOL fLock)
{
    if (fLock) DllAddRef();
    else       DllRelease();
    return S_OK;
}

STDAPI DllGetClassObject(REFCLSID rclsid,
    REFIID riid, void** ppv)
{
    if (rclsid == CLSID_ShellExtension) {
        return c_Factory.QueryInterface(riid, ppv);
    }
    *ppv = NULL;
    return CLASS_E_CLASSNOTAVAILABLE;
}

 STDAPI Test(REFCLSID rclsid,
     REFIID riid, void** ppv)
 {
     
     return CLASS_E_CLASSNOTAVAILABLE;
 }

STDAPI DllCanUnloadNow()
{
    return g_cObjs ? S_OK : S_FALSE;
}

STDMETHODIMP CShellExtension::QueryInterface(
    REFIID riid, void** ppv)
{
    IUnknown* punk = NULL;
    if (riid == IID_IUnknown || riid == IID_IExecuteCommand) {
        punk = static_cast<IExecuteCommand*>(this);
    }
    else if (riid == IID_IInitializeCommand) {
        punk = static_cast<IInitializeCommand*>(this);
    }
    else if (riid == IID_IObjectWithSelection) {
        punk = static_cast<IObjectWithSelection*>(this);
    }
    *ppv = punk;
    if (punk) {
        punk->AddRef();
        return S_OK;
    }
    else {
        return E_NOINTERFACE;
    }
}

STDMETHODIMP CShellExtension::SetSelection(IShellItemArray* psia)
{
    if (psia) psia->AddRef();
    if (m_psia) m_psia->Release();
    m_psia = psia;
    return S_OK;
}
STDMETHODIMP CShellExtension::GetSelection(
    REFIID riid, void** ppv)
{
    if (m_psia) return m_psia->QueryInterface(riid, ppv);
    *ppv = NULL;
    return E_NOINTERFACE;
}

STDMETHODIMP CShellExtension::Initialize(
    PCWSTR pszCommandName,
    IPropertyBag* ppb)
{
    OutputDebugStringW(L"Command: ");
    OutputDebugStringW(pszCommandName);
    OutputDebugStringW(L"\r\n");
    if (ppb) {
        VARIANT vt;
        VariantInit(&vt);
        if (SUCCEEDED(ppb->Read(L"extra", &vt, NULL))) {
            if (SUCCEEDED(VariantChangeType(&vt, &vt, 0, VT_BSTR))) {
                OutputDebugStringW(L"extra: ");
                OutputDebugStringW(vt.bstrVal);
                OutputDebugStringW(L"\r\n");
            }
            VariantClear(&vt);
        }
    }
    return S_OK;
}

STDMETHODIMP CShellExtension::Execute()
{
    HRESULT hr;
    if (m_psia) {
        IEnumShellItems* pesi;
        if (SUCCEEDED(hr = m_psia->EnumItems(&pesi))) {
            IShellItem* psi;
            while (pesi->Next(1, &psi, NULL) == S_OK) {
                LPWSTR pszName;
                if (SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH,
                    &pszName))) {
                    OutputDebugStringW(L"File: ");
                    OutputDebugStringW(pszName);
                    OutputDebugStringW(L"\r\n");
                    CoTaskMemFree(pszName);
                }
                psi->Release();
            }
            pesi->Release();
            hr = S_OK;
        }
    }
    else {
        hr = E_UNEXPECTED;
    }
    return hr;
}

STDMETHODIMP_(ULONG) CShellExtension::AddRef()
{
    return ++m_cRef;
}
STDMETHODIMP_(ULONG) CShellExtension::Release()
{
    ULONG cRef = --m_cRef;
    if (cRef == 0) delete this;
    return cRef;
}

HRESULT __stdcall DllRegisterServer()
{
    return S_OK;
}

HRESULT __stdcall DllUnregisterServer()
{
    return S_OK;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

DEF file


LIBRARY COMIExecuteCommand
EXPORTS
    DllGetClassObject PRIVATE
    DllCanUnloadNow PRIVATE
    DllRegisterServer PRIVATE
    DllUnregisterServer PRIVATE

本文标签: cCannot register IExecuteCommand for context menuStack Overflow