Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

810 lines
22 KiB

  1. // QueryDB.cpp: Database querying methods.
  2. #include "stdafx.h"
  3. #include "AppParseWeb.h"
  4. #include "AppParseWrapper.h"
  5. #include <oledb.h>
  6. #include <comdef.h>
  7. #include <mshtml.h>
  8. #include <assert.h>
  9. // Progress dialog functions
  10. void InitProgressDialog(char* szText, HANDLE hEvent);
  11. void KillProgressDialog();
  12. // Return true if name matches search string, false otherwise.
  13. bool MatchName(char* szString, char* szSearchIn);
  14. // Tree used to represent parse information
  15. class CTreeNode
  16. {
  17. private:
  18. enum {c_Root, c_Project, c_Module, c_Function} m_eType;
  19. int m_nChildren;
  20. CTreeNode** m_ppChildren;
  21. // Relevent info retrieved from DB
  22. union
  23. {
  24. struct
  25. {
  26. char szName[256];
  27. long lPtolemyID;
  28. } m_ProjectInfo;
  29. struct
  30. {
  31. char szName[256];
  32. } m_ModuleInfo;
  33. struct
  34. {
  35. char szName[256];
  36. } m_FunctionInfo;
  37. };
  38. // HTML generation members
  39. // Unique table and div ID's.
  40. static int m_iCurrDiv;
  41. static int m_iCurrTab;
  42. // Amount of space set aside for HTML content.
  43. static int m_iAllocSize;
  44. // Pointer to HTML content.
  45. static char* m_szHTML;
  46. // Pointer to where the more HTML should be inserted.
  47. static char* m_szCurrHTML;
  48. // Pointer a few kilobytes before the end of the HTML buffer, reaching
  49. // here means we should allocate more space.
  50. static char* m_szFencePost;
  51. // True if this node or one of its subtrees contains the function, false otherwise.
  52. bool ContainsFunction(char* szFuncName)
  53. {
  54. if(m_eType == c_Function)
  55. return MatchName(m_FunctionInfo.szName, szFuncName);
  56. for(int i = 0; i < m_nChildren; i++)
  57. {
  58. if(m_ppChildren[i]->ContainsFunction(szFuncName))
  59. return true;
  60. }
  61. return false;
  62. }
  63. // Write all HTML output
  64. void WriteHTML()
  65. {
  66. static int iDepth = 0;
  67. switch(m_eType)
  68. {
  69. case c_Root:
  70. break;
  71. case c_Project:
  72. // Create a new table and Div in the project
  73. m_iCurrTab++;
  74. m_iCurrDiv++;
  75. wsprintf(m_szCurrHTML,
  76. "<table ID = TAB%d border = 1 width = 100%% style=\"float:right\">\n"
  77. "<tr>\n<td width=1%%>\n"
  78. "<input type=\"button\" ID=DIV%dButton value = \"+\" "
  79. "onClick=\"ShowItem(\'DIV%d\')\">"
  80. "</td>\n"
  81. "<td>%s</td><td width=20%%>%d</td>\n</tr>\n"
  82. "</table>\n"
  83. "<DIV ID=DIV%d style=\"display:none;\">\n",
  84. m_iCurrTab, m_iCurrDiv, m_iCurrDiv,
  85. m_ProjectInfo.szName, m_ProjectInfo.lPtolemyID,
  86. m_iCurrDiv);
  87. m_szCurrHTML += strlen(m_szCurrHTML);
  88. break;
  89. case c_Module:
  90. // Create a new table and div in the project
  91. m_iCurrTab++;
  92. m_iCurrDiv++;
  93. wsprintf(m_szCurrHTML,
  94. "<table ID = TAB%d border = 1 width = %d%% style=\"float:right\">\n"
  95. "<tr>\n<td width=1%%>"
  96. "<input type=\"button\" ID=DIV%dButton value = \"+\" "
  97. "onClick=\"ShowItem(\'DIV%d\')\">"
  98. "</td>\n"
  99. "<td>%s</td>\n</tr>\n"
  100. "</table>\n"
  101. "<DIV ID=DIV%d style=\"display:none;\">\n",
  102. m_iCurrTab, 100-iDepth*5, m_iCurrDiv, m_iCurrDiv,
  103. m_ModuleInfo.szName, m_iCurrDiv );
  104. m_szCurrHTML += strlen(m_szCurrHTML);
  105. break;
  106. case c_Function:
  107. // Create a new table in the project
  108. m_iCurrTab++;
  109. wsprintf(m_szCurrHTML,
  110. "<table ID = TAB%d border = 1 width = %d%% style=\"float:right\">\n"
  111. "<tr>"
  112. "<td>%s</td>\n</tr>\n"
  113. "</table>\n",
  114. m_iCurrTab, 100-iDepth*5, m_FunctionInfo.szName);
  115. m_szCurrHTML += strlen(m_szCurrHTML);
  116. break;
  117. default:
  118. assert(0);
  119. break;
  120. }
  121. // Put in all the HTML for the children
  122. if(m_ppChildren)
  123. {
  124. iDepth++;
  125. for(int i = 0; i < m_nChildren; i++)
  126. m_ppChildren[i]->WriteHTML();
  127. iDepth--;
  128. }
  129. switch(m_eType)
  130. {
  131. case c_Function:
  132. case c_Root:
  133. break;
  134. case c_Project:
  135. case c_Module:
  136. wsprintf(m_szCurrHTML, "</DIV>\n");
  137. m_szCurrHTML += strlen(m_szCurrHTML);
  138. break;
  139. }
  140. // Check if we should allocate more
  141. if(m_szCurrHTML > m_szFencePost)
  142. {
  143. m_iAllocSize *= 2;
  144. char* szNewBuffer = new char[m_iAllocSize];
  145. m_szFencePost = &szNewBuffer[m_iAllocSize - 2 * 1024];
  146. strcpy(szNewBuffer, m_szHTML);
  147. m_szCurrHTML = &szNewBuffer[strlen(szNewBuffer)];
  148. delete m_szHTML;
  149. m_szHTML = szNewBuffer;
  150. }
  151. }
  152. public:
  153. CTreeNode()
  154. {
  155. m_eType = c_Root;
  156. m_nChildren = 0;
  157. m_ppChildren = 0;
  158. assert(m_eType < 50);
  159. }
  160. CTreeNode(SProjectRecord pr)
  161. {
  162. m_eType = c_Project;
  163. m_nChildren = 0;
  164. m_ppChildren = 0;
  165. strcpy(m_ProjectInfo.szName, pr.Name);
  166. m_ProjectInfo.lPtolemyID = pr.PtolemyID;
  167. assert(m_eType < 50);
  168. }
  169. CTreeNode(SModuleRecord mr)
  170. {
  171. m_eType = c_Module;
  172. m_nChildren = 0;
  173. m_ppChildren = 0;
  174. strcpy(m_ModuleInfo.szName, mr.Name);
  175. assert(m_eType < 50);
  176. }
  177. CTreeNode(SFunctionRecord fr)
  178. {
  179. m_eType = c_Function;
  180. m_nChildren = 0;
  181. m_ppChildren = 0;
  182. strcpy(m_FunctionInfo.szName, fr.Name);
  183. assert(m_eType < 50);
  184. }
  185. ~CTreeNode()
  186. {
  187. RemoveChildren();
  188. }
  189. // Remove tree nodes that contain no nodes matching the search criteria.
  190. // Returns true if node should be removed, false otherwise.
  191. bool Prune(char* szFunc)
  192. {
  193. assert(m_eType < 50);
  194. // Go through each child
  195. for(int i = 0; i < m_nChildren; i++)
  196. {
  197. // Check if needs to be removed
  198. if(m_ppChildren[i]->Prune(szFunc))
  199. {
  200. // Remove this child.
  201. delete m_ppChildren[i];
  202. m_ppChildren[i] = 0;
  203. }
  204. }
  205. // Update the child list
  206. int nChildren = 0;
  207. for(i = 0; i < m_nChildren; i++)
  208. {
  209. if(m_ppChildren[i])
  210. nChildren++;
  211. }
  212. if(nChildren)
  213. {
  214. CTreeNode** pNew = new CTreeNode*[nChildren];
  215. int iCurr = 0;
  216. for(i = 0; i < m_nChildren; i++)
  217. {
  218. if(m_ppChildren[i])
  219. {
  220. pNew[iCurr++] = m_ppChildren[i];
  221. }
  222. }
  223. delete m_ppChildren;
  224. m_ppChildren = pNew;
  225. assert(iCurr == nChildren);
  226. }
  227. else
  228. {
  229. if(m_ppChildren)
  230. {
  231. delete m_ppChildren;
  232. m_ppChildren = 0;
  233. }
  234. }
  235. m_nChildren = nChildren;
  236. // If we contain no children and we're not a function, we should be removed.
  237. if(m_nChildren == 0 && m_eType != c_Function)
  238. return true;
  239. // Return whether we don't contain the function or not.
  240. return !ContainsFunction(szFunc);
  241. }
  242. // Return a string representing the HTML representation of this tree.
  243. char* GetHTML()
  244. {
  245. // Should only be called on root.
  246. assert(m_eType == c_Root);
  247. // Initially reserve space for 64K of HTML.
  248. m_iAllocSize = 64 * 1024;
  249. if(m_szHTML)
  250. delete m_szHTML;
  251. m_szHTML = new char[m_iAllocSize];
  252. m_szHTML[0] = '\0';
  253. m_szCurrHTML = m_szHTML;
  254. m_szFencePost = &m_szHTML[m_iAllocSize - 2 * 1024];
  255. // Fill it with the HTML for this node and all child nodes.
  256. WriteHTML();
  257. char* szRet = m_szHTML;
  258. m_szHTML = 0;
  259. return szRet;
  260. }
  261. // Remove all children from this node.
  262. void RemoveChildren()
  263. {
  264. assert(m_eType < 50);
  265. while(m_nChildren)
  266. {
  267. delete m_ppChildren[m_nChildren-1];
  268. m_ppChildren[m_nChildren-1] = 0;
  269. m_nChildren--;
  270. }
  271. if(m_ppChildren)
  272. delete m_ppChildren;
  273. m_ppChildren = 0;
  274. assert(m_eType < 50);
  275. }
  276. // Insert a new child.
  277. void InsertChild(CTreeNode* pNew)
  278. {
  279. assert(pNew);
  280. assert(pNew->m_eType < 50);
  281. m_nChildren++;
  282. CTreeNode** pNewList = new CTreeNode*[m_nChildren];
  283. if(m_ppChildren)
  284. {
  285. memcpy(pNewList, m_ppChildren, (m_nChildren-1)*sizeof(CTreeNode*));
  286. delete m_ppChildren;
  287. }
  288. m_ppChildren = pNewList;
  289. m_ppChildren[m_nChildren-1] = pNew;
  290. assert(m_eType < 50);
  291. }
  292. };
  293. // Define the static members of CTreeNode
  294. int CTreeNode::m_iCurrDiv = 0;
  295. int CTreeNode::m_iCurrTab = 0;
  296. int CTreeNode::m_iAllocSize = 0;
  297. char* CTreeNode::m_szHTML = 0;
  298. char* CTreeNode::m_szCurrHTML = 0;
  299. char* CTreeNode::m_szFencePost = 0;
  300. // Global tree info.
  301. CTreeNode g_InfoTreeRoot;
  302. // Return true if name matches search string, false otherwise.
  303. bool MatchName(char* szString, char* szSearchIn)
  304. {
  305. if(strcmp(szSearchIn, "*") == 0)
  306. return true;
  307. char* szSearch = szSearchIn;
  308. while(*szSearch != '\0' && *szString != '\0')
  309. {
  310. // If we get a ?, we don't care and move on to the next
  311. // character.
  312. if(*szSearch == '?')
  313. {
  314. szSearch++;
  315. szString++;
  316. continue;
  317. }
  318. // If we have a wildcard, move to next search string and search for substring
  319. if(*szSearch == '*')
  320. {
  321. char* szCurrSearch;
  322. szSearch++;
  323. if(*szSearch == '\0')
  324. return true;
  325. // Don't change starting point.
  326. szCurrSearch = szSearch;
  327. for(;;)
  328. {
  329. // We're done if we hit another wildcard
  330. if(*szCurrSearch == '*' ||
  331. *szCurrSearch == '?')
  332. {
  333. // Update the permanent search position.
  334. szSearch = szCurrSearch;
  335. break;
  336. }
  337. // At end of both strings, return true.
  338. if((*szCurrSearch == '\0') && (*szString == '\0'))
  339. return true;
  340. // We never found it
  341. if(*szString == '\0')
  342. return false;
  343. // If it doesn't match, start over
  344. if(toupper(*szString) != toupper(*szCurrSearch))
  345. {
  346. // If mismatch on first character
  347. // of search string, move to next
  348. // character in function string.
  349. if(szCurrSearch == szSearch)
  350. szString++;
  351. else
  352. szCurrSearch = szSearch;
  353. }
  354. else
  355. {
  356. szString++;
  357. szCurrSearch++;
  358. }
  359. }
  360. }
  361. else
  362. {
  363. if(toupper(*szString) != toupper(*szSearch))
  364. {
  365. return false;
  366. }
  367. szString++;
  368. szSearch++;
  369. }
  370. }
  371. if((*szString == 0) && ((*szSearch == '\0') || (strcmp(szSearch,"*")==0)))
  372. return true;
  373. else
  374. return false;
  375. }
  376. // Add all functions from a module to the tree.
  377. void BuildFunctions(long lParentID, CTreeNode* pParent, _ConnectionPtr pConn)
  378. {
  379. _RecordsetPtr pFunctions = 0;
  380. pFunctions.CreateInstance(__uuidof(Recordset));
  381. char szQuery[1024];
  382. // Open a recordset of all functions that match
  383. wsprintf(szQuery, "SELECT * FROM FUNCTIONS WHERE MODULEID = %d", lParentID);
  384. pFunctions->Open(szQuery, variant_t((IDispatch*)pConn, true), adOpenKeyset,
  385. adLockOptimistic, adCmdText);
  386. // Bind the record set to a local structure.
  387. IADORecordBinding* pRBFunctions = 0;
  388. HRESULT hr = pFunctions->QueryInterface(__uuidof(IADORecordBinding),
  389. reinterpret_cast<void**>(&pRBFunctions));
  390. if(FAILED(hr))
  391. APError("Unable to acquire record binding interface", hr);
  392. SFunctionRecord fr;
  393. hr = pRBFunctions->BindToRecordset(&fr);
  394. if(FAILED(hr))
  395. APError("Unable to bind recordset", hr);
  396. // Go through each record in the set
  397. VARIANT_BOOL fEOF;
  398. pFunctions->get_EndOfFile(&fEOF);
  399. while(!fEOF)
  400. {
  401. // Create a new node.
  402. CTreeNode* pNewNode = new CTreeNode(fr);
  403. pParent->InsertChild(pNewNode);
  404. pFunctions->MoveNext();
  405. pFunctions->get_EndOfFile(&fEOF);
  406. }
  407. pFunctions->Close();
  408. SafeRelease(pRBFunctions);
  409. }
  410. // Add all modules to the tree.
  411. void BuildModules(long lParentID, CTreeNode* pParent, bool fTopLevel,
  412. _ConnectionPtr pConn, HANDLE hEvent)
  413. {
  414. // Check if we should termiante early.
  415. if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
  416. return;
  417. _RecordsetPtr pModules = 0;
  418. pModules.CreateInstance(__uuidof(Recordset));
  419. char szQuery[1024];
  420. // Get recordset that matches
  421. if(fTopLevel)
  422. wsprintf(szQuery, "SELECT * FROM MODULES WHERE PTOLEMYID = %d", lParentID);
  423. else
  424. wsprintf(szQuery, "SELECT * FROM MODULES WHERE PARENTID = %d", lParentID);
  425. pModules->Open(szQuery, variant_t((IDispatch*)pConn, true), adOpenKeyset,
  426. adLockOptimistic, adCmdText);
  427. IADORecordBinding* pRBModules = 0;
  428. HRESULT hr = pModules->QueryInterface(__uuidof(IADORecordBinding),
  429. reinterpret_cast<void**>(&pRBModules));
  430. if(FAILED(hr))
  431. APError("Unable to acquire record binding interface", hr);
  432. SModuleRecord mr;
  433. hr = pRBModules->BindToRecordset(&mr);
  434. if(FAILED(hr))
  435. APError("Unable to bind recordset", hr);
  436. // Go through each record
  437. VARIANT_BOOL fEOF;
  438. pModules->get_EndOfFile(&fEOF);
  439. while(!fEOF)
  440. {
  441. // Insert into tree
  442. CTreeNode* pNewNode = new CTreeNode(mr);
  443. pParent->InsertChild(pNewNode);
  444. // Build all child modules
  445. BuildModules(mr.ModuleID, pNewNode, false, pConn, hEvent);
  446. // Build all functions
  447. BuildFunctions(mr.ModuleID, pNewNode, pConn);
  448. pModules->MoveNext();
  449. pModules->get_EndOfFile(&fEOF);
  450. }
  451. pModules->Close();
  452. SafeRelease(pRBModules);
  453. }
  454. // Add a project to the tree
  455. void BuildProjects(long PtolemyID, char* szFunc, _ConnectionPtr pConn, HANDLE hEvent)
  456. {
  457. assert(PtolemyID > 0);
  458. // Check if we should terminate early
  459. if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
  460. return;
  461. _RecordsetPtr pProjects = 0;
  462. pProjects.CreateInstance(__uuidof(Recordset));
  463. char szQuery[1024];
  464. // Get a recordset that matches
  465. wsprintf(szQuery, "SELECT * FROM PROJECTS WHERE PTOLEMYID = %d", PtolemyID);
  466. pProjects->Open(szQuery, variant_t((IDispatch*)pConn, true),adOpenKeyset,
  467. adLockOptimistic, adCmdText);
  468. IADORecordBinding* pRBProjects = 0;
  469. HRESULT hr = pProjects->QueryInterface(__uuidof(IADORecordBinding),
  470. reinterpret_cast<void**>(&pRBProjects));
  471. if(FAILED(hr))
  472. APError("Unable to acquire record binding interface", hr);
  473. SProjectRecord pr;
  474. hr = pRBProjects->BindToRecordset(&pr);
  475. if(FAILED(hr))
  476. APError("Unable to bind recordset", hr);
  477. VARIANT_BOOL fEOF;
  478. pProjects->get_EndOfFile(&fEOF);
  479. while(!fEOF)
  480. {
  481. // Insert the node at the root.
  482. CTreeNode* pNewNode = new CTreeNode(pr);
  483. g_InfoTreeRoot.InsertChild(pNewNode);
  484. // Get all child modules
  485. BuildModules(pr.PtolemyID, pNewNode, true, pConn, hEvent);
  486. // Save memory by trimming tree now.
  487. pNewNode->Prune(szFunc);
  488. pProjects->MoveNext();
  489. pProjects->get_EndOfFile(&fEOF);
  490. }
  491. pProjects->Close();
  492. SafeRelease(pRBProjects);
  493. }
  494. long GetModulePtolemy(long lModuleID, _ConnectionPtr pConn)
  495. {
  496. _RecordsetPtr pModules = 0;
  497. pModules.CreateInstance(__uuidof(Recordset));
  498. char szQuery[1024];
  499. // Get a single record recordset containing the module.
  500. wsprintf(szQuery, "SELECT * FROM MODULES WHERE MODULEID = %d", lModuleID);
  501. pModules->Open(szQuery, variant_t((IDispatch*)pConn, true), adOpenKeyset,
  502. adLockOptimistic, adCmdText);
  503. IADORecordBinding* pRBModules = 0;
  504. HRESULT hr = pModules->QueryInterface(__uuidof(IADORecordBinding),
  505. reinterpret_cast<void**>(&pRBModules));
  506. if(FAILED(hr))
  507. APError("Unable to acquire record binding interface", hr);
  508. SModuleRecord mr;
  509. hr = pRBModules->BindToRecordset(&mr);
  510. if(FAILED(hr))
  511. APError("Unable to bind recordset", hr);
  512. // Either return ptolemy ID, if valid, otherwise call on parent module.
  513. long lParent = mr.ParentID;
  514. if(mr.ParentIDStatus != adFldNull)
  515. {
  516. pModules->Close();
  517. SafeRelease(pRBModules);
  518. return GetModulePtolemy(lParent, pConn);
  519. }
  520. else
  521. {
  522. pModules->Close();
  523. SafeRelease(pRBModules);
  524. return lParent;
  525. }
  526. }
  527. long GetFuncPtolemy(SFunctionRecord fr, _ConnectionPtr pConn)
  528. {
  529. return GetModulePtolemy(fr.ModuleID, pConn);
  530. }
  531. // Build a list projects that contain a function that matches szFunc.
  532. void BuildProjectsFromFunction(char* szFunc, _ConnectionPtr pConn, HANDLE hEvent)
  533. {
  534. // Check if we should terminate early.
  535. if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
  536. return;
  537. _RecordsetPtr pFunctions = 0;
  538. pFunctions.CreateInstance(__uuidof(Recordset));
  539. char* szQuery = "SELECT * FROM FUNCTIONS";
  540. pFunctions->Open(szQuery, variant_t((IDispatch*)pConn, true),adOpenKeyset,
  541. adLockOptimistic, adCmdText);
  542. IADORecordBinding* pRBFunctions = 0;
  543. HRESULT hr = pFunctions->QueryInterface(__uuidof(IADORecordBinding),
  544. reinterpret_cast<void**>(&pRBFunctions));
  545. if(FAILED(hr))
  546. APError("Unable to acquire record binding interface", hr);
  547. SFunctionRecord fr;
  548. hr = pRBFunctions->BindToRecordset(&fr);
  549. if(FAILED(hr))
  550. APError("Unable to bind recordset", hr);
  551. VARIANT vtBookMark;
  552. hr = pFunctions->get_Bookmark(&vtBookMark);
  553. if(FAILED(hr))
  554. APError("Unable to get recordset bookmark", hr);
  555. // Do a search for the function
  556. char szFind[512];
  557. int FunctionList[1024] = {0};
  558. wsprintf(szFind, "Name like \'%s\'", szFunc);
  559. pFunctions->Find(szFind, 0, adSearchForward, vtBookMark);
  560. while(!pFunctions->EndOfFile)
  561. {
  562. // Get which module imports this function
  563. long lPtolemy = GetFuncPtolemy(fr, pConn);
  564. assert(lPtolemy > 0);
  565. // Make sure we haven't already touched this module.
  566. bool fInUse = false;
  567. for(int i = 0; i < 1024; i++)
  568. {
  569. if(FunctionList[i] == 0)
  570. {
  571. FunctionList[i] = lPtolemy;
  572. break;
  573. }
  574. else if(FunctionList[i] == lPtolemy)
  575. {
  576. fInUse = true;
  577. }
  578. }
  579. if(!fInUse)
  580. BuildProjects(lPtolemy, szFunc, pConn, hEvent);
  581. hr = pFunctions->get_Bookmark(&vtBookMark);
  582. if(FAILED(hr))
  583. APError("Unable to acquire recordset bookmark", hr);
  584. pFunctions->Find(szFind, 1, adSearchForward, vtBookMark);
  585. }
  586. SafeRelease(pRBFunctions);
  587. pFunctions->Close();
  588. }
  589. STDMETHODIMP CAppParse::QueryDB(long PtolemyID, BSTR bstrFunction)
  590. {
  591. assert(m_hEvent);
  592. try
  593. {
  594. // Start cancelation dialog
  595. ResetEvent(m_hEvent);
  596. InitProgressDialog("Querying database . . .", m_hEvent);
  597. bstr_t bszFunctionSearch = bstrFunction;
  598. char* szFunctionSearch = static_cast<char*>(bszFunctionSearch);
  599. HRESULT hr;
  600. _ConnectionPtr pConn = 0;
  601. pConn.CreateInstance(__uuidof(Connection));
  602. // Connect to the DB
  603. pConn->Open(m_szConnect, "","", adConnectUnspecified);
  604. // Build projects
  605. if(PtolemyID > 0)
  606. BuildProjects(PtolemyID, szFunctionSearch, pConn, m_hEvent);
  607. else
  608. BuildProjectsFromFunction(szFunctionSearch, pConn, m_hEvent);
  609. pConn->Close();
  610. // Check if results should be shown.
  611. if(WaitForSingleObject(m_hEvent, 0) == WAIT_OBJECT_0)
  612. {
  613. g_InfoTreeRoot.RemoveChildren();
  614. KillProgressDialog();
  615. return S_OK;
  616. }
  617. // Trim the tree down.
  618. g_InfoTreeRoot.Prune(szFunctionSearch);
  619. // Get our container document.
  620. CComPtr<IOleContainer> pContainer = 0;
  621. m_spClientSite->GetContainer(&pContainer);
  622. CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> pDoc(pContainer);
  623. if(!pDoc)
  624. APError("Unable to acquire container HTML document", E_FAIL);
  625. CComPtr<IHTMLElementCollection> pElements;
  626. pDoc->get_all(&pElements);
  627. CComPtr<IDispatch> pDispatch = 0;
  628. // Get the element that will contain all HTML output (the "Results" DIV)
  629. hr = pElements->item(variant_t("Results"), variant_t(0L), &pDispatch);
  630. if(FAILED(hr) || !pDispatch)
  631. return E_FAIL;
  632. CComQIPtr<IHTMLElement, &IID_IHTMLElement> pDivElem(pDispatch);
  633. // Get HTML representation of tree.
  634. char* szHTML = g_InfoTreeRoot.GetHTML();
  635. // Convert to wide characters
  636. OLECHAR* oszInnerHTML = new OLECHAR[strlen(szHTML) + 1];
  637. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szHTML,
  638. -1, oszInnerHTML,
  639. (strlen(szHTML)+1)*sizeof(OLECHAR));
  640. delete szHTML;
  641. // Convert to a BSTR
  642. BSTR bszInnerHTML = SysAllocString(oszInnerHTML);
  643. delete oszInnerHTML;
  644. // Write the HTML into the document.
  645. hr = pDivElem->put_innerHTML(bszInnerHTML);
  646. if(FAILED(hr))
  647. APError("Unable to write HTML to container document", hr);
  648. SysFreeString(bszInnerHTML);
  649. }
  650. catch(_com_error& e)
  651. {
  652. ::MessageBox(0, (LPCSTR)e.ErrorMessage(), "COM Error", MB_OK);
  653. }
  654. g_InfoTreeRoot.RemoveChildren();
  655. KillProgressDialog();
  656. return S_OK;
  657. }