GacUI Demo:PDB Viewer(分析pdb文件并获取C++类声明的详细内容) (一)

2014-11-24 12:15:07 · 作者: · 浏览: 0

GacUI为了实现把界面序列化和反序列化到XML,必然要有类似反射一样的功能。但是C++却没有反射,现在想到的方法就是,把编译后的pdb文件拿出来。因为控件不是模板类,所以数据都可以直接获取。pdb文件包含了所有函数的信息,还有被实例化后的模板类和模板函数的信息。因此只需要使用IDiaDataSource(Visual Studio提供的COM组件)读取pdb的类声明之后,把信息整理并输出到一个xml里面,然后就可以用C#编写linq to xml的程序去分析并生成支持C++反射的一系列周边代码了。这样就自动让C++其中一部分必要的类获得反射的功能,代价就是每一次修改完代码之后,要记得非人肉地更新自动生成的代码。

不过为了更加形象的展示pdb的内容,我使用GacUI的带Virtual Mode的TreeView打开pdb填充。这里面有两个view,第一个是pdb,第二个是整理后的class view。显示pdb的GuiTreeView控件展示了如何通过提供一个数据源,从而实现“展开的时候再从pdb文件里面读取信息”的技术。而class view则是通过提供一个数据源来将一个文件中的xml读取到内存并显示出来,但是避免new那些暂时还不需要显示出来的TreeViewNode对象。代码放在Vczh Library++ 3.0http://vlpp.codeplex.com/ (Candidate\GUI\GUIDemo\GUIDemo.sln)。现在先上图:

\

\


解析PDB的关键代码在DumpPDB.cpp文件中,大家只需要下载代码并阅读即可。所有的内容都可以从MSDN搜索IDiaDataSource获得,但是运行的话则需要有这个COM组件,一般要求安装Visual Studio。下面解释一下一段C++代码。这是上面那个按钮的回调函数。这个回调函数做了下面几件事情
1、将Button和TagPage都Disable
2、利用线程池异步将PDB的内容保存到XML文件中(一秒钟)
3、第2步完成之后,发一个消息回到GUI线程,自动显示第二个TagPage
4、异步将XML读取到内存。在这里我没有使用延迟读取技术,所以我直接创建了大约几百万个字符串,需要五秒钟
5、第4步完成之后,发一个消息回到GUI线程吗,将创建好的内存中的XML格式显示在TreeView里

这些异步操作来往十分复杂,但是借助C++0x就可以描述得十分清晰。GacUI的实现并没有使用C++0x,但是仍然可以为使用C++0x的那部分用户提供一些更加优化的接口。因此这些复杂的步骤最后就写成了:

buttonDump->Clicked.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments)
{
INativeController* controller=GetCurrentController();
tabControl->GetPages()[0]->GetContainer()->SetEnabled(false);
buttonDump->SetEnabled(false);
buttonDump->SetText(L"Dumping...");
buttonDump->GetRelatedControlHost()->GetBoundsComposition()->SetAssociatedCursor(controller->GetSystemCursor(INativeCursor::LargeWaiting));

ThreadPoolLite::QueueLambda([=]()
{
dumppdb::DumpPdbToXml(diaSymbol, L"..\\Debug\\GuiDemo.xml");
GetApplication()->InvokeLambdaInMainThread([=]()
{
tabControl->GetPages()[0]->GetContainer()->SetEnabled(true);
tabControl->SetSelectedPage(tabControl->GetPages()[1]);
buttonDump->SetText(L"Loading GuiDemo.xml in the class view...");

ThreadPoolLite::QueueLambda([=]()
{
FileStream fileStream(L"..\\Debug\\GuiDemo.xml", FileStream::ReadOnly);
CacheStream cacheStream(fileStream, 1048576);
BomDecoder decoder;
DecoderStream decoderStream(cacheStream, decoder);
StreamReader reader(decoderStream);
Ptr xml=LoadXmlRawDocument(reader).Cast();

GetApplication()->InvokeLambdaInMainThreadAndWait([=]()
{
buttonDump->SetText(L"GuiDemo.xml dumpped.");
buttonDump->GetRelatedControlHost()->GetBoundsComposition()->SetAssociatedCursor(controller->GetDefaultSystemCursor());

GuiTreeView* treeControl=new GuiTreeView(new win7::Win7TreeViewProvider, CreateProviderFromXml(xml));
treeControl->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
treeControl->SetVerticalAlwaysVisible(false);
treeControl->SetHorizontalAlwaysVisible(false);
tabControl->GetPages()[1]->GetContainer()->Get