|
由于工作的需求要实现像winrara那样的shell扩展菜单,带图标的,针对某个类型的文件执行相应的操作, 查了不少资料,终于解决了,效果如下图中红色矩形部分。
![](/images/cppblog_com/shly/test.jpg)
最先想到的当然是最方便的,直接添加注册表,只需在HCLR中需要处理的类型(即右键选中的文件类型)的注册表项中的shell子键中加入新项, 修改默认值为显示名称,显示效果如上图的<用“记事本”打开>菜单项。(*)代表任意类型的文件。
![](/images/cppblog_com/shly/2..jpg)
然后再新项中加入command子键,默认值设置为运行程序的参数,如"notepad.exe %1”,其中%1代表右键选中的文件。
这样当点击菜单后就可以执行你指定的程序("notepad")并传入选中的文件名作为命令参数,这样就可以处理这个文件了。
其实这样足以满足需求了,但效果上还差了一点,很明显少了个图标。既然winrar都能实现,肯定是还有其它实现的方法了。
于是就是处理图标了,然而最终没能找到好的方法,但如果是win7的话,还是有的,那就是在command中加入icon项,值为
你的目标程序,然而如果是xp就行不通了。
本想简单的解决,但没想到还是得用上复杂的方法,仅仅为了一个图标 - -;。
复杂的方法只能是通过扩展shell接口来实现,首先肯定得牵涉到COM,所以关于COM可以上网查下资料,再这里就不多说(其实
让我讲我也不一定讲得清楚),这里我就写下得注意的地方就是了。
1.创建工程这里我用的VS2005,创建一个ATL 项目,属性不需要改,点默认的就可以了。
2.右击项目,添加,类,添加一个新ATL简单对象。
3.编辑代码,关于IShellExtInit和IContextMenu接口可以查看MSDN,上面写的很详细。
// CCContextMenuExt
![](/Images/OutliningIndicators/None.gif)
class ATL_NO_VTABLE CCContextMenuExt :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCContextMenuExt, &CLSID_CContextMenuExt>,
![](/Images/OutliningIndicators/ExpandedBlockStart.gif) public IDispatchImpl<ICContextMenuExt, &IID_ICContextMenuExt, &LIBID_CtxMenuExtLib, /**//*wMajor =*/ 1, /**//*wMinor =*/ 0>,
public IShellExtInit,
public IContextMenu
![](/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](/Images/OutliningIndicators/ContractedBlock.gif) {
public:
CCContextMenuExt()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
}
![](/Images/OutliningIndicators/InBlock.gif)
DECLARE_REGISTRY_RESOURCEID(IDR_CCONTEXTMENUEXT)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
BEGIN_COM_MAP(CCContextMenuExt)
COM_INTERFACE_ENTRY(ICContextMenuExt)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
DECLARE_PROTECT_FINAL_CONSTRUCT()
![](/Images/OutliningIndicators/InBlock.gif)
HRESULT FinalConstruct()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
m_hBitmap = LoadBitmap(_hInstance, MAKEINTRESOURCE(IDB_MENU));
return S_OK;
}
![](/Images/OutliningIndicators/InBlock.gif)
void FinalRelease()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
if (m_hBitmap)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
DeleteObject(m_hBitmap);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public:
enum
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
IDM_CTXMENU = 0,
};
![](/Images/OutliningIndicators/InBlock.gif)
public:
![](/Images/OutliningIndicators/InBlock.gif)
HRESULT STDMETHODCALLTYPE Initialize(
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* [in] */ LPCITEMIDLIST pidlFolder,
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* [in] */ IDataObject *pdtobj,
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* [in] */ HKEY hkeyProgID)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
HRESULT hr;
UINT nFileCount;
UINT nLen;
![](/Images/OutliningIndicators/InBlock.gif)
FORMATETC fmt =
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
CF_HDROP,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
![](/Images/OutliningIndicators/InBlock.gif)
STGMEDIUM sm =
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
TYMED_HGLOBAL
};
![](/Images/OutliningIndicators/InBlock.gif)
hr = pdtobj->GetData(&fmt, &sm);
if (FAILED(hr))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return hr;
}
![](/Images/OutliningIndicators/InBlock.gif)
nFileCount = DragQueryFile((HDROP)sm.hGlobal, 0xFFFFFFFF, NULL, 0);
![](/Images/OutliningIndicators/InBlock.gif)
if (nFileCount >= 1)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
nLen = DragQueryFile((HDROP)sm.hGlobal, 0, m_pszFileName, sizeof(m_pszFileName));
if (nLen >0 && nLen <MAX_PATH)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
m_pszFileName[nLen] = _T('\0');
hr = S_OK;
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
hr = E_INVALIDARG;
}
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
hr = E_INVALIDARG;
}
![](/Images/OutliningIndicators/InBlock.gif)
ReleaseStgMedium(&sm);
![](/Images/OutliningIndicators/InBlock.gif)
return hr;
}
![](/Images/OutliningIndicators/InBlock.gif)
STDMETHOD(QueryContextMenu)(THIS_
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
MENUITEMINFO mii;
![](/Images/OutliningIndicators/InBlock.gif)
if (uFlags & CMF_DEFAULTONLY)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
}
![](/Images/OutliningIndicators/InBlock.gif)
memset((void*)&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STRING | MIIM_CHECKMARKS | MIIM_ID | MIIM_STATE;
mii.cch = lstrlen(SZ_MENUTEXT);
mii.dwTypeData = SZ_MENUTEXT;
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//*
这里用hbmpChecked而不用hbmpItem的原因
- -自己动手试试就知道了。
*/
mii.hbmpItem
mii.hbmpChecked = m_hBitmap;
mii.hbmpUnchecked = m_hBitmap;
mii.fState = MFS_ENABLED;
mii.wID = idCmdFirst + indexMenu;
![](/Images/OutliningIndicators/InBlock.gif)
if (!InsertMenuItem(hmenu, indexMenu, TRUE, &mii))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return E_FAIL;
}
![](/Images/OutliningIndicators/InBlock.gif)
lstrcpynA(m_pszVerb, "protected_run", 32);
lstrcpynW(m_pwszVerb, L"protected_run", 32);
![](/Images/OutliningIndicators/InBlock.gif)
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, IDM_CTXMENU + 1);
}
![](/Images/OutliningIndicators/InBlock.gif)
STDMETHOD(InvokeCommand)(THIS_
LPCMINVOKECOMMANDINFO lpici)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
BOOL fEx = FALSE;
BOOL fUnicode = FALSE;
![](/Images/OutliningIndicators/InBlock.gif)
if(lpici->cbSize == sizeof(CMINVOKECOMMANDINFOEX))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
fEx = TRUE;
if((lpici->fMask & CMIC_MASK_UNICODE))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
fUnicode = TRUE;
}
}
![](/Images/OutliningIndicators/InBlock.gif)
if( !fUnicode && HIWORD(lpici->lpVerb))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
if(StrCmpIA(lpici->lpVerb, m_pszVerb))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return E_FAIL;
}
}
![](/Images/OutliningIndicators/InBlock.gif)
else if( fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpici)->lpVerbW))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
if(StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpici)->lpVerbW, m_pwszVerb))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return E_FAIL;
}
}
![](/Images/OutliningIndicators/InBlock.gif)
else if(LOWORD(lpici->lpVerb) != IDM_CTXMENU)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return E_FAIL;
}
![](/Images/OutliningIndicators/InBlock.gif)
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
//在此处理点击事件.
MessageBox(NULL, m_pszFileName, _T(""), MB_OK);
![](/Images/OutliningIndicators/InBlock.gif)
return S_OK;
}
![](/Images/OutliningIndicators/InBlock.gif)
return E_FAIL;
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
STDMETHOD(GetCommandString)(THIS_
UINT_PTR idCmd,
UINT uType,
UINT * pwReserved,
LPSTR pszName,
UINT cchMax)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
HRESULT hr = E_INVALIDARG;
static CHAR szHelpTextA[] = "windows扩展菜单!";
static WCHAR szHelpTextW[] = L"windows扩展菜单!";
![](/Images/OutliningIndicators/InBlock.gif)
if(idCmd != IDM_CTXMENU)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return hr;
}
![](/Images/OutliningIndicators/InBlock.gif)
switch(uType)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
case GCS_HELPTEXTA:
lstrcpynA((CHAR*)pszName, szHelpTextA, cchMax);
break;
![](/Images/OutliningIndicators/InBlock.gif)
case GCS_HELPTEXTW:
lstrcpynW((WCHAR*)pszName, szHelpTextW, cchMax);;
break;
![](/Images/OutliningIndicators/InBlock.gif)
case GCS_VERBA:
lstrcpynA((CHAR*)pszName, m_pszVerb, cchMax);
break;
![](/Images/OutliningIndicators/InBlock.gif)
case GCS_VERBW:
lstrcpynW((WCHAR*)pszName, m_pwszVerb, cchMax);
break;
![](/Images/OutliningIndicators/InBlock.gif)
default:
hr = S_OK;
break;
}
return hr;
}
![](/Images/OutliningIndicators/InBlock.gif)
private:
TCHAR m_pszFileName[MAX_PATH];
HBITMAP m_hBitmap;
CHAR m_pszVerb[32];
WCHAR m_pwszVerb[32];
![](/Images/OutliningIndicators/InBlock.gif)
};
4.修改服务注册、取消注册函数,这里只需在需要处理的文件类型的shllex下的ContextMenuHandlers下创建项,并设置接口ID。
// DllRegisterServer - 将项添加到系统注册表
STDAPI DllRegisterServer(void)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](/Images/OutliningIndicators/ContractedBlock.gif) {
// 注册对象、类型库和类型库中的所有接口
HRESULT hr;
HKEY hKey;
![](/Images/OutliningIndicators/InBlock.gif)
static char pszGUID[] = "{C2397F2E-4BA3-4B9D-858A-F775761C023B}";
![](/Images/OutliningIndicators/InBlock.gif)
hr = _AtlModule.DllRegisterServer();
if (FAILED(hr))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return hr;
}
![](/Images/OutliningIndicators/InBlock.gif)
if (RegCreateKeyA(HKEY_CLASSES_ROOT,
"*\\shellex\\ContextMenuHandlers\\CtxMenu", &hKey) != ERROR_SUCCESS)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return E_FAIL;
}
![](/Images/OutliningIndicators/InBlock.gif)
if (RegSetValueA(hKey, NULL, REG_SZ, pszGUID,
(DWORD)strlen(pszGUID)) != ERROR_SUCCESS)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
RegCloseKey(hKey);
return E_FAIL;
}
![](/Images/OutliningIndicators/InBlock.gif)
return hr;
}
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
// DllUnregisterServer - 将项从系统注册表中移除
STDAPI DllUnregisterServer(void)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](/Images/OutliningIndicators/ContractedBlock.gif) {
RegDeleteKeyA(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\CtxMenu");
![](/Images/OutliningIndicators/InBlock.gif)
return _AtlModule.DllUnregisterServer();
}
5.编译运行,VS会自动替你注册,当然也可以用regsvr32 自己注册。
下载地址:http://www.cppblog.com/Files/shly/CtxMenuExt.rar
注意:注册后的DLL无法删除,有种方法可以就是regsvr32 /u 取消注册dll, 然后重启explorer.exe。
|