桌面右键弹出二级菜单

来源:互联网 发布:大数据交易网站有哪些 编辑:程序博客网 时间:2024/04/30 18:58

桌面右键弹出你添加的二级菜单。COM技术,ATL。

这几天一直在做壁纸。翻了一些资料,终于做出来了。

几个函数:

SHGetSpecialFolderPath用于获取特殊文件夹路径

SHGetPathFromIDList从id list获取路径

 


1.新建ATL工程,选支持MFC(因为要使用CString)和合并存根两个选项(因为不需要远程COM)。

 

2.右键工程,选添加类-ATL-ATL简单对象。取个名称。叫做SimpleShlExt。

 

3.下面就该添加SimpleShlExt.h和SimpleShlExt.cpp中的代码了

因为要用到这两个接口IShellExtInit和IContextMenu这两个接口,所以CSimpleShlExt要继承这两个接口,并实现之


class ATL_NO_VTABLE CSimpleShlExt :
 public CComObjectRootEx<CComSingleThreadModel>,
 public CComCoClass<CSimpleShlExt, &CLSID_SimpleShlExt>,
 public IDispatchImpl<ISimpleShlExt, &IID_ISimpleShlExt, &LIBID_SimpleExtLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
 public IShellExtInit,//这俩是新添的。用于ShellExt的初始化
 public IContextMenu//用于右键的上下文菜单

 

4.为CSimpleShlExt实现如下的方法// IShellExtInit
 STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY);
 // IContextMenu
 STDMETHOD(GetCommandString)(UINT_PTR, UINT, UINT*, LPSTR, UINT);
 STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO);
 STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT, UINT, UINT);

 

5.在实现文件中CSimpleShlExt.cpp,实现这四种方法 

STDMETHODIMP CSimpleShlExt::Initialize( LPCITEMIDLIST pidlFolder , LPDATAOBJECT pDataObj , HKEY hProgID )
{
 //MessageBox(0,0,0,0);
 if (pDataObj)//如果鼠标选中了什么,这时候操作结束。做shellex程序一定要负责,要不这个崩溃了,加载这个dll的explorer也会崩溃
 {
  return E_INVALIDARG;
 }

 TCHAR szCurrentPath[MAX_PATH] = {0};
 TCHAR szDesktopPath[MAX_PATH] = {0};

 //这两步当然是为了,你在桌面右键,菜单里会有效果,在其他文件夹,就没有效果
 SHGetSpecialFolderPath( NULL , szDesktopPath , CSIDL_DESKTOP , FALSE);//获取桌面文件夹的路径
 SHGetPathFromIDList ( pidlFolder, szCurrentPath );//获取当前用户点击的路竟

 int ret = lstrcmp(szCurrentPath,szDesktopPath);

 if (ret)
 {
  return E_INVALIDARG;
 }

 return S_OK;
}

 

6.建立右键菜单项 STDMETHODIMP CSimpleShlExt::QueryContextMenu( HMENU hmenu , UINT uMenuIndex , UINT uidFirstCmd , UINT uidLastCmd , UINT uFlags )
{
 UINT uCmdId = uidFirstCmd;
 // 如果标志包含 CMF_DEFAULTONLY 我们不作任何事情.
 if ( uFlags & CMF_DEFAULTONLY )
 {
  return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
 }

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

 //++uMenuIndex;
 HMENU hSubMenu = CreateMenu();
 if (hSubMenu)
 {
  InsertMenu(hSubMenu , 0 , MF_STRING|MF_BYPOSITION , uCmdId++ , TEXT("下一张"));
  //SetMenuItemBitmaps(hSubMenu , 0 , MF_BYPOSITION , nextBitmap , nextBitmap);

  InsertMenu(hSubMenu , 1 , MF_STRING|MF_BYPOSITION , uCmdId++ , TEXT("打开壁纸"));
  //SetMenuItemBitmaps(hSubMenu , 1 , MF_BYPOSITION , openBitmap , openBitmap);

  InsertMenu(hSubMenu , 2, MF_BYPOSITION | MF_SEPARATOR , uCmdId++ , NULL);

  InsertMenu(hSubMenu , 3 , MF_STRING|MF_BYPOSITION , uCmdId++ , TEXT("保存当前壁纸"));
  //SetMenuItemBitmaps(hSubMenu , 3 , MF_BYPOSITION , saveBitmap , saveBitmap);
 }

 InsertMenu(hmenu , uMenuIndex , MF_BYPOSITION | MF_STRING | MF_POPUP , (UINT_PTR)hSubMenu , TEXT("壁纸"));

 return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, uCmdId-uidFirstCmd+1/*这个不能错,要不就少菜单项了*/ );
}

 

7.显示帮助信息STDMETHODIMP CSimpleShlExt::GetCommandString( UINT_PTR idCmd , UINT uFlags, UINT* pwReserved , LPSTR pszName , UINT cchMax )
{
 return S_OK;//啥都不做
}

 

8.实现各个菜单的响应STDMETHODIMP CSimpleShlExt::InvokeCommand( LPCMINVOKECOMMANDINFO pCmdInfo )
{
 if (0 != HIWORD(pCmdInfo->lpVerb))
 {
  return E_INVALIDARG;
 }
 
 switch(LOWORD(pCmdInfo->lpVerb))//根据用户选择了那一项,对应操作
 {
 case 0:
  MessageBox(pCmdInfo->hwnd , _T("下一张") , _T("SimpleShlExt") , MB_ICONINFORMATION);
  return S_OK;
  break;
 case 1:
  MessageBox(pCmdInfo->hwnd , _T("打开壁纸") , _T("SimpleShlExt") , MB_ICONINFORMATION);
  return S_OK;
  break;
 case 3:
  MessageBox(pCmdInfo->hwnd , _T("保存当前壁纸") , _T("SimpleShlExt") , MB_ICONINFORMATION);
  return S_OK;
  break;
 default:
  return E_INVALIDARG;
  break;
 }
}


 9.最后一步。当然是注册注册表了。要不explorer怎么知道你的程序呢在你的工程的rgs文件写下面的注册信息。可以看到两个rgs文件,一个是SimpleShlExt.rgs,这个里面是注册该组件到CLSID下面。SimpleExt.rgs是你要修改成下面的。因为你要支持目录的右键扩展HKCR
{
    NoRemove Directory
    {
        NoRemove Background
        {
            NoRemove shellex
            {
    NoRemove ContextMenuHandlers
    {
     ForceRemove WallPaper = s '{30A75CFD-6E16-4CA0-9D83-3D8E3022E3DB}'
    }
            }
        }
    }
}