您的位置:首页 > 运维架构 > Shell

[ShellExtension]上下文扩展-IContextMenu实现

2016-02-07 14:54 706 查看
还是先亮源码下载地址:https://git.oschina.net/xiangmu110/template_IContextMenuExt

以下所讲与提供下载的源码不同,但都是一个模子出来的。

下面这段程序实现的是在所有类型文件的右键扩展菜单中添加“获取文件大小”和“显示全路径”两个菜单,并实现其功能并支持多文件。

首先创建一个名为“ContextMenu”的工程,并添加一个简称为“CalcFileSizeExt”的“ATL简单对象”,如果不清楚的请看该文章:

[ShellExtension]图标扩展-IShellIconlayIdentifier实现

这篇文章的开头讲解了,我就不再赘述了。

现在开始讲解如何继承实现“IContextMenu”和“IShellExtInit”接口来达成目的。

// CalcFileSizeExt.h : CCalcFileSizeExt 的声明

#pragma once
#include "resource.h"       // 主符号

#include "ContextMenu_i.h"

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"
#endif

# include <vector>//引入头文件,会使用的vector

using namespace ATL;

// CCalcFileSizeExt

class ATL_NO_VTABLE CCalcFileSizeExt :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCalcFileSizeExt, &CLSID_CalcFileSizeExt>,
public IDispatchImpl<ICalcFileSizeExt, &IID_ICalcFileSizeExt, &LIBID_ContextMenuLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IShellExtInit,//接收explorer传递的信息
public IContextMenu//实现右键扩展
{
public:
CCalcFileSizeExt()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_CALCFILESIZEEXT)

BEGIN_COM_MAP(CCalcFileSizeExt)
COM_INTERFACE_ENTRY(ICalcFileSizeExt)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellExtInit)//添加入口点
COM_INTERFACE_ENTRY(IContextMenu)//添加入口点
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()
{
return S_OK;
}

void FinalRelease()
{
}

//用于保存文件路径
std::vector<std::wstring> m_vtFilePath;

//IShellExtInit的接口实现
virtual HRESULT STDMETHODCALLTYPE Initialize(_In_opt_ PCIDLIST_ABSOLUTE pidlFolder, _In_opt_ IDataObject *pdtobj, _In_opt_ HKEY hkeyProgID);

//IContextMenu的接口实现
virtual HRESULT STDMETHODCALLTYPE QueryContextMenu(_In_ HMENU hmenu, _In_ UINT indexMenu, _In_ UINT idCmdFirst, _In_ UINT idCmdLast, _In_ UINT uFlags);

virtual HRESULT STDMETHODCALLTYPE InvokeCommand(_In_ CMINVOKECOMMANDINFO *pici);

virtual HRESULT STDMETHODCALLTYPE GetCommandString(_In_ UINT_PTR idCmd, _In_ UINT uType, _Reserved_ UINT *pReserved, _Out_writes_bytes_((uType & GCS_UNICODE) ? (cchMax * sizeof(wchar_t)) : cchMax) _When_(!(uType & (GCS_VALIDATEA | GCS_VALIDATEW)), _Null_terminated_) CHAR *pszName, _In_ UINT cchMax);

//获取所有文件大小
void ShowAllFileSIze();

//显示所有文件路径
void ShowAllFilePath();
};

OBJECT_ENTRY_AUTO(__uuidof(CalcFileSizeExt), CCalcFileSizeExt)


// CalcFileSizeExt.cpp : CCalcFileSizeExt 的实现

#include "stdafx.h"
#include "CalcFileSizeExt.h"

// CCalcFileSizeExt

HRESULT STDMETHODCALLTYPE CCalcFileSizeExt::Initialize(_In_opt_ PCIDLIST_ABSOLUTE pidlFolder, _In_opt_ IDataObject *pdtobj, _In_opt_ HKEY hkeyProgID)
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
HDROP hDrop;

//在数据对象中查找CF_HDROP类型数据
if (FAILED(pdtobj->GetData(&fmt, &stg)))
{//没有该数据
return E_INVALIDARG;
}

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

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

HRESULT hr = S_OK;
do
{
//有效性检查,保证最少有一个文件名
UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
if (0 == uNumFiles)
{
hr = E_INVALIDARG;
break;
}

WCHAR tFilePath[MAX_PATH];
//取得所有所有文件的文件名
for (UINT i = 0; i < uNumFiles; i++)
{
if (0 != DragQueryFileW(hDrop, i, tFilePath, MAX_PATH))
{
//存放如文件列表中
m_vtFilePath.push_back(tFilePath);
}
else
{//有错误
hr = E_INVALIDARG;
break;
}
}
} while (0);

//释放资源
GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(&stg);
return hr;
}

HRESULT STDMETHODCALLTYPE CCalcFileSizeExt::QueryContextMenu(_In_ HMENU hmenu, _In_ UINT indexMenu, _In_ UINT idCmdFirst, _In_ UINT idCmdLast, _In_ UINT uFlags)
{
if (uFlags & CMF_DEFAULTONLY)
{//此时不做任何处理
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
}

BOOL bRet = false;

int nCmdId = idCmdFirst;
//添加按钮
bRet = InsertMenu(hmenu, indexMenu, MF_STRING | MF_BYPOSITION, nCmdId, _T("获取文件大小"));
//设置按钮的图标
HBITMAP hBitmap = LoadBitmap(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCE(IDB_BITMAP1));
bRet = SetMenuItemBitmaps(hmenu, indexMenu, MF_BYPOSITION, hBitmap, NULL);

++indexMenu;//序号递增
++nCmdId;//命令ID递增
bRet = InsertMenu(hmenu, indexMenu, MF_STRING | MF_BYPOSITION, nCmdId, _T("显示全路径"));

//最后一个参数为创建的菜单的个数
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 2);
}

//对加入的菜单的事件响应
HRESULT STDMETHODCALLTYPE CCalcFileSizeExt::InvokeCommand(_In_ CMINVOKECOMMANDINFO *pici)
{
//如果lpVerb指向一个字符串,忽略此次调用
if (0 != HIWORD(pici->lpVerb))
{
return E_INVALIDARG;
}

//检查lpVerb是不是添加的命令,并进行响应
switch (LOWORD(pici->lpVerb))//为创建菜单时的indexMenu数值
{
case 0:
ShowAllFileSIze();
break;
case 1:
ShowAllFilePath();
break;
default:
return E_INVALIDARG;
}

return S_OK;
}

HRESULT STDMETHODCALLTYPE CCalcFileSizeExt::GetCommandString(_In_ UINT_PTR idCmd, _In_ UINT uType, _Reserved_ UINT *pReserved, _Out_writes_bytes_((uType & GCS_UNICODE) ? (cchMax * sizeof(wchar_t)) : cchMax) _When_(!(uType & (GCS_VALIDATEA | GCS_VALIDATEW)), _Null_terminated_) CHAR *pszName, _In_ UINT cchMax)
{
//是否是获取提示,设置帮助字符串
if (uType & GCS_HELPTEXT)
{
//选择内容
LPCTSTR szPrompt = NULL;
switch (idCmd)
{
case 0:
szPrompt = _T("Help:显示获取选取文件的总大小。");
break;
case 1:
szPrompt = _T("Help:显示选择文件的全路径。");
break;
default:
return E_INVALIDARG;
}

//字符编码
USES_CONVERSION;
if (uType & GCS_UNICODE)
{
lstrcpynW((LPWSTR)pszName, T2CW(szPrompt), cchMax);
}
else
{
lstrcpynA(pszName, T2CA(szPrompt), cchMax);
}
}
return S_OK;
}

//显示文件大小
void CCalcFileSizeExt::ShowAllFileSIze()
{
struct _stat status;
_off_t allSize = 0;
std::wstring msg;
std::wstring errorMsg = L"获取以下文件大小失败:";
bool isError = false;
for each (std::wstring var in m_vtFilePath)
{
//获取文件信息
if (0 == _wstat(var.c_str(), &status))
{
allSize += status.st_size;
}
else
{
isError = true;
errorMsg += var;
errorMsg += L"\n";
}
}

WCHAR buff[10];
msg += L"文件个数:";
_itow_s((int)m_vtFilePath.size(), buff, 10);
msg += buff;
msg += L"\n文件大小为(byte):";
_itow_s(allSize, buff, 10);
msg += buff;
if (isError)
{
msg += errorMsg;
}

MessageBoxW(NULL, msg.c_str(), L"获取文件大小", MB_OK);
}

//显示文件路径
void CCalcFileSizeExt::ShowAllFilePath()
{
std::wstring msg;
for each (std::wstring var in m_vtFilePath)
{
msg += var;
msg += L"\n";
}
MessageBoxW(NULL, msg.c_str(), L"获取文件路径", MB_OK);
}


图标扩展文章中所讲的一样,需要将这个程序注册到注册表中去。这次不是注册到资源管理器下,而是注册到对应的文件下。下面这段代码,是将其注册到所有类型的文件的上下文菜单中。

HKCR
{
NoRemove *
{
NoRemove shellex
{
NoRemove ContextMenuHandlers
{
ForceRemove CalcFileSizeExt = s '{3E9A1A8A-1311-48F1-9843-879C758E49A0}'
}
}
}
}


注册与反注册及删除均和图标扩展文章中所讲的一模一样,这里就不再赘述。

下面是运行效果图。







内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息