如何添加(启用)标准“发送到”命名空间扩展中的上下文菜单选项 [英] How to add(enable) standard "Send To" context menu option in a namespace extension

查看:530
本文介绍了如何添加(启用)标准“发送到”命名空间扩展中的上下文菜单选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个命名空间扩展,它提供了服务器中文件/文件夹的虚拟视图。

I have a namespace extension, which provides a virtual view of files/folders in a server.

IContextMenu :: QueryContextMenu )我添加了一些自定义菜单项。

In the IContextMenu::QueryContextMenu() I have added some of the custom menu items.

我还设置了两个SGAOF标志在 IShellFolder :: GetAttributesOf()在上下文菜单中获得重命名,删除和属性。

I have also set couple of SGAOF flags in the IShellFolder::GetAttributesOf() to get the rename, delete, and properties, in the context menu.

在我的命名空间扩展中的项目的上下文菜单中的发送到选项?一旦这些命令被启用,我如何处理这些命令?请指教。

Is there any way I can get the "Send To" option in the context menu for items in my namespace extension? and How do I handle these commands once these are enabled?. Please advise.

这是我在Denis Anisimov建议的代码

This is the code I tried as Denis Anisimov suggested

    const CLSID SendToCLSID = { 0x7BA4C740, 0x9E81, 0x11CF, { 0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37 } };

    HRESULT CMyNSEContextMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder , IDataObject *pDataObj, HKEY  hkeyProgID )
    {
        OutputDebugString(L"CMyNSEContextMenu::Initialize\n");
        //Other initialization code
        ...
        ...

        if (_pdtobj)
        {
            _pdtobj->Release();
            _pdtobj = NULL;
        }

        _mpidlFolder = pidlFolder;
        _pdtobj = pDataObj;
        if (pDataObj)
        {
            _pdtobj->AddRef();
            CoCreateInstance(SendToCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IContextMenu, (LPVOID*)&_pSendToMenu);
        }
        return S_OK;
    }

    HRESULT CMyNSEContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT  idCmdLast , UINT  uFlags )
    {
        OutputDebugString(L"CMyNSEContextMenu::QueryContextMenu\n");
        UNREFERENCED_PARAMETER(indexMenu);
        UNREFERENCED_PARAMETER(idCmdFirst);
        //Get File Name
        IShellItemArray *psia=NULL;
        HRESULT    hr;
        USHORT items = 0;

        //Adding other menu items


        AddMenuItem(hmenu, 
                    indexMenu++, 
                    idCmdFirst + MENUVERB_XXX, 
                    IDS_COMMAND_XXX, 
                    IDB_XXX);
        items++;

        IShellExtInit *pShellExtInitSendTo = NULL;

        _pSendToMenu->QueryInterface(IID_IShellExtInit, (LPVOID*)&pShellExtInitSendTo);
        pShellExtInitSendTo->Initialize(NULL, _pdtobj, 0); // your IDataObject with CFSTR_SHELLIDLIST format)
        hr = _pSendToMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
        if (SUCCEEDED(hr))
        {
            items += HRESULT_CODE(hr);
        }

        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(items));
    }

    HRESULT CMyNSEContextMenu::HandleMenuMsg(
        UINT uMsg,
        WPARAM wParam,
        LPARAM lParam
        )
    {
        IContextMenu2 *pSendToMenu = NULL;
        _pSendToMenu->QueryInterface(IID_IContextMenu2, (LPVOID*)&pSendToMenu);

        return pSendToMenu->HandleMenuMsg(uMsg,wParam,lParam);
    }

    HRESULT CMyNSEContextMenu::HandleMenuMsg2(
        UINT uMsg,
        WPARAM wParam,
        LPARAM lParam,
        LRESULT *plResult
        )
    {
        IContextMenu3 *pSendToMenu = NULL;
        _pSendToMenu->QueryInterface(IID_IContextMenu3, (LPVOID*)&pSendToMenu);
        return pSendToMenu->HandleMenuMsg2(uMsg, wParam, lParam, plResult);
    }
HRESULT CMyNSEContextMenu::GetCommandString(UINT_PTR  idCmd , UINT uType , UINT *  pRes , LPSTR  pszName , UINT  cchMax )
{
    OutputDebugString(L"CMyNSEContextMenu::GetCommandString\n");

    return _pSendToMenu->GetCommandString(idCmd, uType, pRes, pszName, cchMax);

}

默认上下文菜单是作为GetUIObjectOf的一部分创建的。并且MyNSEContextMenu类的实例是通过Classfactory。

The default context menu is created as part of GetUIObjectOf. and the instance of MyNSEContextMenu class is through the Classfactory.

HRESULT CMyNSEShellFolder::GetUIObjectOf(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
                                             REFIID riid, UINT * /* prgfInOut */, void **ppv)
{
    OutputDebugString(L"CMyNSEShellFolder::GetUIObjectOf\n");
    *ppv = NULL;
    HRESULT hr = E_NOINTERFACE;

    if (riid == IID_IContextMenu)
    {
        // The default context menu will call back for IQueryAssociations to determine the
        // file associations with which to populate the menu.
        DEFCONTEXTMENU const dcm = { hwnd, NULL, m_pidl, static_cast<IShellFolder2 *>(this),
                               cidl, apidl, NULL, 0, NULL };
        hr = SHCreateDefaultContextMenu(&dcm, riid, ppv);
    }   
    //Others
    ....
    ....
    else if (riid == IID_IQueryAssociations)
    {
            else
            {
                ASSOCIATIONELEMENT const rgAssocItem[] =
                {
                    { ASSOCCLASS_PROGID_STR, NULL, L"MyNSE_Type"},
                };
                hr = AssocCreateForClasses(rgAssocItem, ARRAYSIZE(rgAssocItem), riid, ppv);
            }
    }
    ...
    ...
    return hr;
}

//Called from the class factory     
HRESULT CMyNSEContextMenu_CreateInstance(REFIID riid, void **ppv)
{
    *ppv = NULL;
    CMyNSEContextMenu* pContextMenu = new (std::nothrow) CMyNSEContextMenu();
    HRESULT hr = pContextMenu ? S_OK : E_OUTOFMEMORY;
    if (SUCCEEDED(hr))
    {
        hr = pContextMenu->QueryInterface(riid, ppv);
        pContextMenu->Release();
    }
    return hr;
}

相关注册表如下

HKEY_LOCAL_MACHINE,   L"Software\\Classes\\CLSID\\%s",                  szContextMenuClassID,    NULL,                   (LPBYTE)g_szExtTitle,       REG_SZ,
HKEY_LOCAL_MACHINE,   L"Software\\Classes\\CLSID\\%s\\InprocServer32",  szContextMenuClassID,    NULL,                   (LPBYTE)L"%s",              REG_SZ,
HKEY_LOCAL_MACHINE,   L"Software\\Classes\\CLSID\\%s\\InprocServer32",  szContextMenuClassID,    L"ThreadingModel",      (LPBYTE)L"Apartment",       REG_SZ,

        HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\ProgID", szFolderViewImplClassID, NULL, (LPBYTE)L"MyNSE_Type", REG_SZ,

// For performance, only context menu verbs that register this are considered when the user double-clicks.
HKEY_CLASSES_ROOT,   L"CLSID\\%s\\ShellEx\\MayChangeDefaultMenu",                szContextMenuClassID, NULL,  (LPBYTE)L"",                  REG_SZ,
// register the context menu handler under the MyNSE_Type type.
HKEY_CLASSES_ROOT,   L"MyNSE_Type\\shellex\\ContextMenuHandlers\\%s",  szContextMenuClassID, NULL,  (LPBYTE)szContextMenuClassID, REG_SZ,


推荐答案

SendTo只是简单的shell扩展,实现IContextMenu(2,3)。扩展名CLSID是{7BA4C740-9E81-11CF-99D3-00AA004AE837}在Windows 7(不要忘记检查正确的CLSID在您要支持的其他Windows版本)。所以只需使用这样:

SendTo is just simple shell extension which implements IContextMenu(2,3). CLSID of extension is {7BA4C740-9E81-11CF-99D3-00AA004AE837} in Windows 7 (dont forget to check correct CLSID in other Windows versions you want to support). So just use something like this:

function TMenuWithSentTo.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult;
const
  SendToCLSID: TGUID = '{7BA4C740-9E81-11CF-99D3-00AA004AE837}';
var
  ShellExtInit: IShellExtInit;
begin
  Result := 0;

  // Add you menu items here

  CoCreateInstance(SendToCLSID, nil, CLSCTX_INPROC_SERVER, IContextMenu, FSendToMenu);
  FSendToMenu.QueryInterface(IShellExtInit, ShellExtInit);
  ShellExtInit.Initialize(nil, FDataObject, 0); // your IDataObject with CFSTR_SHELLIDLIST format 
  Result := Result + FSendToMenu.QueryContextMenu(Menu, indexMenu, idCmdFirst, idCmdLast, uFlags);

  // Add you menu items here
end;

function TMenuWithSentTo.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
begin
  if IsMyCommand(lpici) then
    begin
      // Process your command here
      Result := S_OK;
    end
  else
    Result := FSendToMenu.InvokeCommand(lpici);
end;

function TMenuWithSentTo.GetCommandString(idCmd: UINT_PTR; uFlags: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;
begin
  if IsMyCommandID(idCmd) then
    begin
      // Process your command here
      Result := S_OK;
    end
  else
    FSendToMenu.GetCommandString(idCmd);
end;

function TMenuWithSentTo.HandleMenuMsg(uMsg: UINT; WParam: WPARAM; LParam: LPARAM): HResult;
var
  SendToMenu2: IContextMenu2;
begin
  if IsMyMessage(uMsg, WParam, LParam) then
    begin
      // Process your command here
      Result := S_OK;
    end
  else
    begin
      FSendToMenu.QueryInterface(IContextMenu2, SendToMenu2);
      Result := SendToMenu2.HandleMenuMsg(uMsg, WParam, LParam);
    end;
end;

function TMenuWithSentTo.HandleMenuMsg2(uMsg: UINT; wParam: WPARAM; lParam: LPARAM; var lpResult: LRESULT): HResult;
var
  SendToMenu3: IContextMenu3;
begin
  if IsMyMessage(uMsg, WParam, LParam) then
    begin
      // Process your command here
      Result := S_OK;
    end
  else
    begin
      FSendToMenu.QueryInterface(IContextMenu3, SendToMenu3);
      Result := SendToMenu3.HandleMenuMsg(uMsg, WParam, LParam);
    end;
end;

但是你应该准备好SendTo的某些命令将被隐藏,有些命令将无法正常工作,因为有些

But your should be ready that some command of SendTo will be hidden and some will not work correctly because some of them requests real files but you have virtual only.

正常发送到菜单:

发送到NSE中的菜单:

Send to menu in NSE:

>

这篇关于如何添加(启用)标准“发送到”命名空间扩展中的上下文菜单选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆