VC 向windows系统菜单中添加菜单项---Windows shell扩展编程

vs2008的方法和vc6.0做法几乎一样。下面是转载一位新浪博客-丢丢的。

 

打开VC6,新建一个工程,选ATL COM APPWIZARD,工程名写BlogTest。然后OK。如果要用到MFC,那把Support MFC打上勾,然后按完成。

    新工程生成完毕后,在Class View里根结点按右键,选New Atl Object...,再选Simple Object,在short name里填上类名(起的类型不要和工程名重了),我填Blog,其他会自动填写完毕,OK

    在Blog.h文件头上先添加如下代码:
  #include "shlobj.h"
  #include "comdef.h"

  在class ATL_NO_VTABLE CBlog :后面添加如下代码:
  public IShellExtInit,
  public IContextMenu
  
  在EGIN_COM_MAP(CBlog)后面添加如下代码
  COM_INTERFACE_ENTRY(IShellExtInit)
  COM_INTERFACE_ENTRY(IContextMenu)
  
  在// IBlog后添加如下代码
  // IDesPdm
  protected:
  TCHAR m_szFile [MAX_PATH];
  public:
  // IShellExtInit
  STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY);
  public:
  // IContextMenu
  STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT);
  STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO);
  STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT, UINT, UINT);

  到这里为止头文件已经定义好了,现在要去为Blog.cpp添加代码了。

  首先添加如下代码:
  HRESULT CBlog::Initialize ( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID )
  {
 {
 FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 STGMEDIUM stg = { TYMED_HGLOBAL };
 HDROP hDrop;
 TCHAR szFile [MAX_PATH];
 int nNumFiles;

 // 在数据对象内查找 CF_HDROP 型数据.
 if ( FAILED( pDataObj->GetData ( &fmt, &stg )))
 {
 // Nope! Return an "invalid argument" error back to Explorer.
 return E_INVALIDARG;
 }

 // 获得指向实际数据的指针
 hDrop = (HDROP) GlobalLock ( stg.hGlobal );

 // 检查非NULL.
 if ( NULL == hDrop )
 {
 return E_INVALIDARG;
 }

 // 检查在该操作中有几个文件被选择.
 nNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );

 if(0 == nNumFiles)
 {
  GlobalUnlock ( stg.hGlobal );
  ReleaseStgMedium ( &stg );
  return E_INVALIDARG;
 }
 
 /*// 有效性检查 – 保证最少有一个文件名.
 UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
 if ( 0 == uNumFiles )
 {
 GlobalUnlock ( stg.hGlobal );
 ReleaseStgMedium ( &stg );
 return E_INVALIDARG;
 } */

 for ( int uFile = 0; uFile < nNumFiles; uFile++ )
 {
  //取得下一个文件名.
  if ( 0 == DragQueryFile ( hDrop,
  uFile, szFile, MAX_PATH ))
  continue;

  //m_lsFiles.AddTail(szFile);
  m_mapInt2StrFiles[uFile] = szFile;

 } // end for

 GlobalUnlock ( stg.hGlobal );
 ReleaseStgMedium ( &stg );
 return ( m_mapInt2StrFiles.size() > 0 ) ? S_OK : E_INVALIDARG;
 }
  }

  这个函数用来抓取所有选中文件的绝对路径,保存到m_mapInt2StrFiles这个MAP里(MAP用法就不细说了,查阅STL相关内容)

  HRESULT CBlog::QueryContextMenu ( HMENU hmenu,UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
  {         
 UINT uCmdID = uidFirstCmd;

 char *szMenuText_Popup = "自定义菜单";
      char *szMenuText_1 = "自定义菜单1...";
 char *szMenuText_2 = "自定义菜单2...";
 char *szMenuText_3 = "自定义菜单3...";
 char *szMenuText_4 = "自定义菜单4...";

 // 如果标志包含 CMF_DEFAULTONLY 我们不作任何事情.
 if ( uFlags & CMF_DEFAULTONLY )
 {
  return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
 }

 InsertMenu(hmenu, uMenuIndex, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); 
 uMenuIndex++;

 HMENU hSubMenu = CreateMenu();

 if(hSubMenu)
 {
  InsertMenu(hSubMenu, 0, MF_STRING  | MF_BYPOSITION, uCmdID++, szMenuText_1);
  SetMenuItemBitmaps(hSubMenu, 0, MF_BYPOSITION, m_hRegBmp, m_hRegBmp);

  InsertMenu(hSubMenu, 1, MF_STRING  | MF_BYPOSITION, uCmdID++, szMenuText_2);
  SetMenuItemBitmaps(hSubMenu, 1, MF_BYPOSITION, m_hRegBmp, m_hRegBmp);

  //InsertMenu(hSubMenu, 2, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);

  InsertMenu(hSubMenu, 2, MF_STRING  | MF_BYPOSITION, uCmdID++, szMenuText_3);
  SetMenuItemBitmaps(hSubMenu, 2, MF_BYPOSITION, m_hRegBmp, m_hRegBmp);

  InsertMenu(hSubMenu, 3, MF_STRING  | MF_BYPOSITION, uCmdID++, szMenuText_4);
  SetMenuItemBitmaps(hSubMenu, 3, MF_BYPOSITION, m_hRegBmp, m_hRegBmp);
 }

 InsertMenu(hmenu, uMenuIndex, MF_STRING | MF_POPUP | MF_BYPOSITION, (UINT_PTR)hSubMenu, szMenuText_Popup);
 uMenuIndex++;

      InsertMenu(hmenu, uMenuIndex, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);
 uMenuIndex++;
    
 //最后告诉浏览器我们添加了几个菜单项
 return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, uCmdID );
  }
    这个函数就是添加菜单项的函数。
  InsertMenu(hmenu, uMenuIndex, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);这一句加的是一个空菜单,显示时就是一个菜单里的分隔符。
  SetMenuItemBitmaps(hSubMenu, 2, MF_BYPOSITION, m_hRegBmp, m_hRegBmp);这一句是设定菜单所对应的图标,可在资源中添加一张BMP图,ID设为ID_BMP1,然后在构造函数里加如下代码:
  m_hRegBmp = LoadBitmap ( _Module.GetModuleInstance(),
                             MAKEINTRESOURCE(IDB_GREATSKYBMP) );

  在头文件里加:HBITMAP m_hRegBmp;

  HRESULT CDesPdm::GetCommandString( UINT idCmd, UINT uFlags,UINT* pwReserved, LPSTR pszName, UINT cchMax )
  {
 USES_CONVERSION;
 LPCTSTR szPrompt;

 // 如果 Explorer 要求帮助字符串,就将它拷贝到提供的缓冲区中.
 if ( uFlags & GCS_HELPTEXT )
 {
  switch ( idCmd )
            {
            case 0:
                szPrompt = _T("自定义菜单1");
            break;

            case 1:
                szPrompt = _T("自定义菜单2");
            break;

     case 2:
                szPrompt = _T("自定义菜单3");
            break;

   case 3:
                szPrompt = _T("自定义菜单4");
            break;

            default:
                ATLASSERT(0);           // should never get here
                return E_INVALIDARG;
            break;
            }            
  if ( uFlags & GCS_UNICODE )
  {
   // 我们需要将 pszName 转化为一个 Unicode 字符串, 接着使用Unicode字符串拷贝 API.
   lstrcpynW ( (LPWSTR) pszName, T2CW(szPrompt), cchMax );
  }
  else
  {
   // 使用 ANSI 字符串拷贝API 来返回帮助字符串.
   lstrcpynA ( pszName, T2CA(szPrompt), cchMax );
  }

  return S_OK;
 }

 return E_INVALIDARG;
  }
  这个函数是响应资源管理器左下角的帮助信息

  HRESULT CDesPdm::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )
  { 
 //此语句用来正确地切换MFC模块状态
 AFX_MANAGE_STATE(AfxGetStaticModuleState());
 CString strCmd = "";
     
 // 如果lpVerb 实际指向一个字符串, 忽略此次调用并退出.
 if ( 0 != HIWORD( pCmdInfo->lpVerb ))
  return E_INVALIDARG;
 // 点击的命令索引 – 在这里,唯一合法的索引为0.
 switch ( LOWORD( pCmdInfo->lpVerb ))
 {
  case 0:
  {
   //执行自定义菜单1的操作
   break;
  }
  case 1:
  {
   //执行自定义菜单2的操作
   break;
  }
  case 2:
  {
   //执行自定义菜单3的操作
   break;
  }
  case 3:
  {
   //执行自定义菜单4的操作
   break;
  }
  default:
  {
   return E_INVALIDARG;
   break;
  }
 }
 return S_OK;
  }
    这就是点选了相应菜单后要执行相应操作的函数。

  打开工程里的.idl文件,可以看到有三个不同的注册码,选择最下面一条,我的例子程序是EA29B300-3EA0-4DD2-B2F8-3CC519BFA948

  打开工程里的.rgs文件,删除原来的代码替换成如下代码。
  HKCR
  {
    NoRemove *
    {
        NoRemove ShellEx
        {
            NoRemove ContextMenuHandlers
            {
                ForceRemove Blog = s '{EA29B300-3EA0-4DD2-B2F8-3CC519BFA948}'
            }
        }
    }

 NoRemove Folder
    {
        NoRemove ShellEx
        {
            NoRemove ContextMenuHandlers
            {
                ForceRemove Blog = s '{EA29B300-3EA0-4DD2-B2F8-3CC519BFA948}'
            }
        }
    }
  }
    这是供生成的DLL文件在注册表里注册用的,*表示适用于所有文件,Folder表示适用于文件夹。

  用regsvr32命令注册生成的DLL控件,重启Explore就可查看效果了
  

时间: 2024-12-03 21:40:54

VC 向windows系统菜单中添加菜单项---Windows shell扩展编程的相关文章

如何在IE右键菜单中添加菜单项

菜单|右键 如果使用过Netants的朋友可能都知道,NetAnts在IE中添加了右键菜单功能,只要在页面的一个链接或者图片上点击右键后在菜单中选择 Down By Netants 就可以调用Netants下载该链接指向的文件.在本文中作者将介绍如何通过VB来实现这样的功能. 要实现在IE右键菜单中添加菜单项的功能,要依次实现以下步骤: 1.在注册表HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt项下建立一个新项,项的名

【转】Windows Shell扩展编程傻瓜手册大全:上下文菜单扩展

引用自:http://blog.163.com/yesaidu@126/blog/static/51819307200861853827582/ Part I: A step-by-step tutorial on writing shell extensions 第一节:Windows shell扩展初步:上下文菜单扩展   作者:Michael Dunn 译者:yesaidu   源代码下载:1       2   目录 ● README ● 系列绪言 ● 第一部分绪言 ● 从AppWiza

Delphi为窗体的系统菜单中添加选项

通常在应用程序中,如果单击标题栏的左侧图标,就会弹出一个窗体的系统菜单,在其中可以完成最小化.最大化和关闭等操作.本实例将演示如何在窗体的系统菜单中添加自己的选项. 在窗体中添加一个TMainMenu组件,其中TMainMenu组件中的选项将要被添加到窗体的系统菜单中.添加组件后的窗体如图1所示. 图1 添加组件后的窗体 在TMainMenu组件生成的菜单中添加一个File菜单,在这个菜单下面添加一个Exit选项. 在本程序开始运行时就会把TMainMenu组件生成的菜单添加到窗体的系统菜单中,

win7纯净版系统下在右键菜单中添加“禁用/启用u盘”的技巧

  1.首先鼠标单击win7系统中的"开始/运行",在"运行"对话框中输入"regedit"回车打开注册表编辑器后; 2.然后依次展开[HKEY_CLASSES_ROOTCLSID{20D04FE0-3AEA-1069-A2D8-08002B30309D}shell分支; 3.然后鼠标右击"shell"项并在弹出的菜单中选择"新建/项"命令,然后将其重命名为"禁用U盘",接着在"

在系统菜单里添加菜单项和相应事件

有时候我们经常在程序中实现菜单项的重画,已有好多文章已经加以介绍,在此不再赘述.但是有时我们需要加新菜单项到系统菜单中,并希望给其增加相应的事件.笔者通过运用WindowAPI的AppendMenu函数和C++BUIDER的相关方法.属性,实现了往系统菜单中增加菜单项和事件. 下面介绍具体的实现方法,读者按照以下步骤操作,就可以实现在系统菜单中增加菜单项和事件: 1 首先创建一个新的空工程文件,存盘为project1.cpp和unit1.cpp. 2 使用菜单Tools中的Image Edito

修改注册表在右键菜单中添加清空文件夹命令

  本文介绍用修改注册表的方法在右键菜单中添加清空文件夹命令.很多时候,你可能需要清空文件夹中的内容,但希望继续保留文件夹中原来的结构,如果逐一打开各个文件夹进行文件删除,确实比较麻烦.其实,我们可以在右键菜单中添加相关的命令,以后操作起来就方便多了. 打开注册表编辑器,依次定位到"HKEY_CLASSES_ROOTFoldershell",右击选择"新建→项",新建一个名为"清空文件夹内容"的子项,接下来右击该项,继续新建一个名为"c

编程-怎么在文件菜单中添加&amp;amp;quot;显示Dock&amp;amp;quot;菜单?

问题描述 怎么在文件菜单中添加"显示Dock"菜单? 我把工具箱关掉后怎么让它再显示出来?书上说在Action编辑器中进入""显示Dock""菜单动作的触发信号triggered()的槽函数,再添加代码ui->dockWidget->show();就可以,但我不知道怎么操作? 解决方案 把ui->dockWidget->show();写在你的菜单槽函数中啊.看这个例子http://blog.csdn.net/qiurisu

vbs实现右键菜单中添加CMD HERE_vbs

右键菜单中添加CMD HERE 复制代码 代码如下: Set WshShell=CreateObject("Wscript.Shell")  WshShell.RegWrite "HKEY_LOCAL_MACHINE\Software\CLASSES\Folder\shell\cmd here\",""  WshShell.RegWrite "HKEY_LOCAL_MACHINE\Software\CLASSES\Folder\shel

Windows应用程序多级菜单中上级菜单弹出子菜单的方式

问题描述 Windows应用程序多级菜单中上级菜单弹出子菜单的方式.常见的方式是鼠标悬停在包含子菜单的菜单项时子菜单就会弹出.但我记得好像还有一种方式就是鼠标需要点击一下子菜单才能弹出.请问有没有第二种方式,如果有的话该怎么设定?问题补充:不是只针对开始菜单,是所有的的应用程序菜单.