如何实现 IContextMenu 接口
IContextMenu 是最强大但也是要实现的最复杂的接口。 强烈建议使用静态谓词方法之一实现谓词。 有关详细信息,请参阅 选择静态或动态快捷菜单方法。 IContextMenu 有三种方法: GetCommandString、 InvokeCommand 和 QueryContextMenu,此处将对此进行详细介绍。
需要了解的事项
技术
- C++
先决条件
- 静态谓词
- 快捷菜单
Instructions
IContextMenu::GetCommandString 方法
处理程序的 IContextMenu::GetCommandString 方法用于返回谓词的规范名称。 此方法是可选的。 在 Windows XP 和早期版本的 Windows 中,当 Windows 资源管理器具有状态栏时,此方法用于检索菜单项的状态栏中显示的帮助文本。
idCmd 参数保存调用 IContextMenu::QueryContextMenu 时定义的命令的标识符偏移量。 如果请求帮助字符串, uFlags 将设置为 GCS_HELPTEXTW。 将帮助字符串复制到 pszName 缓冲区,并将其强制转换为 PWSTR。 通过将 uFlags 设置为 GCS_VERBW 来请求谓词字符串。 将相应的字符串复制到 pszName,就像使用帮助字符串一样。 快捷菜单处理程序不使用 GCS_VALIDATEA 和 GCS_VALIDATEW 标志。
以下示例演示 GetCommandString 的简单实现,该实现对应于本主题的 IContextMenu::QueryContextMenu 方法部分中给出的 QueryContextMenu 示例。 由于处理程序只添加一个菜单项,因此只能返回一组字符串。 方法测试 idCmd 是否有效,如果有效,则返回请求的字符串。
StringCchCopy 函数用于将请求的字符串复制到 pszName,以确保复制的字符串不会超过 cchName 指定的缓冲区大小。 此示例仅实现对 uFlags 的 Unicode 值的支持,因为自 Windows 2000 以来,Windows 资源管理器中只使用这些值。
IFACEMETHODIMP CMenuExtension::GetCommandString(UINT idCommand,
UINT uFlags,
UINT *pReserved,
PSTR pszName,
UINT cchName)
{
HRESULT hr = E_INVALIDARG;
if (idCommand == IDM_DISPLAY)
{
switch (uFlags)
{
case GCS_HELPTEXTW:
// Only useful for pre-Vista versions of Windows that
// have a Status bar.
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
cchName,
L"Display File Name");
break;
case GCS_VERBW:
// GCS_VERBW is an optional feature that enables a caller
// to discover the canonical name for the verb that is passed in
// through idCommand.
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
cchName,
L"DisplayFileName");
break;
}
}
return hr;
}
IContextMenu::InvokeCommand 方法
当用户单击菜单项以告知处理程序运行关联的命令时,将调用此方法。 pici 参数指向包含运行命令所需的信息的 结构。
尽管 pici 在 Shlobj.h 中声明为 CMINVOKECOMMANDINFO 结构,但在实践中,它通常指向 CMINVOKECOMMANDINFOEX 结构。 此结构是 CMINVOKECOMMANDINFO 的扩展版本,具有多个附加成员,可用于传递 Unicode 字符串。
检查 pici 的 cbSize 成员以确定传入的结构。 如果它是 CMINVOKECOMMANDINFOEX 结构,并且 fMask 成员设置了 CMIC_MASK_UNICODE 标志,请将 pici 强制转换为 CMINVOKECOMMANDINFOEX。 这使应用程序能够使用结构的最后五个成员中包含的 Unicode 信息。
结构的 lpVerb 或 lpVerbW 成员用于标识要执行的命令。 命令通过以下两种方式之一进行标识:
- 通过命令的谓词字符串
- 按命令的标识符偏移量
若要区分这两种情况,检查 ANSI 事例的 lpVerb 高序字,对于 Unicode 大小写,则为 lpVerbW。 如果高序字非零, lpVerb 或 lpVerbW 将保留谓词字符串。 如果高序字为零,则命令偏移量位于 lpVerb 的低序字中。
以下示例演示 IContextMenu::InvokeCommand 的简单实现,该实现对应于本部分前后给出的 IContextMenu::QueryContextMenu 和 IContextMenu::GetCommandString 示例。 方法首先确定要传入的结构。 然后,它确定命令是否由其偏移量或谓词标识。 如果 lpVerb 或 lpVerbW 保留有效的谓词或偏移量,该方法将显示一个消息框。
STDMETHODIMP CShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
BOOL fEx = FALSE;
BOOL fUnicode = FALSE;
if(lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX))
{
fEx = TRUE;
if((lpcmi->fMask & CMIC_MASK_UNICODE))
{
fUnicode = TRUE;
}
}
if( !fUnicode && HIWORD(lpcmi->lpVerb))
{
if(StrCmpIA(lpcmi->lpVerb, m_pszVerb))
{
return E_FAIL;
}
}
else if( fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpcmi)->lpVerbW))
{
if(StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpcmi)->lpVerbW, m_pwszVerb))
{
return E_FAIL;
}
}
else if(LOWORD(lpcmi->lpVerb) != IDM_DISPLAY)
{
return E_FAIL;
}
else
{
MessageBox(lpcmi->hwnd,
"The File Name",
"File Name",
MB_OK|MB_ICONINFORMATION);
}
return S_OK;
}
IContextMenu::QueryContextMenu 方法
Shell 调用 IContextMenu::QueryContextMenu ,使快捷菜单处理程序能够将其菜单项添加到菜单中。 它在 hmenu 参数中传入 HMENU 句柄。 indexMenu 参数设置为要用于要添加的第一个菜单项的索引。
处理程序添加的任何菜单项都必须具有 介于 idCmdFirst 和 idCmdLast 参数中的值之间的标识符。 通常,第一个命令标识符设置为 idCmdFirst,对于每个附加命令,该标识符 (1) 递增。 这种做法有助于避免超过 idCmdLast ,并在 Shell 调用多个处理程序时最大化可用标识符的数量。
项标识符的 命令偏移量 是 标识符与 idCmdFirst 中的值之间的差异。 存储处理程序添加到快捷菜单的每个项的偏移量,因为如果 Shell 随后调用 IContextMenu::GetCommandString 或 IContextMenu::InvokeCommand,则它可能会使用该偏移量来标识该项。
还应将 谓词 分配给添加的每个命令。 谓词是调用 InvokeCommand 时可用于标识命令的字符串,而不是偏移量。 ShellExecuteEx 等函数也使用它来执行快捷菜单命令。
可以通过与快捷菜单处理程序相关的 uFlags 参数传入三个标志。 下表对它们进行了说明。
标志 | 描述 |
---|---|
CMF_DEFAULTONLY | 用户已选择默认命令,通常通过双击对象。 IContextMenu::QueryContextMenu 应在不修改菜单的情况下将控制权返回到 Shell。 |
CMF_NODEFAULT | 菜单中的项不应为默认项。 方法应将其命令添加到菜单中。 |
CMF_NORMAL | 快捷菜单将正常显示。 方法应将其命令添加到菜单中。 |
使用 InsertMenu 或 InsertMenuItem 将菜单项添加到列表。 然后返回严重性设置为SEVERITY_SUCCESS的 HRESULT 值。 将代码值设置为已分配的最大命令标识符的偏移量,加上一 (1) 。 例如,假设 idCmdFirst 设置为 5,并且你向菜单添加三个命令标识符为 5、7 和 8 的项。 返回值应为 MAKE_HRESULT (SEVERITY_SUCCESS、0、8 + 1) 。
以下示例演示插入单个命令的 QueryContextMenu 的简单实现。 命令的标识符偏移量IDM_DISPLAY,设置为零。 m_pszVerb和m_pwszVerb变量是私有变量,用于以 ANSI 和 Unicode 格式存储与语言无关的关联谓词字符串。
#define IDM_DISPLAY 0
STDMETHODIMP CMenuExtension::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
HRESULT hr;
if(!(CMF_DEFAULTONLY & uFlags))
{
InsertMenu(hMenu,
indexMenu,
MF_STRING | MF_BYPOSITION,
idCmdFirst + IDM_DISPLAY,
"&Display File Name");
hr = StringCbCopyA(m_pszVerb, sizeof(m_pszVerb), "display");
hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"display");
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_DISPLAY + 1));
}
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));}
备注
有关其他谓词实现任务,请参阅 创建快捷菜单处理程序。