Microsoft Visual Studio 2005 Doxygen 插件





5.00/5 (1投票)
MSVS 插件用于 Doxygen 文档系统。
引言
此 MSVS 插件允许选择加载解决方案中包含的多个文件并将它们传递给 Doxygen。它还提供了选择项目名称和目标文件夹的可用性。所有其他 Doxygen 选项都可以通过插件执行的 Doxywizard 进行设置。我尽量做得简单,以便将来扩展,下次会完成。
必备组件
用法
- Microsoft Visual Studio 2005
- Doxygen。从 http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc 下载
构建源代码
- Boost(我使用了 boost.1.38.0)。从 https://boost.ac.cn/下载
- WTL 80。从 http://www.microsoft.com/downloads/details.aspx?familyid=E5BA5BA4-6E6B-462A-B24C-61115E846F0C&displaylang=en下载
描述
Doxygen 插件可以从 MSVS IDE 的“工具”菜单运行。
此选项卡允许选择用于文档生成的文件的

这用于 Doxygen 的原始设置

“Doxygen 可执行文件”&“Doxywizard 可执行文件”
它们在插件启动时被搜索。但如果需要,我留了一个手动选择的选项。
“名称”用于文档生成,可以在 Doxywizard 中更改。
“Doxygen 配置文件”
运行 Doxywizard 时,您可以微调生成的文档的选项,并为不同目的保存各种配置文件。然后,您可以选择所需的配置并运行 Doxygen。
“输出目录”是告诉 Doxygen 将文档放在哪里。在 Doxywizard 模式下也可以更改。
代码
MSVS 插件架构
首先,我将尝试解释(并理解我自己)MSVS 插件架构的一些重要方面。
让我们看这张图

预加载插件*
(*) 仅当您在注册脚本(Addin.rgs)中使用 CommandPreload
标志设置为“1”时,才会发生这种情况。它表示您的插件必须预加载以设置 UI。之后,插件将被卸载。
重要:请记住,所有已初始化的类成员和局部对象将在 UI 设置完成后被销毁。
第一次创建对象<CConnect
>是为了提供设置 UI 的可用性,这可以在 OnConnect( ConnectMode == ext_cm_UISetup )
中完成。此时,我们将我们的控件添加到菜单栏(这也可以通过“Visual Studio Add-in Wizard”完成)。命令是使用 EnvDTE80::Commands2
接口的 AddNamedCommand2
方法创建的。存储创建的命令是没有意义的,因为它只在第一次运行时创建一次,并由 MSVS IDE 环境保存。稍后,我将展示如何获取它以便在“Add-in Manager”中取消选中我们的插件的可用性时将其删除。
之后,我们收到 OnDisconnection( RemoveMode == ext_dm_UISetupComplete )
,它告诉我们“插件在用户界面设置后被卸载”(MSDN)。
最后,我们的对象将被销毁。调用 FinalRelease()
和随后的对象析构函数调用告诉我们这一点。
加载插件
UI 设置完成后,插件将第二次加载(如果设置了 CommandPreload
)(构造函数和 FinalConstruct()
的新调用表明了这一点)。
现在我们将收到 OnConnect (ConnectMode == ext_cm_CommandLine
)。此时,我们的插件已被 MSVS 环境加载。
下一项是 OnAddInsUpdate()
,它“在插件加载或从 Visual Studio 集成开发环境 (IDE) 卸载时发生”(MSDN)。我们可以通过分析 OnConnection()
的最后一次调用中的 ConnectMode::ext_ConnectMode
参数和 OnDisconnection()
方法中的 RemoveMode::ext_DisconnectMode
来检测其类型(加载/卸载)。
最后是 OnStartupComplete
。它“在设置为在 Visual Studio 启动时加载的插件加载时发生”。
检查/取消选中“Add-in Manager”中的可用性通知
取消选中可用性
当我们在“Add-in Manager”中取消选中插件时,我们会收到 OnDisconnect( RemoveMode == ext_dm_UserClosed )
。此时,我们可以从菜单栏中删除我们的项目。
如果我们将 CommandPreload
标志设置为“1”(参见“预加载插件”),那么我们没有指向我们命令的变量,需要手动获取它。这是这样做的
IfFailGoCheck(m_pDTE->get_Commands(&pCommands), pCommands);
CComQIPtr< EnvDTE::Command > dx_cmd;
IfFailGoCheck( pCommands->Item( CComVariant
( "DoxygenAddin.Connect.DoxygenAddin" ), 0, &dx_cmd ), dx_cmd );
dx_cmd->Delete();
重要:“ DoxygenAddin.Connect.DoxygenAddin
”是命令的完整名称。它由两部分组成:类“ DoxygenAddin.Connect
”的完整名称和命令的名称“ DoxygenAddin
”。 EnvDTE::Command
的 Delete()
方法将其从菜单栏中删除。
如果我们的命令不是在 OnConnection( ConnectMode == ext_cm_UISetup )
中创建的,那么我们可以通过显式调用已创建 EnvDTE::Command
对象中的 EnvDTE::Command::Delete()
来删除它。
检查可用性
当我们再次选中它时,会调用 OnConnection( ConnectMode == ext_cm_AfterStartup )
。我们所要做的就是使用 EnvDTE80::Commands2
接口的 AddNamedCommand2
方法重新添加我们的控件菜单按钮,就像之前所做的那样。
不幸的是,它仅在加载任何解决方案时才能正常工作。当我移除没有加载解决方案的按钮时,我无法再次添加它,:-(。为什么会这样——我不知道。如果有人能解释一下——我将很高兴:)。
插件可用性(启用/禁用)
另一个问题是,我不想在没有解决方案存在时执行我的插件。为此编写了 CSolutionEventsSink
类。它继承了 IDispEventImpl
和 __uuidof(EnvDTE::_dispSolutionEvents)
,并接收“Opened
”和“BeforeClosing
”解决方案事件。
BEGIN_SINK_MAP(SolutionEventsSink)
SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispSolutionEvents), 1, Opened)
SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispSolutionEvents), 2, BeforeClosing)
END_SINK_MAP()
上面的代码可以轻松解决这个问题,但我对深入研究它感兴趣。我感兴趣的是如何在运行时在一个类中接收所有 dispids、函数名称以及其中其他信息,以便执行动态建议。
宏 和
BEGIN_SINK_MAP
和 SINK_ENTRY_EX
声明了 _GetSinkMap() static
方法并创建了 static
数组 _ATL_EVENT_ENTRY
条目,其中包含通过 dispids 将事件与用户回调关联所需的信息。
我们的 sink 类派生自 IDispEventImpl
及其父类 IDispEventSimpleImpl
包含 static
对象类型为 CComTypeInfoHolder
。从它获取 ITypeInfo
有助于我们接收 EnvDTE::_dispSolutionEvents
的所有类型信息。现在我们可以创建 _ATL_EVENT_ENTRY
条目数组,运行时。
在对 EnvDTE::SolutionEvents
对象感兴趣的事件进行建议后,我所要做的就是在 CConnect::QueryStatus
中检查解决方案的当前状态,并使菜单项启用或禁用。
CConnect::CheckHasSolution()
有助于确定在解决方案已存在时插件是否在“Add-in Manager”中被选中。这可以通过分析 EnvDTE::_Solution
项计数属性(EnvDTE::_Solution
对象始终存在,但可能包含也可能不包含子项)来轻松完成。
重要
看看 CSolutionEventsSink
类的声明
class CSolutionEventsSink : public IDispEventImpl< 1, CSolutionEventsSink
, &__uuidof( EnvDTE::_dispSolutionEvents ), &EnvDTE::LIBID_EnvDTE, 8, 0 >
8
- 是类型库的主版本号。由于它是在 MSVS 8.0 下构建的,所以这个数字表示其主版本号。在其他版本的 MSVS IDE 中,它会有所不同。
获取解决方案项
获取解决方案项相对简单。我们可以从 EnvDTE80::DTE2
获取 EnvDTE::_Solution
对象。然后获取其中项目的数量(EnvDTE::_Solution::get_Count()
)以及所有 EnvDTE::Project
对象。同样,您可以从 EnvDTE::Project
对象获取 EnvDTE::ProjectItems
。
唯一有趣的是确定 EnvDTE::ProjectItems
是否指向一个文件。这是通过分析其 Kind
属性来完成的。 EnvDTE::vsProjectItemKindPhysicalFile
指出这一点。
重要:如果您将文件加载到空的 IDE 中,它也会创建一个解决方案(EnvDTE::_Solution
)、项目(EnvDTE::Project
)和项目项(EnvDTE::ProjectItems
)(未在“解决方案资源管理器”中显示),因此您可以轻松获取它。
超出范围
CCBTreeViewCtrl
为了查看和选择用于文档生成的文件的,我使用了 CCBTreeViewCtrl
类,它扩展了 WTL::CTreeViewCtrlEx
。
它为其父类增加了 3 个新功能
- 通过父级选择/取消选择整个分支
- 当子项状态不同时,父项会呈灰色显示
ParseTree()
方法,有助于处理来自指定项的所有子项
Boost::spirit 解析
它看起来并不简单,难以理解和使用,但当你得到你想要的结果时,它看起来很棒,:).
pugi::pugixml
轻量级且直观的 XML 解析库。