天天看點

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);

  // 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 )

 // 檢查在該操作中有幾個檔案被選擇.

 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 );

 } */

 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

 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);

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

 //最後告訴浏覽器我們添加了幾個菜單項

 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");

     case 2:

                szPrompt = _T("自定義菜單3");

   case 3:

                szPrompt = _T("自定義菜單4");

            default:

                ATLASSERT(0);           // should never get here

                return E_INVALIDARG;

            }            

  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;

  這個函數是響應資料總管左下角的幫助資訊

  HRESULT CDesPdm::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )

  { 

 //此語句用來正确地切換MFC子產品狀态

 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 CString strCmd = "";

 // 如果lpVerb 實際指向一個字元串, 忽略此次調用并退出.

 if ( 0 != HIWORD( pCmdInfo->lpVerb ))

 // 點選的指令索引 – 在這裡,唯一合法的索引為0.

 switch ( LOWORD( pCmdInfo->lpVerb ))

  case 0:

   //執行自定義菜單1的操作

   break;

  case 1:

   //執行自定義菜單2的操作

  case 2:

   //執行自定義菜單3的操作

  case 3:

   //執行自定義菜單4的操作

  default:

   return E_INVALIDARG;

 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

    這是供生成的DLL檔案在系統資料庫裡注冊用的,*表示适用于所有檔案,Folder表示适用于檔案夾。

  用regsvr32指令注冊生成的DLL控件,重新開機Explore就可檢視效果了

繼續閱讀