Comments Workbench for C++ - Visual Studio .NET 插件






1.67/5 (5投票s)
2004年6月9日
5分钟阅读

48166

633
Comments workbench for C++ - a Visual Studio .NET add-in.
引言
所以,你已经写完了所有的代码,正悠闲地等着同事来评审。你打电话给你的女朋友,约她晚上见面,因为你所有的工作都终于结束了。你正准备下班,你的评审人打来电话,告诉你他一个字都看不懂你的代码,问你有没有上过高中,如果上过,你就应该知道代码在送审之前需要注释得很好吧?你终于打开了你最喜欢的编辑器,它以树状视图显示了所有的函数、类等,你创建了一个基本的注释模板。现在,你逐个函数地粘贴你的模板,然后逐个函数地编辑这个模板以适应代码并解释清楚。完成所有这些之后,你会想,这是否是最好的方法,或者你有没有可能更快地完成(而不取消你的约会)?我想,即使没有这个虚构的故事(我只是为了填补这个介绍部分;)),我们都明白注释的重要性。
幕后到底发生了什么?
嗯,在完全归功于代码之前,我必须感谢 Microsoft Visual Studio 7 架构师们向插件开发者公开了代码结构,否则这个项目是不可能实现的。那些看过或用过 C++ 语法的人会同意我的观点——它非常庞大且令人困惑!我见过很多类似的宏,但它们猜测参数、类型等,并且每一个都强制执行一种特定的注释风格。
实现这个插件的另一个目的是为了更多地学习 ATL,以及微软如何通过 COM 公开其接口来编写与产品无缝集成的插件。那些有 COM/ATL 经验的人,在看到代码后,会立刻意识到我只是这个学科的初学者,代码离稳定还有很长的路要走。
现在长话短说,让我们看看幕后到底发生了什么。
我们已经有什么了?
当你使用向导创建一个新项目时,你会得到以下内容:
- 一个预定义的、半实现的类,名为
CConnect
,它有以下声明:class ATL_NO_VTABLE <CODE>CConnect : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CConnect, &CLSID_Connect>, public IDispatchImpl<EnvDTE::IDTCommandTarget, \ &EnvDTE::IID_IDTCommandTarget, &EnvDTE::LIBID_EnvDTE, 7, 0>, public IDispatchImpl<AddInDesignerObjects::_IDTExtensibility2, \ &AddInDesignerObjects::IID__IDTExtensibility2, &AddInDesignerObjects::LIBID_AddInDesignerObjects, 1, 0>
CConnect
派生的每个类的函数将在下面解释:CComObjectRootEx
- 用于通过 Query interface 机制公开你的接口。你只需要在BEGIN_COM_MAP
和END_COM_MAP
宏中使用COM_INTERFACE_ENTRY
输入你的代码,其余的将由这个类处理。CComCoClass
- 这个类有助于创建类的实例并获取其属性。简而言之,它有助于你声明一个类工厂,并声明你的类可以被聚合。另一个宏OBJECT_ENTRY_AUTO
有助于在注册表中更新信息,并在 DLL 被调用时立即实例化类的对象。IDispatchImpl
- 这个类提供了EnvDTE::IDTCommandTarget
接口的IDispatch
部分的默认实现。因此,我们实现了EnvDTE::IDTCommandTarget
以便能够添加命名命令,并让宿主知道我们有可执行的命令。我们还实现了AddInDesignerObjects::_IDTExtensibility2
的IDispatch
,以便宿主可以通知我们启动、连接和关闭等各种操作。
嗯,以上大部分内容都是从 MSDN 复制或派生而来的,因为细节超出了文章的范围。我这里想说的是,向导完成了大部分工作,我们无需担心我们的插件将如何加载或销毁。下面,我们来看看为了实现我们的目标需要做什么。
- 我们还为我们的类
CConnect
派生的各种接口提供了存根实现。CConnect::OnConnection
- 在宿主连接到插件时调用。这是添加命令和工具栏对象到宿主的好时机。为此,我们使用EnvDTE::_DTE
的一个实例,其中EnvDTE
是类型库,_DTE
是类接口,它提供了对宿主公开的代码结构和各种项的访问。CConnect::OnDisconnection
- 我们可以释放连接时获取的所有资源。通常,因为我们在连接时在插件中存储了EnvDTE::_DTE
的引用,我们可以在这里释放它。CConnect::QueryStatus
- 由宿主调用,以获取插件支持的命令名称。CConnect::Exec
- 由宿主调用,以在插件内执行命令。这就是所有动作发生的地方。
我们该做什么?
如果你仔细研究了上面的部分,你将立即意识到 EnvDTE::_DTE
对象将为我们提供各种代码结构细节。现在,从这里开始,对于任何 C++ 爱好者来说都是小菜一碟。简而言之,我做了以下事情:
- 创建了主对话框,显示代码树和两个编辑框(一个用于注释,一个用于代码部分)。
- 主对话框显然使用
_DTE
对象来填充代码树。 - 当你点击树中的某个项目时,它会再次使用
_DTE
对象来获取代码项在编辑器中的位置,然后查找它前面的注释。如果找到,它会检查注释是否与配置的模板一致。如果一致,它会显示准确的注释,否则,它会显示“/*
”和“*/
”之间的内容。 - 模板对话框可以从主对话框调用,你可以在其中配置用于配置每个项目注释格式的模板。
已知问题
- 下拉列表不下拉 :)。你必须使用键盘来更改下拉列表选中的值。
- 根据风格反转注释尚未完美。
- 它绝不完美或安全,并且可能会搞乱你的代码。因此,请谨慎使用!
对其他语言的支持
这是一个 beta 版本,因此仅用于测试此类工具的需求。如果需求量很大,我可能会考虑为各种语言支持此工具。不过,目前这并不容易(由于一些设计上的决定)。