GacUI為了實(shí)現(xiàn)把界面序列化和反序列化到XML,必然要有類似反射一樣的功能。但是C++卻沒有反射,現(xiàn)在想到的方法就是,把編譯后的pdb文件拿出來(lái)。因?yàn)榭丶皇悄0孱悾詳?shù)據(jù)都可以直接獲取。pdb文件包含了所有函數(shù)的信息,還有被實(shí)例化后的模板類和模板函數(shù)的信息。因此只需要使用IDiaDataSource(Visual Studio提供的COM組件)讀取pdb的類聲明之后,把信息整理并輸出到一個(gè)xml里面,然后就可以用C#編寫linq to xml的程序去分析并生成支持C++反射的一系列周邊代碼了。這樣就自動(dòng)讓C++其中一部分必要的類獲得反射的功能,代價(jià)就是每一次修改完代碼之后,要記得非人肉地更新自動(dòng)生成的代碼。
不過(guò)為了更加形象的展示pdb的內(nèi)容,我使用GacUI的帶Virtual Mode的TreeView打開pdb填充。這里面有兩個(gè)view,第一個(gè)是pdb,第二個(gè)是整理后的class view。顯示pdb的GuiTreeView控件展示了如何通過(guò)提供一個(gè)數(shù)據(jù)源,從而實(shí)現(xiàn)“展開的時(shí)候再?gòu)膒db文件里面讀取信息”的技術(shù)。而class view則是通過(guò)提供一個(gè)數(shù)據(jù)源來(lái)將一個(gè)文件中的xml讀取到內(nèi)存并顯示出來(lái),但是避免new那些暫時(shí)還不需要顯示出來(lái)的TreeViewNode對(duì)象。代碼放在
Vczh Library++ 3.0(Candidate\GUI\GUIDemo\GUIDemo.sln)。現(xiàn)在先上圖:


解析PDB的關(guān)鍵代碼在DumpPDB.cpp文件中,大家只需要下載代碼并閱讀即可。所有的內(nèi)容都可以從MSDN搜索IDiaDataSource獲得,但是運(yùn)行的話則需要有這個(gè)COM組件,一般要求安裝Visual Studio。下面解釋一下一段C++代碼。這是上面那個(gè)按鈕的回調(diào)函數(shù)。這個(gè)回調(diào)函數(shù)做了下面幾件事情
1、將Button和TagPage都Disable
2、利用線程池異步將PDB的內(nèi)容保存到XML文件中(一秒鐘)
3、第2步完成之后,發(fā)一個(gè)消息回到GUI線程,自動(dòng)顯示第二個(gè)TagPage
4、異步將XML讀取到內(nèi)存。在這里我沒有使用延遲讀取技術(shù),所以我直接創(chuàng)建了大約幾百萬(wàn)個(gè)字符串,需要五秒鐘
5、第4步完成之后,發(fā)一個(gè)消息回到GUI線程嗎,將創(chuàng)建好的內(nèi)存中的XML格式顯示在TreeView里
這些異步操作來(lái)往十分復(fù)雜,但是借助C++0x就可以描述得十分清晰。GacUI的實(shí)現(xiàn)并沒有使用C++0x,但是仍然可以為使用C++0x的那部分用戶提供一些更加優(yōu)化的接口。因此這些復(fù)雜的步驟最后就寫成了:
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<TreeElement> xml=LoadXmlRawDocument(reader).Cast<TreeElement>();
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()->GetContainerComposition()->AddChild(treeControl->GetBoundsComposition());
});
});
});
});
});
buttonDump->Clicked.AttachLambda的意思是將一個(gè)滿足C++0x標(biāo)準(zhǔn)的lambda表達(dá)式當(dāng)成一個(gè)事件處理程序綁定到一個(gè)時(shí)間上。ThreadPoolLite::QueueLambda則是將一個(gè)lambda表達(dá)式放進(jìn)Windows內(nèi)核實(shí)現(xiàn)的內(nèi)存池進(jìn)行異步調(diào)用。GetApplication()->InvokeLambdaInMainThread(AndWait)則是在別的線程里將一個(gè)lambda表達(dá)式放到GUI線程(一般是主線程)中運(yùn)行。如果調(diào)用了Wait的版本,則這個(gè)函數(shù)會(huì)一直等到該lambda表達(dá)式在主線程執(zhí)行完了才會(huì)返回。如果大家關(guān)心實(shí)現(xiàn)的話,可以去Candidate\GUI\GUI\NativeWindow\Windows\WinNativeWindow.cpp文件里查看。
大家可以想象,在古老的不支持lambda表達(dá)式的C++版本里面,要實(shí)現(xiàn)這個(gè)過(guò)程,這個(gè)函數(shù)將被拆散成多少函數(shù)。為了傳遞很多復(fù)雜的對(duì)象,要寫多少個(gè)臨時(shí)的struct,new多少內(nèi)存碎片才能將異步回調(diào)函數(shù)的參數(shù)做成Windows所希望的DWORD(__stdcall*)(void*)格式。為了把一部分事情放回到GUI線程做(我們都知道GUI庫(kù)不值得為了線程安全而做很多浪費(fèi)性能的事情),得實(shí)現(xiàn)多少私有的Win32消息,subclass多少東西才能最終做到。這一切在GacUI中都簡(jiǎn)化了。
接下來(lái)將會(huì)研究如何利用pdb里面的信息讓跟GacUI有關(guān)的對(duì)象支持反射的具體細(xì)節(jié)。元旦就先休息了,啊哈哈哈。
posted on 2011-12-30 04:12
陳梓瀚(vczh) 閱讀(7625)
評(píng)論(21) 編輯 收藏 引用 所屬分類:
GacUI