天天看点

IContextMenu第六部分:显示菜单帮助信息

关于上下文菜单,还有一个值得关注的地方是在状态栏上显示对应的帮助信息。到目前为止,我们的例子程序还没有涉及到状态栏,但是没关系,为了演示今天的主题,我们将菜单帮助信息显示在窗口的标题栏,也是一样的效果。正文即将开始,请做好扶稳。

关于菜单帮助信息,一个关键的接口方法是

IContextMenu::GetCommandString,它主要用来和上下文菜单处理器进行通信。为了方便演示,我再一次地将本应该声明为成员的变量声明为了一个全局变量,但实际工程开发中,请尽量避免全局变量的使用。

IContextMenu第六部分:显示菜单帮助信息

在我们调用TrackPopupMenuEx的前后,我们将对这个变量进行更新,如下图所示:

IContextMenu第六部分:显示菜单帮助信息

做好了如上的准备工作之后,我们就可以开始编写代码,实现在用户浏览上下文菜单项时显示对应的帮助信息了,我们先看看下面的代码:

IContextMenu第六部分:显示菜单帮助信息

这个函数首先检查被选中的菜单是否位于我们定义的范围,如果是,则我们通过调用GetCommandString方法来获取对应的帮助信息,并显示在窗口的标题栏上。

最后,我们将这个函数集成到我们的窗口过程中。我们希望即使上下文菜单处理器会对菜单做后续的操作,我们也能更新菜单项的选中状态并显示在窗口的标题栏上,所以,这里我们在将消息分发到菜单处理器之前就调用了我们定义的OnMenuSelect函数,如下图所示:

IContextMenu第六部分:显示菜单帮助信息

先等会

细心的读者可能发现了,在上面的代码中,我们有一条注释说以下代码可能存在Bug,具体是什么神仙Bug呢?

请稍安勿躁,其实技术上来说,也没有什么Bug,只是,当你尝试运行这段代码的时候,你会觉察到程序的行为有些怪异。

这是因为,有一些上下文菜单处理器没有很好地实现,Bug也源自于此。

有一些处理器没有支持Unicode,有一些则没有支持ANSI。更加有意思的是,他们没有实现对应的代码,同时,没有按照惯例返回E_NOTIMPL错误代码,而是直接返回了S_OK。还有另外一些处理器存在潜在的缓冲区溢出问题,他们会在超出内存边界的位置写入数据。

很好,欢迎大家再次来到应用程序兼容性的世界。

下面我们来写一个帮助函数,试着解决上面所提到的各种问题。

IContextMenu第六部分:显示菜单帮助信息
IContextMenu第六部分:显示菜单帮助信息

在外壳代码实现中,类似于上面的代码随处可见。

接下来,我们将这个帮助函数集成到OnMenuSelect中,如下图所示:

IContextMenu第六部分:显示菜单帮助信息

新的版本可以正确地显示被支持的菜单项帮助信息,也能容忍一些未能正确实现的处理器错误,甚至是一些比较严重的安全性问题,例如缓冲区溢出问题。

好了,今天的支线任务就先到这里。在下一篇文章中,我们将回到主线,即默认操作的调用。

总结

其实获取帮助信息的实现并不复杂,只是你需要面对一个不那么完美的真实世界。

为了保持兼容性,还得在设计上多考虑各种意外情况,在代码上也多下些功夫。

最后

最近我写了个东西

继续阅读