ATL右键文件菜单

自己写的小程序中用到的,网上资料相对还是毕竟全的,这里再整理下。毕竟我也不是很了解ATL,里面估计还是有不少问题的,就当作参考吧。

1.创建ATL工程,这个没什么好讲的。

我对COM组件没什么研究,这边就没勾选COM。

2.Project >> Add New Item >> ATL >> ATL Simple Object

3.添加继承关系,需要继承自IShellExtInit和IContextMenu。

IShellExtInit接口用于Shell初始化Shell扩展对象的初始化工作。当用户需要定制Shell的快捷菜单或者属性页时,需实现IContextMenu或IShellPropSheetExt接口的同时,还需实现IShellExtInit接口.Shell会自动调用该接口的Initialize方法来初始化Shell扩展对象。

class ATL_NO_VTABLE CAtlMenuImpl :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CAtlMenuImpl, &CLSID_AtlMenuImpl>,
    public IDispatchImpl<IAtlMenuImpl, &IID_IAtlMenuImpl, &LIBID_AtlMenuLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IShellExtInit, //继承IShellExtInit
    public IContextMenu   //继承IContextMenu

添加到映射表:

BEGIN_COM_MAP(CAtlMenuImpl)
    COM_INTERFACE_ENTRY(IShellExtInit)
    COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()

 添加几个变量:

std::vector<std::wstring> m_fileNameVector; //文件列表容器
UINT m_uiFileNum;
HBITMAP m_hRegBmp; //图标

实现继承的虚函数:

//IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);            //初始化Shell扩展对象

//IContextMenu
STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT*, LPSTR, UINT);    //获取有关快捷菜单命令的信息,包括帮助字符串以及命令的语言无关或规范名称
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO);                    //执行与快捷菜单项关联的命令
STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT);        //将命令添加到快捷菜单

4.具体的实现

CAtlMenuImpl::CAtlMenuImpl()
{
    //m_hRegBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDC_MENU));
}


STDMETHODIMP CAtlMenuImpl::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.
    m_uiFileNum = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
    HRESULT hr = S_OK;

    WCHAR wcFileName[MAX_PATH];
    for (UINT i = 0; i < m_uiFileNum; i++)
    {
        memset(wcFileName, 0, MAX_PATH);
        if (0 == DragQueryFileW(hDrop, i, wcFileName, MAX_PATH))
        {
            hr = E_INVALIDARG;
            break;
        }

        m_fileNameVector.push_back(wstring(wcFileName));
    }

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

    return hr;
}

STDMETHODIMP CAtlMenuImpl::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
    USES_CONVERSION;

    // Check idCmd, it must be 0 since we have only one menu item.
    if (0 != idCmd)
        return E_INVALIDARG;

    // If Explorer is asking for a help string, copy our string into the
    // supplied buffer.
    if (uFlags & GCS_HELPTEXT)
    {
        LPCTSTR szText = _T("This is the simple shell extension's help");

        if (uFlags & GCS_UNICODE)
        {
            // We need to cast pszName to a Unicode string, and then use the
            // Unicode string copy API.
            lstrcpynW((LPWSTR)pszName, T2CW(szText), cchMax);
        }
        else
        {
            // Use the ANSI string copy API to return the help string.
            lstrcpynA(pszName, T2CA(szText), cchMax);
        }

        return S_OK;
    }

    return E_INVALIDARG;
}

STDMETHODIMP CAtlMenuImpl::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
{
    // If lpVerb really points to a string, ignore this function call and bail out.
    if (0 != HIWORD(pCmdInfo->lpVerb))
        return E_INVALIDARG;

    wchar_t szCurrentDir[MAX_PATH] = { 0 };
    wstring exePath = L"";
    wstring paramStr = L"";
    wstring parms = L"\"";

    GetModuleFileNameW(g_hInstance, szCurrentDir, MAX_PATH);
    exePath = szCurrentDir;
    exePath = exePath.substr(0, exePath.find_last_of(L'\\'));
    exePath += L"\\DF.exe";

    for (UINT i = 0; i < m_uiFileNum; i++)
    {
        parms += m_fileNameVector.at(i).c_str();
        if (i != m_uiFileNum - 1)
        {
            parms += L"*";
        }
    }
    parms += L'\"';

    paramStr += parms;

    g_log.LogInfo(L"[InvokeCommand]exePath:%s, param:%s", exePath.c_str(), paramStr.c_str());

    ShellExecuteW(pCmdInfo->hwnd, L"open", exePath.c_str(), paramStr.c_str(), NULL, SW_HIDE);
    return S_OK;

}

STDMETHODIMP CAtlMenuImpl::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags)
{
    UINT uCmdID = uidFirstCmd;
    UINT uMenuCount = 0;
    // 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_SEPARATOR | MF_BYPOSITION, 0, NULL);
    uMenuCount++;

    HMENU hNextDocSecurity = CreateMenu();
    InsertMenuW(hmenu, uMenuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)uCmdID, _T("呵呵呵呵"));
    SetMenuItemBitmaps(hmenu, 0, MF_BYPOSITION, NULL, NULL);

    uMenuIndex++;
    uMenuCount++;

    return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uMenuCount);
}

5.代码注册

打开idl文件,记录下最下面的uuid

fc71b946-3310-4bb2-9f54-ac8a98a02f22

在AtlMenu.cpp中DllRegisterServer和DllUnregisterServer增加对应的注册表信息

// DllRegisterServer - Adds entries to the system registry.
_Use_decl_annotations_
STDAPI DllRegisterServer(void)
{
    // registers object, typelib and all interfaces in typelib
    if (0 == (GetVersion() & 0x80000000UL))
    {
        g_log.LogInfo(L"[DllRegisterServer] start");

        //写相应的注册表键值
        CRegKey reg;
        LONG    lRet = reg.Open(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), KEY_SET_VALUE);

        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] Open HKEY_LOCAL_MACHINE failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        lRet = reg.SetStringValue(_T("AtlMenu"), _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}"));

        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] SetStringValue failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        lRet = reg.Create(HKEY_CLASSES_ROOT, _T("*\\shellex\\ContextMenuHandlers\\AtlMenu"));
        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] Creating shellex\\ContextMenuHandlers register failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        lRet = reg.SetStringValue(NULL, _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}"));

        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] Set \\shellex\\ContextMenuHandlers register failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        //写文件夹注册表项
        lRet = reg.Create(HKEY_CLASSES_ROOT, _T("Folder\\shellex\\ContextMenuHandlers\\AtlMenu"));

        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] Create Folder reg failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        lRet = reg.SetStringValue(_T("AtlMenu"), _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}"));

        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] SetStringValue ( Folder AtlMenu ) failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        lRet = reg.Create(HKEY_CLASSES_ROOT, _T("Directory\\shellex\\ContextMenuHandlers\\AtlMenu"));
        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] Creating HKEY_CLASSES_ROOT\\Directory\\shellex register failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        lRet = reg.SetStringValue(NULL, _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}"));

        if (ERROR_SUCCESS != lRet)
        {
            g_log.LogError(L"[DllRegisterServer] Set HKEY_CLASSES_ROOT\\diretory\\shell register failed:%d", GetLastError());
            return E_ACCESSDENIED;
        }

        g_log.LogInfo(L"[DllRegisterServer] finished");
    }

    // registers object, typelib and all interfaces in typelib
    HRESULT hr = _AtlModule.DllRegisterServer();
    return hr;
}

// DllUnregisterServer - Removes entries from the system registry.
_Use_decl_annotations_
STDAPI DllUnregisterServer(void)
{
    //删除相关注册表键、值
    if (0 == (GetVersion() & 0x80000000UL))
    {
        CRegKey reg;
        LONG    lRet;

        lRet = reg.Open(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), KEY_SET_VALUE);
        if (ERROR_SUCCESS == lRet)
        {
            lRet = reg.DeleteValue(_T("AtlMenu"));
        }
        lRet = RegDeleteKeyW(HKEY_CLASSES_ROOT, L"*\\shellex\\ContextMenuHandlers\\AtlMenu");
        lRet = RegDeleteKeyW(HKEY_CLASSES_ROOT, L"Folder\\shellex\\ContextMenuHandlers\\AtlMenu");
        lRet = RegDeleteKeyW(HKEY_CLASSES_ROOT, L"Directory\\shellex\\ContextMenuHandlers\\AtlMenu");
    }

    HRESULT hr = _AtlModule.DllUnregisterServer();
    return hr;
}

6.管理员启动cmd运行regsvr32注册dll就可以看到具体的效果了

 

转载于:https://www.cnblogs.com/anow/p/10172203.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值