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.

2811 lines
84 KiB

  1. //=============================================================================
  2. // MSInfo.cpp : Implementation of CMSInfo
  3. //
  4. // Contains implementation for some of the functions in the CMSInfo class
  5. // (the ones which aren't inline).
  6. //=============================================================================
  7. #include "stdafx.h"
  8. #include "Msinfo32.h"
  9. #include "MSInfo.h"
  10. #include "cabfunc.h"
  11. #include "msictrl.h"
  12. #include "MSInfo4Category.h"
  13. #include "remotedialog.h"
  14. #include "filestuff.h"
  15. #include <afxole.h>
  16. //a-kjaw
  17. #include "dataset.h"
  18. //a-kjaw
  19. WNDPROC CMSInfo::m_wndprocParent = NULL;
  20. CMSInfo * CMSInfo::m_pControl = NULL;
  21. extern CMSInfoHistoryCategory catHistorySystemSummary;
  22. extern CMSInfoHistoryCategory catHistoryResources;
  23. extern CMSInfoHistoryCategory catHistoryComponents;
  24. extern CMSInfoHistoryCategory catHistorySWEnv;
  25. //=========================================================================
  26. // Here's a very simple class to show a message when the data is
  27. // being refreshed.
  28. //=========================================================================
  29. class CWaitForRefreshDialog : public CDialogImpl<CWaitForRefreshDialog>
  30. {
  31. public:
  32. enum { IDD = IDD_WAITFORREFRESHDIALOG };
  33. //-------------------------------------------------------------------------
  34. // Refresh the specified category using the specified source.
  35. //-------------------------------------------------------------------------
  36. int DoRefresh(CLiveDataSource * pSource, CMSInfoLiveCategory * pLiveCategory)
  37. {
  38. m_pSource = pSource;
  39. m_pLiveCategory = pLiveCategory;
  40. m_nCategories = pLiveCategory->GetCategoryCount();
  41. if (m_nCategories == 0) m_nCategories = 1; // should never happen
  42. return (int)DoModal();
  43. };
  44. //-------------------------------------------------------------------------
  45. // When the dialog initializes, the source and category pointers should
  46. // have already been set. Start the refresh and create a timer to control
  47. // the update of information on the dialog. The timer is set to 500ms.
  48. //-------------------------------------------------------------------------
  49. LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  50. {
  51. if (m_pSource && m_pSource->m_pThread && m_pLiveCategory)
  52. m_pSource->m_pThread->StartRefresh(m_pLiveCategory, TRUE);
  53. m_iTimer = (UINT)SetTimer(1, 500);
  54. return 0;
  55. }
  56. //-------------------------------------------------------------------------
  57. // Every time the timer fires, check to see if the refresh is done. If
  58. // it is, close the dialog. Otherwise, update the progress bar and
  59. // refreshing category string.
  60. //-------------------------------------------------------------------------
  61. LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  62. {
  63. if (m_pSource == NULL)
  64. return 0;
  65. if (!m_pSource->m_pThread->IsRefreshing())
  66. {
  67. KillTimer(m_iTimer);
  68. EndDialog(0);
  69. return 0;
  70. }
  71. CString strCurrent;
  72. LONG nCount;
  73. m_pSource->m_pThread->GetRefreshStatus(&nCount, &strCurrent);
  74. if (nCount > 0) nCount -= 1; // this number is incremented before the refresh is complete
  75. UpdateProgress((nCount * 100) / m_nCategories, strCurrent);
  76. return 0;
  77. }
  78. //-------------------------------------------------------------------------
  79. // Update the percentage complete and the refreshing category name.
  80. //-------------------------------------------------------------------------
  81. void UpdateProgress(int iPercent, const CString & strCurrent = _T(""))
  82. {
  83. HWND hwnd = GetDlgItem(IDC_REFRESHPROGRESS);
  84. if (hwnd != NULL)
  85. {
  86. if (iPercent < 0)
  87. iPercent = 0;
  88. if (iPercent > 100)
  89. iPercent = 100;
  90. ::SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
  91. ::SendMessage(hwnd, PBM_SETPOS, iPercent, 0);
  92. }
  93. if (!strCurrent.IsEmpty())
  94. {
  95. hwnd = GetDlgItem(IDC_REFRESHCAT);
  96. if (hwnd != NULL)
  97. ::SetWindowText(hwnd, strCurrent);
  98. }
  99. }
  100. private:
  101. CLiveDataSource * m_pSource;
  102. CMSInfoLiveCategory * m_pLiveCategory;
  103. int m_nCategories;
  104. UINT m_iTimer;
  105. BEGIN_MSG_MAP(CWaitForRefreshDialog)
  106. MESSAGE_HANDLER(WM_TIMER, OnTimer)
  107. MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  108. END_MSG_MAP()
  109. };
  110. UINT HistoryRefreshDlgThreadProc( LPVOID pParam )
  111. {
  112. CMSInfo* pInfo = (CMSInfo*) pParam;
  113. if (WAIT_OBJECT_0 != WaitForSingleObject(pInfo->m_hEvtHistoryComplete,60*60*10/*10 minutes*/))
  114. {
  115. ASSERT(0 && "Wait Abandoned or timed out");
  116. }
  117. pInfo->m_HistoryProgressDlg.EndDialog(MB_OK);//use if dlg was create with DoModal()
  118. return 0;
  119. }
  120. //=========================================================================
  121. // A function to check if a file is a version 4.x (compound document) file
  122. // (for bug 582973). It checks this by opening the file, opening the
  123. // "MSInfo" stream and checking the version number.
  124. //=========================================================================
  125. BOOL IsVersion4File(const CString & strFilename)
  126. {
  127. BOOL fReturn = FALSE;
  128. DWORD grfMode = STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE;
  129. CComBSTR bstrFileName(strFilename);
  130. CComPtr<IStorage> pStorage;
  131. if (SUCCEEDED(StgOpenStorage(bstrFileName, NULL, grfMode, NULL, 0, &pStorage)))
  132. {
  133. CComPtr<IStream> pStream;
  134. CComBSTR bstrMSIStream(_T("MSInfo"));
  135. if (SUCCEEDED(pStorage->OpenStream(bstrMSIStream, NULL, grfMode, 0, &pStream)))
  136. {
  137. const DWORD MSI_FILE_VER = 0x03000000;
  138. COleStreamFile * pOStream;
  139. DWORD dwVersion;
  140. ULONG ulCount;
  141. pOStream = new COleStreamFile(pStream);
  142. if (pOStream->Read((void *) &dwVersion, sizeof(DWORD)) == sizeof(DWORD))
  143. fReturn = (dwVersion == MSI_FILE_VER);
  144. delete pOStream;
  145. }
  146. }
  147. return fReturn;
  148. }
  149. //=========================================================================
  150. // Dispatch a command from the user (such as a menu bar selection).
  151. //=========================================================================
  152. BOOL CMSInfo::DispatchCommand(int iCommand)
  153. {
  154. BOOL fHandledCommand = TRUE;
  155. // Can't do any command while the find is in progress.
  156. if (m_fInFind)
  157. {
  158. CancelFind();
  159. SelectCategory(GetCurrentCategory());
  160. }
  161. // Before we execute a command, make sure that any refreshes currently
  162. // in progress are finished.
  163. CMSInfoCategory * pCategory = GetCurrentCategory();
  164. if (pCategory && pCategory->GetDataSourceType() == LIVE_DATA)
  165. {
  166. CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData;
  167. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  168. pLiveDataSource->WaitForRefresh();
  169. ::SetCursor(hc);
  170. }
  171. // Check to see if the selected command is a tool that we added to the
  172. // tools menu.
  173. CMSInfoTool * pTool;
  174. if (m_mapIDToTool.Lookup((WORD) iCommand, (void * &) pTool))
  175. {
  176. ASSERT(pTool);
  177. if (pTool)
  178. pTool->Execute();
  179. return TRUE;
  180. }
  181. switch (iCommand)
  182. {
  183. case ID_FILE_OPENNFO:
  184. if (m_fFindVisible)
  185. DispatchCommand(ID_EDIT_FIND);
  186. OpenNFO();
  187. break;
  188. case ID_FILE_SAVENFO:
  189. SaveNFO();
  190. break;
  191. case ID_FILE_CLOSE:
  192. if (m_fFindVisible)
  193. DispatchCommand(ID_EDIT_FIND);
  194. CloseFile();
  195. break;
  196. case ID_FILE_EXPORT:
  197. Export();
  198. break;
  199. case ID_FILE_PRINT:
  200. DoPrint();
  201. break;
  202. case ID_FILE_EXIT:
  203. if (NULL != m_hwndParent)
  204. ::PostMessage(m_hwndParent, WM_CLOSE, 0, 0);
  205. break;
  206. case ID_EDIT_COPY:
  207. EditCopy();
  208. break;
  209. case ID_EDIT_PASTE:
  210. if (GetFocus() == m_wndFindWhat.m_hWnd && m_wndFindWhat.IsWindowVisible() && m_wndFindWhat.IsWindowEnabled())
  211. {
  212. BOOL fHandled = FALSE;
  213. if (::OpenClipboard(m_hWnd))
  214. {
  215. if (::IsClipboardFormatAvailable(CF_UNICODETEXT))
  216. {
  217. HANDLE h = ::GetClipboardData(CF_UNICODETEXT);
  218. if (h != NULL)
  219. {
  220. LPWSTR szData = (LPWSTR)GlobalLock(h);
  221. if (szData != NULL)
  222. {
  223. // If the user tries to paste a tab character, replace it with spaces.
  224. CString strTemp(szData);
  225. if (strTemp.Find(_T('\t')) != -1)
  226. strTemp.Replace(_T('\t'), _T(' '));
  227. SETTEXTEX st;
  228. st.flags = ST_SELECTION;
  229. st.codepage = 1200; // Unicode
  230. m_wndFindWhat.SendMessage(EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(LPCTSTR)strTemp);
  231. fHandled = TRUE;
  232. GlobalUnlock(h);
  233. }
  234. }
  235. }
  236. ::CloseClipboard();
  237. }
  238. if (!fHandled)
  239. m_wndFindWhat.SendMessage(WM_PASTE);
  240. }
  241. break;
  242. case ID_EDIT_SELECTALL:
  243. EditSelectAll();
  244. break;
  245. case ID_EDIT_FIND:
  246. m_fFindVisible = !m_fFindVisible;
  247. m_fFindNext = FALSE;
  248. m_pcatFind = NULL;
  249. m_fCancelFind = FALSE;
  250. m_fInFind = FALSE;
  251. ShowFindControls();
  252. LayoutControl();
  253. SetMenuItems();
  254. UpdateFindControls();
  255. if (m_fFindVisible)
  256. GotoDlgCtrl(m_wndFindWhat.m_hWnd);
  257. break;
  258. case ID_VIEW_REFRESH:
  259. MSInfoRefresh();
  260. break;
  261. case ID_VIEW_BASIC:
  262. if (m_fAdvanced)
  263. {
  264. m_fAdvanced = FALSE;
  265. RefillListView(FALSE);
  266. SetMenuItems();
  267. }
  268. break;
  269. case ID_VIEW_ADVANCED:
  270. if (!m_fAdvanced)
  271. {
  272. m_fAdvanced = TRUE;
  273. RefillListView(FALSE);
  274. SetMenuItems();
  275. }
  276. break;
  277. case ID_VIEW_REMOTE_COMPUTER:
  278. ShowRemoteDialog();
  279. break;
  280. case ID_VIEW_CURRENT:
  281. case ID_VIEW_HISTORY:
  282. {
  283. int iShow = (iCommand == ID_VIEW_HISTORY) ? SW_SHOW : SW_HIDE;
  284. /* v-stlowe 2/27/2001:
  285. problem: if history was loaded from file after combo has been populated,
  286. combo doesn't get updated. So update each time we switch to history view
  287. if (iCommand == ID_VIEW_HISTORY && m_history.SendMessage(CB_GETCURSEL, 0, 0) == CB_ERR)
  288. */
  289. if (iCommand == ID_VIEW_HISTORY)
  290. FillHistoryCombo();
  291. //v-stlowe 3/04/2001
  292. //if (!this->m_pHistoryStream)
  293. //{
  294. if (this->m_pDCO && !((CLiveDataSource *)m_pLiveData)->GetXMLDoc() && ID_VIEW_HISTORY == iCommand)
  295. {
  296. VERIFY(m_pDCO && "NULL datacollection object");
  297. if (m_pDCO)
  298. {
  299. HRESULT hr;
  300. HWND hWnd = m_HistoryProgressDlg.GetDlgItem(IDC_PROGRESS1);
  301. if(::IsWindow(hWnd))
  302. {
  303. ::SendMessage(hWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
  304. ::SendMessage(hWnd,PBM_SETPOS,0,0);
  305. ::SendMessage(hWnd, PBM_DELTAPOS, 0, 0L);
  306. }
  307. m_pDCO->ExecuteAsync();
  308. //m_HistoryProgressDlg.Create(m_hWnd);
  309. ResetEvent(m_hEvtHistoryComplete);
  310. AfxBeginThread((AFX_THREADPROC) HistoryRefreshDlgThreadProc,this);
  311. m_HistoryProgressDlg.DoModal(m_hWnd);
  312. }
  313. }
  314. else
  315. {
  316. }
  317. //end v-stlowe 12/17/00
  318. m_history.ShowWindow(iShow);
  319. m_historylabel.ShowWindow(iShow);
  320. LayoutControl();
  321. HTREEITEM htiToSelect = NULL;
  322. if (iCommand == ID_VIEW_HISTORY)
  323. {
  324. m_pLastCurrentCategory = GetCurrentCategory();
  325. int iIndex = (int)m_history.SendMessage(CB_GETCURSEL, 0, 0);
  326. if (iIndex == CB_ERR)
  327. {
  328. iIndex = 0;
  329. m_history.SendMessage(CB_SETCURSEL, (WPARAM)iIndex, 0);
  330. }
  331. ChangeHistoryView(iIndex);
  332. // Select the appropriate history category based on the current info category.
  333. CMSInfoHistoryCategory * pHistoryCat = NULL;
  334. CString strName;
  335. m_pLastCurrentCategory->GetNames(NULL, &strName);
  336. if (!strName.IsEmpty())
  337. {
  338. // This is a little kludgy:
  339. //todo: append file name if XML stream was opened from a file
  340. if (strName.Left(13) == CString(_T("SystemSummary")))
  341. pHistoryCat = &catHistorySystemSummary;
  342. else if (strName.Left(9) == CString(_T("Resources")))
  343. pHistoryCat = &catHistoryResources;
  344. else if (strName.Left(10) == CString(_T("Components")))
  345. pHistoryCat = &catHistoryComponents;
  346. else if (strName.Left(5) == CString(_T("SWEnv")))
  347. pHistoryCat = &catHistorySWEnv;
  348. }
  349. if (pHistoryCat)
  350. htiToSelect = pHistoryCat->GetHTREEITEM();
  351. }
  352. else
  353. {
  354. ChangeHistoryView(-1);
  355. // Changing to always select the system summary category when
  356. // switching back from history view.
  357. //
  358. // if (m_pLastCurrentCategory)
  359. // htiToSelect = m_pLastCurrentCategory->GetHTREEITEM();
  360. htiToSelect = TreeView_GetRoot(m_tree.m_hWnd);
  361. }
  362. if (htiToSelect != NULL)
  363. {
  364. TreeView_EnsureVisible(m_tree.m_hWnd, htiToSelect);
  365. TreeView_SelectItem(m_tree.m_hWnd, htiToSelect);
  366. }
  367. SetMenuItems();
  368. }
  369. break;
  370. case ID_TOOLS_PLACEHOLDER:
  371. break;
  372. case ID_HELP_ABOUT:
  373. {
  374. CSimpleDialog<IDD_ABOUTBOX> dlg;
  375. dlg.DoModal();
  376. }
  377. break;
  378. case ID_HELP_CONTENTS:
  379. //::HtmlHelp(m_hWnd, _T("msinfo32.chm"), HH_DISPLAY_TOPIC, 0);
  380. ShowHSCHelp(_T("msinfo_overview.htm"));
  381. break;
  382. case ID_HELP_TOPIC:
  383. ShowCategoryHelp(GetCurrentCategory());
  384. break;
  385. default:
  386. fHandledCommand = FALSE;
  387. break;
  388. }
  389. return fHandledCommand;
  390. }
  391. //=========================================================================
  392. // Called to allow the user to remote to a different computer.
  393. //=========================================================================
  394. void CMSInfo::ShowRemoteDialog()
  395. {
  396. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  397. CRemoteDialog dlg;
  398. dlg.SetRemoteDialogValues(m_hWnd, !m_strMachine.IsEmpty(), m_strMachine);
  399. if (dlg.DoModal() == IDOK)
  400. {
  401. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  402. CString strMachine;
  403. BOOL fRemote;
  404. dlg.GetRemoteDialogValues(&fRemote, &strMachine);
  405. if (!fRemote)
  406. strMachine.Empty();
  407. if (strMachine.CompareNoCase(m_strMachine) != 0)
  408. DoRemote(strMachine);
  409. ::SetCursor(hc);
  410. }
  411. }
  412. void CMSInfo::DoRemote(LPCTSTR szMachine)
  413. {
  414. CString strMachine(szMachine);
  415. // The user has changed the machine name. We need to recreate the
  416. // current data source object with the new machine name. Also, make
  417. // sure we aren't showing history data.
  418. if (m_history.IsWindowVisible())
  419. DispatchCommand(ID_VIEW_CURRENT);
  420. CLiveDataSource * pLiveData = new CLiveDataSource;
  421. if (pLiveData)
  422. {
  423. HRESULT hr = pLiveData->Create(strMachine, m_hWnd, m_strCategories);
  424. if (FAILED(hr))
  425. {
  426. // bad news, report an error
  427. delete pLiveData;
  428. }
  429. else
  430. {
  431. // Check to see if the pLiveData works. If it doesn't (for example,
  432. // if it's to a non-existent machine), don't change the data source.
  433. HRESULT hr = pLiveData->ValidDataSource();
  434. if (SUCCEEDED(hr))
  435. {
  436. pLiveData->m_pHistoryStream = ((CLiveDataSource *)m_pLiveData)->m_pHistoryStream;
  437. pLiveData->m_pXMLDoc = ((CLiveDataSource *)m_pLiveData)->m_pXMLDoc;
  438. if (m_pLiveData)
  439. delete m_pLiveData;
  440. m_pLiveData = pLiveData;
  441. m_strMachine = strMachine;
  442. SelectDataSource(m_pLiveData);
  443. }
  444. else
  445. {
  446. // Report the error for the bad connection.
  447. CString strMessage;
  448. if (strMachine.IsEmpty())
  449. strMessage.LoadString(IDS_REMOTEERRORLOCAL);
  450. else
  451. strMessage.Format(IDS_REMOTEERRORREMOTE, strMachine);
  452. MSInfoMessageBox(strMessage);
  453. delete pLiveData;
  454. }
  455. }
  456. }
  457. else
  458. {
  459. // bad news - no memory
  460. }
  461. }
  462. //=========================================================================
  463. // Functions for managing the displayed data.
  464. //=========================================================================
  465. void CMSInfo::SelectDataSource(CDataSource * pDataSource)
  466. {
  467. ASSERT(pDataSource);
  468. if (pDataSource == NULL || m_pCurrData == pDataSource)
  469. return;
  470. m_pCurrData = pDataSource;
  471. m_pCategory = NULL;
  472. // Clear the existing categories in the tree.
  473. TreeClearItems();
  474. // Load the contents of the tree from the data source.
  475. CMSInfoCategory * pRoot = m_pCurrData->GetRootCategory();
  476. if (pRoot)
  477. {
  478. BuildTree(TVI_ROOT, TVI_LAST, pRoot);
  479. TreeView_Expand(m_tree.m_hWnd, TreeView_GetRoot(m_tree.m_hWnd), TVE_EXPAND);
  480. TreeView_SelectItem(m_tree.m_hWnd, TreeView_GetRoot(m_tree.m_hWnd));
  481. }
  482. SetMenuItems();
  483. }
  484. //-------------------------------------------------------------------------
  485. // Select the specified category.
  486. //
  487. // TBD - better to check columns for being the same
  488. //-------------------------------------------------------------------------
  489. void CMSInfo::SelectCategory(CMSInfoCategory * pCategory, BOOL fRefreshDataOnly)
  490. {
  491. ASSERT(pCategory);
  492. if (pCategory == NULL) return;
  493. // If there's a currently selected category, save some information
  494. // for it (such as the widths of the columns that the user might
  495. // have changed).
  496. if (m_pCategory && !fRefreshDataOnly && m_pCategory->GetDataSourceType() != NFO_410)
  497. {
  498. int iWidth;
  499. ASSERT(m_iCategoryColNumberLen <= 64);
  500. for (int iListViewCol = 0; iListViewCol < m_iCategoryColNumberLen; iListViewCol++)
  501. {
  502. iWidth = ListView_GetColumnWidth(m_list.m_hWnd, iListViewCol);
  503. m_pCategory->SetColumnWidth(m_aiCategoryColNumber[iListViewCol], iWidth);
  504. }
  505. }
  506. ListClearItems();
  507. if (!fRefreshDataOnly && pCategory && pCategory->GetDataSourceType() != NFO_410)
  508. {
  509. ListClearColumns();
  510. m_iCategoryColNumberLen = 0;
  511. int iColCount;
  512. if (pCategory->GetCategoryDimensions(&iColCount, NULL))
  513. {
  514. CString strCaption;
  515. UINT uiWidth;
  516. int iListViewCol = 0;
  517. for (int iCategoryCol = 0; iCategoryCol < iColCount; iCategoryCol++)
  518. {
  519. if (!m_fAdvanced && pCategory->IsColumnAdvanced(iCategoryCol))
  520. continue;
  521. if (pCategory->GetColumnInfo(iCategoryCol, &strCaption, &uiWidth, NULL, NULL)) // TBD - faster to return reference to string
  522. {
  523. // Save what the actual column number (for the category) was.
  524. ASSERT(iListViewCol < 64);
  525. m_aiCategoryColNumber[iListViewCol] = iCategoryCol;
  526. ListInsertColumn(iListViewCol++, (int)uiWidth, strCaption);
  527. m_iCategoryColNumberLen = iListViewCol;
  528. }
  529. }
  530. }
  531. }
  532. // If the currently displayed category is from a 4.10 NFO file, and we're showing a
  533. // new category, then hide the existing category.
  534. if (m_pCategory && m_pCategory != pCategory && m_pCategory->GetDataSourceType() == NFO_410)
  535. ((CMSInfo4Category *) m_pCategory)->ShowControl(m_hWnd, this->GetOCXRect(), FALSE);
  536. // Save the currently displayed category.
  537. m_pCategory = pCategory;
  538. // If this is live data and has never been refreshed, refresh and return.
  539. // Refresh will send a message causing this function to be executed again.
  540. if (pCategory->GetDataSourceType() == LIVE_DATA)
  541. {
  542. CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory;
  543. if (!pLiveCategory->EverBeenRefreshed())
  544. {
  545. SetMessage((m_history.IsWindowVisible()) ? IDS_REFRESHHISTORYMESSAGE : IDS_REFRESHMESSAGE, 0, TRUE);
  546. CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData;
  547. if (pLiveDataSource->InRefresh())
  548. {
  549. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  550. pLiveCategory->Refresh((CLiveDataSource *) m_pCurrData, FALSE);
  551. ::SetCursor(hc);
  552. }
  553. else
  554. pLiveCategory->Refresh((CLiveDataSource *) m_pCurrData, FALSE);
  555. return;
  556. }
  557. }
  558. else if (pCategory->GetDataSourceType() == NFO_410)
  559. {
  560. this->m_list.ShowWindow(SW_HIDE);
  561. CMSInfo4Category * p4Cat = (CMSInfo4Category *) pCategory;
  562. if (!p4Cat->IsDisplayableCategory())
  563. SetMessage(IDS_SELECTCATEGORY, 0, TRUE);
  564. else if (FAILED(p4Cat->ShowControl(m_hWnd,this->GetOCXRect())))
  565. SetMessage(IDS_NOOCX, IDS_NOOCXDETAIL, TRUE);
  566. return;
  567. }
  568. else if (pCategory->GetDataSourceType() == XML_SNAPSHOT)
  569. {
  570. ((CXMLSnapshotCategory*)pCategory)->Refresh((CXMLDataSource*) m_pCurrData, FALSE);
  571. CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory;
  572. // Any category that has children (besides the root category) doesn't display
  573. // information. So put up a message to that effect.
  574. if (pLiveCategory->GetFirstChild() != NULL && pLiveCategory->GetParent() != NULL)
  575. {
  576. SetMessage(IDS_SELECTCATEGORY, 0, TRUE);
  577. return;
  578. }
  579. else if (!pLiveCategory->EverBeenRefreshed())
  580. {
  581. SetMessage((m_history.IsWindowVisible()) ? IDS_REFRESHHISTORYMESSAGE : IDS_REFRESHMESSAGE, 0, TRUE);
  582. return;
  583. }
  584. }
  585. // Set the columns and fill the rows with the data for this category.
  586. // Note, if this is live data we need to lock it (so we don't have
  587. // a threading problem with the refresh).
  588. CLiveDataSource * pLiveDataSource = NULL;
  589. if (pCategory->GetDataSourceType() == LIVE_DATA)
  590. pLiveDataSource = (CLiveDataSource *) m_pCurrData;
  591. if (pLiveDataSource)
  592. pLiveDataSource->LockData();
  593. if (SUCCEEDED(pCategory->GetHRESULT()))
  594. {
  595. int iColCount, iRowCount;
  596. if (pCategory->GetCategoryDimensions(&iColCount, &iRowCount))
  597. {
  598. CString * pstrData , strCaption , cstring;
  599. DWORD dwData;
  600. int iListViewCol, iListViewRow = 0;
  601. for (int iCategoryRow = 0; iCategoryRow < iRowCount; iCategoryRow++)
  602. {
  603. if (!m_fAdvanced && pCategory->IsRowAdvanced(iCategoryRow))
  604. continue;
  605. iListViewCol = 0;
  606. for (int iCategoryCol = 0; iCategoryCol < iColCount; iCategoryCol++)
  607. {
  608. if (!m_fAdvanced && pCategory->IsColumnAdvanced(iCategoryCol))
  609. continue;
  610. if (pCategory->GetData(iCategoryRow, iCategoryCol, &pstrData, &dwData))
  611. {
  612. //a-kjaw
  613. if(pstrData->IsEmpty())
  614. {
  615. pCategory->GetColumnInfo(iCategoryCol, &strCaption, NULL , NULL, NULL);
  616. cstring.LoadString(IDS_SERVERNAME);
  617. if( strCaption == cstring )
  618. pstrData->LoadString(IDS_LOCALSERVER);
  619. }
  620. //a-kjaw
  621. ListInsertItem(iListViewRow, iListViewCol++, *pstrData, iCategoryRow);
  622. }
  623. }
  624. iListViewRow += 1;
  625. }
  626. }
  627. // Return the sorting to how it was last set.
  628. if (pCategory->m_iSortColumn != -1)
  629. ListView_SortItems(m_list.m_hWnd, (PFNLVCOMPARE) ListSortFunc, (LPARAM) pCategory);
  630. if (iColCount == 0 || (iRowCount == 0 && pCategory->GetFirstChild() != NULL))
  631. SetMessage(IDS_SELECTCATEGORY, 0, TRUE);
  632. else
  633. SetMessage(0);
  634. }
  635. else
  636. {
  637. // The HRESULT for this category indicates some sort of failure. We should display
  638. // an error message instead of the list view.
  639. CString strTitle, strMessage;
  640. pCategory->GetErrorText(&strTitle, &strMessage);
  641. SetMessage(strTitle, strMessage, TRUE);
  642. }
  643. if (pLiveDataSource)
  644. pLiveDataSource->UnlockData();
  645. SetMenuItems();
  646. }
  647. //-------------------------------------------------------------------------
  648. // Get the currently selected category.
  649. //-------------------------------------------------------------------------
  650. CMSInfoCategory * CMSInfo::GetCurrentCategory()
  651. {
  652. HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd);
  653. if (hti)
  654. {
  655. TVITEM tvi;
  656. tvi.mask = TVIF_PARAM;
  657. tvi.hItem = hti;
  658. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  659. {
  660. ASSERT(tvi.lParam);
  661. ASSERT(tvi.lParam == (LPARAM)m_pCategory);
  662. return (CMSInfoCategory *) tvi.lParam;
  663. }
  664. }
  665. return NULL;
  666. }
  667. //-------------------------------------------------------------------------
  668. // Refresh the displayed data.
  669. //-------------------------------------------------------------------------
  670. void CMSInfo::MSInfoRefresh()
  671. {
  672. CMSInfoCategory * pCategory = GetCurrentCategory();
  673. if (pCategory && pCategory->GetDataSourceType() == LIVE_DATA)
  674. {
  675. CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *)pCategory;
  676. ListClearItems();
  677. SetMessage(IDS_REFRESHMESSAGE);
  678. pLiveCategory->Refresh((CLiveDataSource *) m_pCurrData, FALSE);
  679. }
  680. else if (pCategory && pCategory->GetDataSourceType() == NFO_410)
  681. {
  682. CMSInfo4Category* p4Category = (CMSInfo4Category*) pCategory;
  683. p4Category->Refresh();
  684. }
  685. }
  686. //-------------------------------------------------------------------------
  687. // Present the user with a dialog box to select a file to open.
  688. //-------------------------------------------------------------------------
  689. void CMSInfo::OpenNFO()
  690. {
  691. // Display the dialog box and let the user select a file.
  692. TCHAR szBuffer[MAX_PATH] = _T("");
  693. TCHAR szFilter[MAX_PATH];
  694. TCHAR szDefaultExtension[4];
  695. ::LoadString(_Module.GetResourceInstance(), IDS_OPENFILTER, szFilter, MAX_PATH);
  696. ::LoadString(_Module.GetResourceInstance(), IDS_DEFAULTEXTENSION, szDefaultExtension, 4);
  697. for (int i = 0; szFilter[i]; i++)
  698. if (szFilter[i] == _T('|'))
  699. szFilter[i] = _T('\0');
  700. OPENFILENAME ofn;
  701. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  702. ofn.lStructSize = sizeof(OPENFILENAME);
  703. ofn.hwndOwner = m_hWnd;
  704. ofn.lpstrFilter = szFilter;
  705. ofn.nFilterIndex = 1;
  706. ofn.lpstrCustomFilter = NULL;
  707. ofn.lpstrFile = szBuffer;
  708. ofn.nMaxFile = MAX_PATH;
  709. ofn.lpstrFileTitle = NULL; // maybe use later?
  710. ofn.nMaxFileTitle = 0;
  711. ofn.lpstrInitialDir = NULL;
  712. ofn.lpstrTitle = NULL;
  713. ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  714. ofn.lpstrDefExt = szDefaultExtension;
  715. if (!::GetOpenFileName(&ofn))
  716. return; // user cancelled
  717. OpenMSInfoFile(ofn.lpstrFile, ofn.nFileExtension);
  718. }
  719. //-------------------------------------------------------------------------
  720. // SaveNFO allows the user to select a filename, and saves the current
  721. // data to an NFO file.
  722. //-------------------------------------------------------------------------
  723. void CMSInfo::SaveNFO()
  724. {
  725. // Present the user with a dialog box to select a name for saving.
  726. TCHAR szBuffer[MAX_PATH] = _T("");
  727. TCHAR szFilter[MAX_PATH];
  728. TCHAR szDefaultExtension[4];
  729. //v-stlowe 3/19/2001 if (m_fHistoryAvailable && m_strMachine.IsEmpty())
  730. if (m_fHistorySaveAvailable && m_strMachine.IsEmpty())
  731. ::LoadString(_Module.GetResourceInstance(), IDS_SAVEBOTHFILTER, szFilter, MAX_PATH);
  732. else
  733. ::LoadString(_Module.GetResourceInstance(), IDS_SAVENFOFILTER, szFilter, MAX_PATH);
  734. ::LoadString(_Module.GetResourceInstance(), IDS_DEFAULTEXTENSION, szDefaultExtension, 4);
  735. for (int i = 0; szFilter[i]; i++)
  736. if (szFilter[i] == _T('|'))
  737. szFilter[i] = _T('\0');
  738. OPENFILENAME ofn;
  739. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  740. ofn.lStructSize = sizeof(OPENFILENAME);
  741. ofn.hwndOwner = m_hWnd;
  742. ofn.lpstrFilter = szFilter;
  743. ofn.nFilterIndex = 0;
  744. ofn.lpstrCustomFilter = NULL;
  745. ofn.lpstrFile = szBuffer;
  746. ofn.nMaxFile = MAX_PATH;
  747. ofn.lpstrFileTitle = NULL; // maybe use later?
  748. ofn.nMaxFileTitle = 0;
  749. ofn.lpstrInitialDir = NULL;
  750. ofn.lpstrTitle = NULL;
  751. ofn.Flags = OFN_OVERWRITEPROMPT;
  752. ofn.lpstrDefExt = szDefaultExtension;
  753. if (!::GetSaveFileName(&ofn))
  754. return; // user cancelled
  755. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  756. CString strFileName(ofn.lpstrFile);
  757. if (strFileName.Right(4).CompareNoCase(_T(".xml")) == 0)
  758. SaveXML(strFileName);
  759. else
  760. SaveMSInfoFile(strFileName, ofn.nFilterIndex);
  761. ::SetCursor(hc);
  762. }
  763. //-------------------------------------------------------------------------
  764. // Actually saves the current information to an NFO file.
  765. //-------------------------------------------------------------------------
  766. void CMSInfo::SaveMSInfoFile(LPCTSTR szFilename, DWORD dwFilterIndex)
  767. {
  768. ASSERT(m_pCurrData);
  769. if (m_history.IsWindowVisible())
  770. DispatchCommand(ID_VIEW_CURRENT);
  771. if (m_pCurrData)
  772. {
  773. CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory();
  774. if (pCategory)
  775. {
  776. HANDLE hFile = ::CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  777. if (hFile != INVALID_HANDLE_VALUE)
  778. {
  779. if (pCategory->GetDataSourceType() == LIVE_DATA)
  780. {
  781. CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory;
  782. if (m_fNoUI)
  783. pLiveCategory->RefreshSynchronous((CLiveDataSource *) m_pCurrData, TRUE);
  784. else
  785. RefreshData((CLiveDataSource *)m_pCurrData, pLiveCategory);
  786. }
  787. else if (pCategory->GetDataSourceType() == XML_SNAPSHOT)
  788. ((CXMLSnapshotCategory *)pCategory)->Refresh((CXMLDataSource *)m_pCurrData, TRUE);
  789. //PENDING dependence on filter order. Always add new filters to the end.
  790. if (dwFilterIndex == 1)//NFO_700
  791. pCategory->SaveXML(hFile);
  792. else
  793. pCategory->SaveNFO(hFile, pCategory, TRUE);
  794. ::CloseHandle(hFile);
  795. }
  796. else
  797. {
  798. DWORD dwError = ::GetLastError();
  799. LPVOID lpMsgBuf;
  800. ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  801. FORMAT_MESSAGE_FROM_SYSTEM |
  802. FORMAT_MESSAGE_IGNORE_INSERTS,
  803. NULL,
  804. dwError,
  805. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  806. (LPTSTR) &lpMsgBuf,
  807. 0,
  808. NULL);
  809. // TBD Process any inserts in lpMsgBuf.
  810. CString strCaption;
  811. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  812. strCaption.LoadString(IDS_SYSTEMINFO);
  813. ::MessageBox(m_hWnd, (LPCTSTR) lpMsgBuf, strCaption, MB_ICONEXCLAMATION | MB_OK);
  814. ::LocalFree(lpMsgBuf);
  815. }
  816. }
  817. }
  818. }
  819. //-------------------------------------------------------------------------
  820. // Save an XML file containing the history information.
  821. //-------------------------------------------------------------------------
  822. void CMSInfo::SaveXML(const CString & strFileName)
  823. {
  824. if (m_pHistoryStream == NULL)
  825. {
  826. MSInfoMessageBox(IDS_XMLSAVEERR);
  827. return;
  828. }
  829. // get the stream status, so we can determine the size of the stream
  830. STATSTG streamStat;
  831. HRESULT hr = m_pHistoryStream->Stat(&streamStat,STATFLAG_NONAME );
  832. if (FAILED(hr))
  833. {
  834. ASSERT(0 && "couldn't get stream statistics");
  835. MSInfoMessageBox(IDS_XMLSAVEERR);
  836. return;
  837. }
  838. // allocate buffer of appropriate size
  839. BYTE* pBuffer = new BYTE[streamStat.cbSize.LowPart];
  840. ULONG ulRead;
  841. // seek to beginning of stream
  842. ULARGE_INTEGER uliSeekPtr;
  843. LARGE_INTEGER liSeekLoc;
  844. liSeekLoc.QuadPart = 0;
  845. hr = m_pHistoryStream->Seek(liSeekLoc,0,&uliSeekPtr);
  846. if (FAILED(hr))
  847. {
  848. MSInfoMessageBox(IDS_XMLSAVEERR);
  849. if (pBuffer)
  850. delete [] pBuffer;
  851. return;
  852. }
  853. hr = m_pHistoryStream->Read(pBuffer,streamStat.cbSize.LowPart,&ulRead);
  854. if (FAILED(hr) || !pBuffer)
  855. {
  856. MSInfoMessageBox(IDS_XMLSAVEERR);
  857. if (pBuffer)
  858. delete [] pBuffer;
  859. return;
  860. }
  861. if(ulRead != streamStat.cbSize.LowPart)
  862. {
  863. ASSERT(0 && "Not enough bytes read from stream");
  864. MSInfoMessageBox(IDS_XMLSAVEERR);
  865. if (pBuffer)
  866. delete [] pBuffer;
  867. return;
  868. }
  869. CFile file;
  870. try
  871. {
  872. file.Open(strFileName, CFile::modeCreate | CFile::modeWrite);
  873. file.Write(pBuffer,ulRead);
  874. }
  875. catch (CFileException * pException)
  876. {
  877. pException->ReportError();
  878. pException->Delete();
  879. }
  880. catch (...)
  881. {
  882. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  883. CString strCaption, strMessage;
  884. strCaption.LoadString(IDS_SYSTEMINFO);
  885. strMessage.LoadString(IDS_XMLSAVEERR);
  886. ::MessageBox(NULL,strMessage, strCaption,MB_OK);
  887. }
  888. delete [] pBuffer;
  889. }
  890. //-------------------------------------------------------------------------
  891. // Export allows the user to select a filename, and saves the current
  892. // data to a text or XML file.
  893. //-------------------------------------------------------------------------
  894. void CMSInfo::Export()
  895. {
  896. // Present the user with a dialog box to select a name for saving.
  897. TCHAR szBuffer[MAX_PATH] = _T("");
  898. TCHAR szFilter[MAX_PATH];
  899. TCHAR szTitle[MAX_PATH] = _T("");
  900. TCHAR szDefaultExtension[4];
  901. ::LoadString(_Module.GetResourceInstance(), IDS_EXPORTFILTER, szFilter, MAX_PATH); // TBD - add XML
  902. ::LoadString(_Module.GetResourceInstance(), IDS_DEFAULTEXPORTEXTENSION, szDefaultExtension, 4);
  903. ::LoadString(_Module.GetResourceInstance(), IDS_EXPORTDIALOGTITLE, szTitle, MAX_PATH);
  904. for (int i = 0; szFilter[i]; i++)
  905. if (szFilter[i] == _T('|'))
  906. szFilter[i] = _T('\0');
  907. OPENFILENAME ofn;
  908. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  909. ofn.lStructSize = sizeof(OPENFILENAME);
  910. ofn.hwndOwner = m_hWnd;
  911. ofn.lpstrFilter = szFilter;
  912. ofn.nFilterIndex = 0;
  913. ofn.lpstrCustomFilter = NULL;
  914. ofn.lpstrFile = szBuffer;
  915. ofn.nMaxFile = MAX_PATH;
  916. ofn.lpstrFileTitle = NULL; // maybe use later?
  917. ofn.nMaxFileTitle = 0;
  918. ofn.lpstrInitialDir = NULL;
  919. ofn.lpstrTitle = (szTitle[0] == _T('\0')) ? NULL : szTitle;
  920. ofn.Flags = OFN_OVERWRITEPROMPT;
  921. ofn.lpstrDefExt = szDefaultExtension;
  922. if (!::GetSaveFileName(&ofn))
  923. return; // user cancelled
  924. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  925. ExportFile(ofn.lpstrFile, ofn.nFileExtension);
  926. ::SetCursor(hc);
  927. }
  928. //-------------------------------------------------------------------------
  929. // Open the specified file (it might be XML, NFO, CAB, etc.). If the open
  930. // succeeds, we should show the contents of the file.
  931. //-------------------------------------------------------------------------
  932. HRESULT CMSInfo::OpenMSInfoFile(LPCTSTR szFilename, int nFileExtension)
  933. {
  934. if (m_pFileData != NULL && m_strFileName.Right(4).CompareNoCase(_T(".xml")) == 0)
  935. CloseFile();
  936. HRESULT hr = S_OK;
  937. CDataSource * pOldOpenFile = m_pFileData;
  938. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  939. /* v-stlowe 3/04/2001...we don't want to automatically switch from history
  940. in the event we're opening XML.
  941. if (m_history.IsWindowVisible())
  942. DispatchCommand(ID_VIEW_CURRENT);*/
  943. // Open the file.
  944. LPCTSTR szExtension = szFilename + nFileExtension;
  945. if (_tcsicmp(szExtension, _T("NFO")) == 0)
  946. {
  947. // If this is a version 4 NFO, check to see if that's enabled. Bug 582973.
  948. if (IsVersion4File(szFilename))
  949. {
  950. HKEY hkey;
  951. BOOL fDisabled = TRUE;
  952. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_READ, &hkey))
  953. {
  954. DWORD dwType = REG_DWORD, dwValue, dwSize = sizeof(DWORD);
  955. if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("AllowVersion4NFO"), NULL, &dwType, (LPBYTE)&dwValue, &dwSize))
  956. fDisabled = (dwValue == 0);
  957. RegCloseKey(hkey);
  958. }
  959. if (fDisabled)
  960. {
  961. MSInfoMessageBox(IDS_VER4NFODISABLED);
  962. return E_FAIL;
  963. }
  964. }
  965. // First, try opening it as a 4.x file.
  966. CNFO4DataSource* pMSI4Source = new CNFO4DataSource();
  967. hr = pMSI4Source->Create(szFilename);
  968. if (SUCCEEDED(hr))
  969. {
  970. m_pFileData = pMSI4Source;
  971. }
  972. else
  973. {
  974. delete pMSI4Source;
  975. if (STG_E_ACCESSDENIED == hr || STG_E_SHAREVIOLATION == hr || STG_E_LOCKVIOLATION == hr)
  976. {
  977. MSInfoMessageBox(IDS_OLDNFOSHARINGVIOLATION);
  978. return E_FAIL;
  979. }
  980. }
  981. // If that failed, then try opening it as a 5.0/6.0 file.
  982. if (FAILED(hr))
  983. {
  984. HANDLE h = ::CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  985. if (INVALID_HANDLE_VALUE == h)
  986. {
  987. MSInfoMessageBox(IDS_BADNFOFILE);
  988. return E_FAIL;
  989. }
  990. CNFO6DataSource * p60Source = new CNFO6DataSource;
  991. if (p60Source)
  992. {
  993. hr = p60Source->Create(h, szFilename);
  994. if (FAILED(hr))
  995. {
  996. delete p60Source;
  997. //MSInfoMessageBox(IDS_BADNFOFILE);
  998. }
  999. else
  1000. m_pFileData = p60Source;
  1001. }
  1002. else
  1003. hr = E_FAIL; // TBD no memory
  1004. ::CloseHandle(h);
  1005. }
  1006. //Try 7.0
  1007. if (FAILED(hr))
  1008. {
  1009. CNFO7DataSource * p70Source = new CNFO7DataSource;
  1010. if (!p70Source)
  1011. hr = E_FAIL;
  1012. else
  1013. {
  1014. hr = p70Source->Create(szFilename);//blocks while parsing
  1015. if (FAILED(hr))
  1016. {
  1017. delete p70Source;
  1018. MSInfoMessageBox(IDS_BADNFOFILE);
  1019. }
  1020. else
  1021. m_pFileData = p70Source;
  1022. }
  1023. }
  1024. }
  1025. else if (_tcsicmp(szExtension, _T("CAB")) == 0)
  1026. {
  1027. CString strDest;
  1028. GetCABExplodeDir(strDest, TRUE, _T(""));
  1029. if (!strDest.IsEmpty())
  1030. {
  1031. if (OpenCABFile(szFilename, strDest))
  1032. {
  1033. LoadGlobalToolsetWithOpenCAB(m_mapIDToTool, strDest);
  1034. UpdateToolsMenu();
  1035. CString strFileInCAB;
  1036. //first, look for xml files (the incident file specified in the registry, and (possibly) dataspec.xml
  1037. //Get default incident file name from registry (create it if it's not there)
  1038. CString strIncidentFileName;
  1039. HKEY hkey;
  1040. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_ALL_ACCESS, &hkey))
  1041. {
  1042. TCHAR szBuffer[MAX_PATH];
  1043. DWORD dwType, dwSize = MAX_PATH * sizeof(TCHAR);
  1044. long lErr = RegQueryValueEx(hkey, _T("incidentfilename"), NULL, &dwType, (LPBYTE)szBuffer, &dwSize);
  1045. if (ERROR_SUCCESS == lErr)
  1046. {
  1047. if (dwType == REG_SZ)
  1048. {
  1049. strIncidentFileName = szBuffer;
  1050. }
  1051. else
  1052. {
  1053. ASSERT(0 && "invalid incidentfilename reg key");
  1054. return E_FAIL;
  1055. }
  1056. }
  1057. //check lErr to make sure it's appropriate error for value not existing
  1058. else if (2 == lErr)
  1059. {
  1060. //create registry key.
  1061. CString strDefaultValue = _T("Incident.xml");
  1062. lErr = RegSetValueEx(hkey,_T("incidentfilename"),NULL,REG_SZ,(BYTE*) strDefaultValue.GetBuffer(strDefaultValue.GetLength()),strDefaultValue.GetLength() * sizeof(TCHAR));
  1063. strIncidentFileName = strDefaultValue;
  1064. }
  1065. }
  1066. if (IsIncidentXMLFilePresent(strDest,strIncidentFileName))
  1067. {
  1068. strFileInCAB = strDest + "\\";
  1069. strFileInCAB += strIncidentFileName;
  1070. OpenMSInfoFile(strFileInCAB,strFileInCAB.Find(_T(".xml")) +1);
  1071. return S_OK;
  1072. }
  1073. //if there are no xml incident files
  1074. FindFileToOpen(strDest, strFileInCAB);
  1075. if (!strFileInCAB.IsEmpty())
  1076. {
  1077. int iExtension = strFileInCAB.GetLength() - 1;
  1078. while (iExtension && strFileInCAB[iExtension] != _T('.'))
  1079. iExtension--;
  1080. if (iExtension)
  1081. return OpenMSInfoFile(strFileInCAB, iExtension + 1 /* skip the dot */);
  1082. else
  1083. {
  1084. ASSERT(0 && "couldn't find dot in file name");
  1085. }
  1086. }
  1087. }
  1088. }
  1089. else
  1090. {
  1091. // TBD - do something about the error.
  1092. ASSERT(0 && "could get not CAB destination directory");
  1093. }
  1094. MSInfoMessageBox(IDS_BADCABFILE);
  1095. return E_FAIL;
  1096. }
  1097. else if (_tcsicmp(szExtension, _T("XML")) == 0)
  1098. {
  1099. /* v-stlowe 3/04/2001
  1100. CXMLDataSource* pSSDataSource = new CXMLDataSource();
  1101. hr = pSSDataSource->Create(szFilename,(CMSInfoLiveCategory *) this->m_pLiveData->GetRootCategory(),m_hWnd);
  1102. CXMLSnapshotCategory* pRootXML = (CXMLSnapshotCategory*) pSSDataSource->GetRootCategory();
  1103. pRootXML->AppendFilenameToCaption(szFilename);
  1104. if (SUCCEEDED(hr))
  1105. {
  1106. m_pFileData = pSSDataSource;
  1107. }
  1108. else
  1109. {
  1110. delete pSSDataSource;
  1111. }*/
  1112. try
  1113. {
  1114. hr = ((CLiveDataSource *)m_pLiveData)->LoadXMLDoc(szFilename);
  1115. m_pFileData = m_pLiveData;
  1116. this->m_strFileName = szFilename;
  1117. //trigger refresh
  1118. CMSInfoCategory * pCategory = GetCurrentCategory();
  1119. if (pCategory)
  1120. ChangeHistoryView(((CMSInfoHistoryCategory*) pCategory)->m_iDeltaIndex);
  1121. if (FAILED(hr))//v-stlowe 3/9/2001 || !varBSuccess)
  1122. {
  1123. ASSERT(0 && "unable to load xml document");
  1124. return E_FAIL;
  1125. }
  1126. }
  1127. catch(...)
  1128. {
  1129. return E_FAIL;
  1130. }
  1131. DispatchCommand(ID_VIEW_HISTORY);
  1132. }
  1133. else
  1134. {
  1135. // Report that we can't open this kind of file.
  1136. MSInfoMessageBox(IDS_UNKNOWNFILETYPE);
  1137. hr = E_FAIL;
  1138. }
  1139. // It succeeded, so we should show the new data and update the menu
  1140. // for the new state.
  1141. if (SUCCEEDED(hr))
  1142. {
  1143. if (pOldOpenFile && pOldOpenFile != m_pFileData)
  1144. delete pOldOpenFile;
  1145. SelectDataSource(m_pFileData);
  1146. }
  1147. else
  1148. ; // report the error
  1149. return hr;
  1150. }
  1151. //-------------------------------------------------------------------------
  1152. // Export to the specified file. This will be either a TXT or an XML file.
  1153. //-------------------------------------------------------------------------
  1154. void CMSInfo::ExportFile(LPCTSTR szFilename, int nFileExtension)
  1155. {
  1156. ASSERT(m_pCurrData);
  1157. if (m_pCurrData)
  1158. {
  1159. // If there is a selected category, export that node only (bug 185305).
  1160. CMSInfoCategory * pCategory = (m_pCategory) ? m_pCategory : m_pCurrData->GetRootCategory();
  1161. if (pCategory)
  1162. {
  1163. if (pCategory->GetDataSourceType() == LIVE_DATA)
  1164. {
  1165. if (m_history.IsWindowVisible() == TRUE)
  1166. {
  1167. ((CMSInfoHistoryCategory*)pCategory)->Refresh((CLiveDataSource*)m_pCurrData,TRUE);
  1168. }
  1169. else
  1170. {
  1171. CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory;
  1172. if (m_fNoUI)
  1173. pLiveCategory->RefreshSynchronous((CLiveDataSource *) m_pCurrData, TRUE);
  1174. else
  1175. RefreshData((CLiveDataSource *)m_pCurrData, pLiveCategory);
  1176. }
  1177. }
  1178. else if (pCategory->GetDataSourceType() == NFO_410)
  1179. {
  1180. ((CMSInfo4Category *) pCategory)->RefreshAllForPrint(m_hWnd,this->GetOCXRect());
  1181. }
  1182. else if (pCategory->GetDataSourceType() == XML_SNAPSHOT)
  1183. {
  1184. ((CXMLSnapshotCategory *) pCategory)->Refresh((CXMLDataSource *)m_pCurrData,TRUE);
  1185. }
  1186. /*HANDLE hFile = ::CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1187. if (hFile != INVALID_HANDLE_VALUE)
  1188. {
  1189. pCategory->SaveAsText(hFile, TRUE);
  1190. ::CloseHandle(hFile);
  1191. }
  1192. else
  1193. {
  1194. // TBD - handle the error
  1195. }*/
  1196. //a-stephl: Fixing OSR4.1 bug #133823, not displaying message when saving to write-protected diskette
  1197. try
  1198. {
  1199. HANDLE hFile = ::CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1200. if (hFile != INVALID_HANDLE_VALUE)
  1201. {
  1202. DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
  1203. LPTSTR lpMachineName = new TCHAR[dwSize];
  1204. GetMachineName(lpMachineName, &dwSize);
  1205. /*a-kjaw To implement save as XML
  1206. if( _tcsicmp(szFilename + nFileExtension , _T("XML")) == 0)
  1207. {
  1208. pCategory->SaveAsXml(hFile, TRUE);
  1209. }
  1210. //a-kjaw */
  1211. // else
  1212. // {
  1213. pCategory->SaveAsText(hFile, TRUE, lpMachineName);
  1214. // }
  1215. delete [] lpMachineName;
  1216. ::CloseHandle(hFile);
  1217. }
  1218. else
  1219. {
  1220. DWORD dwError = ::GetLastError();
  1221. LPVOID lpMsgBuf;
  1222. ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1223. FORMAT_MESSAGE_FROM_SYSTEM |
  1224. FORMAT_MESSAGE_IGNORE_INSERTS,
  1225. NULL,
  1226. dwError,
  1227. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  1228. (LPTSTR) &lpMsgBuf,
  1229. 0,
  1230. NULL);
  1231. // TBD Process any inserts in lpMsgBuf.
  1232. CString strCaption;
  1233. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1234. strCaption.LoadString(IDS_SYSTEMINFO);
  1235. ::MessageBox(m_hWnd, (LPCTSTR) lpMsgBuf, strCaption, MB_ICONEXCLAMATION | MB_OK);
  1236. ::LocalFree(lpMsgBuf);
  1237. }
  1238. }
  1239. catch (CFileException * pException)
  1240. {
  1241. pException->ReportError();
  1242. pException->Delete();
  1243. }
  1244. catch (CException * pException)
  1245. {
  1246. pException->ReportError();
  1247. pException->Delete();
  1248. }
  1249. catch (...)
  1250. {
  1251. DWORD dwError = ::GetLastError();
  1252. LPVOID lpMsgBuf;
  1253. ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1254. FORMAT_MESSAGE_FROM_SYSTEM |
  1255. FORMAT_MESSAGE_IGNORE_INSERTS,
  1256. NULL,
  1257. dwError,
  1258. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  1259. (LPTSTR) &lpMsgBuf,
  1260. 0,
  1261. NULL);
  1262. // TBD Process any inserts in lpMsgBuf.
  1263. CString strCaption;
  1264. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1265. strCaption.LoadString(IDS_SYSTEMINFO);
  1266. ::MessageBox(m_hWnd, (LPCTSTR) lpMsgBuf, strCaption, MB_ICONEXCLAMATION | MB_OK);
  1267. ::LocalFree(lpMsgBuf);
  1268. }
  1269. }
  1270. //end a-stephl: Fixing OSR4.1 bug #133823, not displaying message when saving to write-protected diskette
  1271. }
  1272. }
  1273. //-------------------------------------------------------------------------
  1274. // Close the currently open file (if there is one). Displays the current
  1275. // system information.
  1276. //-------------------------------------------------------------------------
  1277. void CMSInfo::CloseFile()
  1278. {
  1279. ASSERT(m_pFileData);
  1280. //v-stlowe 3/12/2001
  1281. SelectDataSource(m_pLiveData);
  1282. if (m_strFileName.Right(4).CompareNoCase(_T(".xml")) == 0)
  1283. {
  1284. ((CLiveDataSource *)m_pLiveData)->RevertToLiveXML();
  1285. }
  1286. if (m_pFileData)
  1287. {
  1288. //v-stlowe: so we can use livedata as filedata when opening history xml
  1289. if (m_pFileData != this->m_pLiveData)
  1290. {
  1291. delete m_pFileData;
  1292. }
  1293. m_pFileData = NULL;
  1294. }
  1295. if (!m_history.IsWindowVisible())
  1296. {
  1297. DispatchCommand(ID_VIEW_CURRENT);
  1298. }
  1299. else
  1300. {
  1301. DispatchCommand(ID_VIEW_HISTORY);
  1302. }
  1303. SetMenuItems();
  1304. }
  1305. //-------------------------------------------------------------------------
  1306. // Enable or disable menu items based on the current state.
  1307. //-------------------------------------------------------------------------
  1308. void CMSInfo::SetMenuItems()
  1309. {
  1310. if (NULL == m_hmenu || NULL == m_hwndParent)
  1311. return;
  1312. // This struct will be used a bunch in this function to set menu item states.
  1313. MENUITEMINFO mii;
  1314. mii.cbSize = sizeof(MENUITEMINFO);
  1315. // The type of data being displayed will also be used frequently.
  1316. DataSourceType datatype = LIVE_DATA;
  1317. if (m_pCurrData)
  1318. {
  1319. CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory();
  1320. if (pCategory)
  1321. datatype = pCategory->GetDataSourceType();
  1322. }
  1323. // Enable or disable items in the File menu.
  1324. HMENU hmenuFile = ::GetSubMenu(m_hmenu, 0);
  1325. if (hmenuFile)
  1326. {
  1327. mii.fMask = MIIM_STATE;
  1328. mii.fState = (m_pFileData == m_pCurrData) ? MFS_ENABLED : MFS_GRAYED;
  1329. ::SetMenuItemInfo(hmenuFile, ID_FILE_CLOSE, FALSE, &mii);
  1330. mii.fState = MFS_ENABLED; // Was: (m_pFileData != m_pCurrData) ? MFS_ENABLED : MFS_GRAYED;
  1331. ::SetMenuItemInfo(hmenuFile, ID_FILE_OPENNFO, FALSE, &mii);
  1332. mii.fState = (datatype == LIVE_DATA || datatype == XML_SNAPSHOT) ? MFS_ENABLED : MFS_GRAYED;
  1333. ::SetMenuItemInfo(hmenuFile, ID_FILE_SAVENFO, FALSE, &mii);
  1334. //mii.fState = MFS_ENABLED;
  1335. mii.fState = (datatype != NFO_410) ? MFS_ENABLED : MFS_GRAYED;;
  1336. ::SetMenuItemInfo(hmenuFile, ID_FILE_EXPORT, FALSE, &mii);
  1337. mii.fState = MFS_ENABLED;
  1338. ::SetMenuItemInfo(hmenuFile, ID_FILE_PRINT, FALSE, &mii);
  1339. if (NULL == m_hwndParent)
  1340. {
  1341. // Remove the last two items (the exit command and the divider).
  1342. int nItems = ::GetMenuItemCount(hmenuFile);
  1343. if (ID_FILE_EXIT == ::GetMenuItemID(hmenuFile, nItems - 1))
  1344. {
  1345. ::RemoveMenu(hmenuFile, nItems - 1, MF_BYPOSITION);
  1346. ::RemoveMenu(hmenuFile, nItems - 2, MF_BYPOSITION);
  1347. }
  1348. }
  1349. }
  1350. // Enable or disable items in the Edit menu.
  1351. HMENU hmenuEdit = ::GetSubMenu(m_hmenu, 1);
  1352. if (hmenuEdit)
  1353. {
  1354. mii.fMask = MIIM_STATE;
  1355. if (datatype == NFO_410 || ListView_GetNextItem(m_list.m_hWnd, -1, LVNI_SELECTED) != -1)
  1356. mii.fState = MFS_ENABLED;
  1357. else
  1358. mii.fState = MFS_GRAYED;
  1359. // Disable copy if the list view is not visible.
  1360. if (!m_list.IsWindowVisible())
  1361. mii.fState = MFS_GRAYED;
  1362. // If the find control has focus, enable copy based on that control.
  1363. if (GetFocus() == m_wndFindWhat.m_hWnd && m_wndFindWhat.IsWindowVisible() && m_wndFindWhat.IsWindowEnabled())
  1364. mii.fState = MFS_ENABLED;
  1365. ::SetMenuItemInfo(hmenuEdit, ID_EDIT_COPY, FALSE, &mii);
  1366. mii.fState = (m_list.IsWindowVisible()) ? MFS_ENABLED : MFS_GRAYED;
  1367. ::SetMenuItemInfo(hmenuEdit, ID_EDIT_SELECTALL, FALSE, &mii);
  1368. mii.fState = (datatype != NFO_410) ? MFS_ENABLED : MFS_GRAYED;
  1369. mii.fState |= ((!m_fFindVisible) ? MFS_CHECKED : MFS_UNCHECKED);
  1370. ::SetMenuItemInfo(hmenuEdit, ID_EDIT_FIND, FALSE, &mii);
  1371. }
  1372. // Enable or disable items in the View menu.
  1373. HMENU hmenuView = ::GetSubMenu(m_hmenu, 2);
  1374. if (hmenuView)
  1375. {
  1376. mii.fMask = MIIM_STATE;
  1377. mii.fState = (datatype == LIVE_DATA && !m_history.IsWindowVisible()) ? MFS_ENABLED : MFS_GRAYED;
  1378. ::SetMenuItemInfo(hmenuView, ID_VIEW_REFRESH, FALSE, &mii);
  1379. mii.fState = MFS_ENABLED | ((!m_fAdvanced) ? MFS_CHECKED : MFS_UNCHECKED);
  1380. ::SetMenuItemInfo(hmenuView, ID_VIEW_BASIC, FALSE, &mii);
  1381. mii.fState = MFS_ENABLED | ((m_fAdvanced) ? MFS_CHECKED : MFS_UNCHECKED);
  1382. ::SetMenuItemInfo(hmenuView, ID_VIEW_ADVANCED, FALSE, &mii);
  1383. // Set the menu item for the current system view or snapshot, depending on whether
  1384. // or not there is an XML file open.
  1385. BOOL fEnableHistoryLive = FALSE;
  1386. if (datatype == LIVE_DATA && m_fHistoryAvailable && m_strMachine.IsEmpty())
  1387. fEnableHistoryLive = TRUE;
  1388. BOOL fEnableHistoryXML = FALSE;
  1389. if (m_pFileData)
  1390. {
  1391. CMSInfoCategory * pCategory = m_pFileData->GetRootCategory();
  1392. if (pCategory && (pCategory->GetDataSourceType() == XML_SNAPSHOT || pCategory == &catHistorySystemSummary))
  1393. fEnableHistoryXML = TRUE;
  1394. }
  1395. BOOL fShowingHistory = FALSE;
  1396. if (m_pCurrData)
  1397. {
  1398. CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory();
  1399. if (pCategory == &catHistorySystemSummary)
  1400. fShowingHistory = TRUE;
  1401. }
  1402. // Whether or not you can remote depends on if you are showing live data.
  1403. mii.fState = (datatype == LIVE_DATA && !fEnableHistoryXML) ? MFS_ENABLED : MFS_GRAYED;
  1404. ::SetMenuItemInfo(hmenuView, ID_VIEW_REMOTE_COMPUTER, FALSE, &mii);
  1405. // Enabling the menu items to switch between current (or snapshot) and history
  1406. // are based on whether history is available.
  1407. mii.fState = (fEnableHistoryLive || fEnableHistoryXML) ? MFS_ENABLED : MFS_GRAYED;
  1408. mii.fState |= (!m_history.IsWindowVisible()) ? MFS_CHECKED : MFS_UNCHECKED;
  1409. ::SetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &mii);
  1410. mii.fState = (fEnableHistoryLive || fEnableHistoryXML) ? MFS_ENABLED : MFS_GRAYED;
  1411. mii.fState |= (m_history.IsWindowVisible()) ? MFS_CHECKED : MFS_UNCHECKED;
  1412. ::SetMenuItemInfo(hmenuView, ID_VIEW_HISTORY, FALSE, &mii);
  1413. // Set the menu item text (for system snapshot/current system information) based on
  1414. // whether or not we have an XML file open.
  1415. UINT uiMenuCaption = IDS_VIEWCURRENTSYSTEMINFO;
  1416. if (m_pFileData)
  1417. {
  1418. CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory();
  1419. // v-stlowe 6/26/2001...pCategory && (pCategory->GetDataSourceType() == XML_SNAPSHOT no longer possible... if (pCategory && (pCategory->GetDataSourceType() == XML_SNAPSHOT || pCategory == &catHistorySystemSummary))
  1420. if (pCategory && (pCategory == &catHistorySystemSummary))
  1421. {
  1422. //v-stlowe 6/26/2001: we need to remove "snapshot" uiMenuCaption = IDS_VIEWSYSTEMSNAPSHOT;
  1423. uiMenuCaption = IDS_VIEWCURRENTSYSTEMINFO;
  1424. }
  1425. }
  1426. CString strMenuItem;
  1427. strMenuItem.LoadString(uiMenuCaption);
  1428. MENUITEMINFO miiName;
  1429. miiName.cbSize = sizeof(MENUITEMINFO);
  1430. miiName.fMask = MIIM_TYPE;
  1431. miiName.fType = MFT_STRING;
  1432. miiName.dwTypeData = (LPTSTR)(LPCTSTR)strMenuItem;
  1433. ::SetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &miiName);
  1434. }
  1435. // Enable or disable items in the Help menu.
  1436. HMENU hmenuHelp = ::GetSubMenu(m_hmenu, 4);
  1437. if (hmenuHelp)
  1438. {
  1439. mii.fMask = MIIM_STATE;
  1440. mii.fState = MFS_ENABLED;
  1441. ::SetMenuItemInfo(hmenuHelp, ID_HELP_ABOUT, FALSE, &mii);
  1442. }
  1443. }
  1444. //-------------------------------------------------------------------------
  1445. // Set a message in the right hand pane (hiding the list view).
  1446. //-------------------------------------------------------------------------
  1447. void CMSInfo::SetMessage(const CString & strTitle, const CString & strMessage, BOOL fRedraw)
  1448. {
  1449. m_strMessTitle = strTitle;
  1450. m_strMessText = strMessage;
  1451. if (strTitle.IsEmpty() && strMessage.IsEmpty())
  1452. {
  1453. m_list.ShowWindow(SW_SHOW);
  1454. return;
  1455. }
  1456. m_list.ShowWindow(SW_HIDE);
  1457. if (fRedraw)
  1458. {
  1459. RECT rectList;
  1460. m_list.GetWindowRect(&rectList);
  1461. ScreenToClient(&rectList);
  1462. InvalidateRect(&rectList, TRUE);
  1463. UpdateWindow();
  1464. }
  1465. }
  1466. void CMSInfo::SetMessage(UINT uiTitle, UINT uiMessage, BOOL fRedraw)
  1467. {
  1468. CString strTitle(_T(""));
  1469. CString strMessage(_T(""));
  1470. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1471. if (uiTitle)
  1472. strTitle.LoadString(uiTitle);
  1473. if (uiMessage)
  1474. strMessage.LoadString(uiMessage);
  1475. SetMessage(strTitle, strMessage, fRedraw);
  1476. }
  1477. //---------------------------------------------------------------------------
  1478. // This function is used to sort the list by a specified column.
  1479. //---------------------------------------------------------------------------
  1480. int CALLBACK ListSortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  1481. {
  1482. int iReturn = 0;
  1483. CMSInfoCategory * pCategory = (CMSInfoCategory *) lParamSort;
  1484. if (pCategory)
  1485. {
  1486. CString * pstrFirst;
  1487. CString * pstrSecond;
  1488. DWORD dwFirst = 0, dwSecond = 0;
  1489. pCategory->GetData((int)lParam1, pCategory->m_iSortColumn, &pstrFirst, &dwFirst);
  1490. pCategory->GetData((int)lParam2, pCategory->m_iSortColumn, &pstrSecond, &dwSecond);
  1491. //a-kjaw . To fix bug "Sort order style for an nfo file differs from that of live data."
  1492. if(pCategory->GetDataSourceType() == NFO_500/*|| pCategory->GetDataSourceType() == NFO_410 */) //BugBug
  1493. if(pstrFirst->Left(3) == _T("IRQ"))//Very weird fix. Need Loc?
  1494. {
  1495. LPTSTR strIrq = pstrFirst->GetBuffer(pstrFirst->GetLength() + 1);
  1496. dwFirst = _ttoi(strIrq + 4 );
  1497. pstrFirst->ReleaseBuffer();
  1498. strIrq = pstrSecond->GetBuffer(pstrSecond->GetLength() + 1);
  1499. dwSecond = _ttoi(strIrq + 4 );
  1500. pstrSecond->ReleaseBuffer();
  1501. }
  1502. //a-kjaw
  1503. if (pCategory->m_fSortLexical)
  1504. iReturn = pstrFirst->Collate(*pstrSecond);
  1505. else
  1506. iReturn = (dwFirst < dwSecond) ? -1 : (dwFirst == dwSecond) ? 0 : 1;
  1507. if (!pCategory->m_fSortAscending)
  1508. iReturn *= -1;
  1509. }
  1510. return iReturn;
  1511. }
  1512. //---------------------------------------------------------------------------
  1513. // Copy selected text from the list view into the clipboard.
  1514. //---------------------------------------------------------------------------
  1515. void CMSInfo::EditCopy()
  1516. {
  1517. if (GetFocus() == m_wndFindWhat.m_hWnd && m_wndFindWhat.IsWindowVisible() && m_wndFindWhat.IsWindowEnabled())
  1518. {
  1519. m_wndFindWhat.SendMessage(WM_COPY);
  1520. return;
  1521. }
  1522. CString strClipboardText(_T(""));
  1523. CMSInfoCategory * pCategory = GetCurrentCategory();
  1524. if (pCategory == NULL)
  1525. return;
  1526. if (pCategory && pCategory->GetDataSourceType() == NFO_410)
  1527. {
  1528. CMSInfo4Category * pCategory4 = (CMSInfo4Category *) pCategory;
  1529. CMSIControl * p4Ctrl = NULL;
  1530. if (CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pCategory4->m_strCLSID, p4Ctrl) && p4Ctrl)
  1531. p4Ctrl->MSInfoCopy();
  1532. return;
  1533. }
  1534. int iRowCount, iColCount;
  1535. pCategory->GetCategoryDimensions(&iColCount, &iRowCount);
  1536. // Build the string to put in the clipboard by finding all of the
  1537. // selected lines in the list view.
  1538. LVITEM lvi;
  1539. lvi.mask = LVIF_PARAM;
  1540. lvi.iSubItem = 0;
  1541. CString * pstrCell;
  1542. int iSelected = ListView_GetNextItem(m_list.m_hWnd, -1, LVNI_SELECTED);
  1543. while (iSelected != -1)
  1544. {
  1545. lvi.iItem = iSelected;
  1546. if (ListView_GetItem(m_list.m_hWnd, &lvi))
  1547. {
  1548. ASSERT(lvi.lParam < iRowCount);
  1549. if (lvi.lParam < iRowCount)
  1550. for (int iCol = 0; iCol < iColCount; iCol++)
  1551. if (SUCCEEDED(pCategory->GetData((int)lvi.lParam, iCol, &pstrCell, NULL)))
  1552. {
  1553. if (iCol)
  1554. strClipboardText += _T("\t");
  1555. strClipboardText += *pstrCell;
  1556. }
  1557. strClipboardText += _T("\r\n");
  1558. }
  1559. iSelected = ListView_GetNextItem(m_list.m_hWnd, iSelected, LVNI_SELECTED);
  1560. }
  1561. // Put the string in the clipboard.
  1562. if (OpenClipboard())
  1563. {
  1564. if (EmptyClipboard())
  1565. {
  1566. DWORD dwSize = (strClipboardText.GetLength() + 1) * sizeof(TCHAR);
  1567. HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dwSize);
  1568. if (hMem)
  1569. {
  1570. LPVOID lpvoid = ::GlobalLock(hMem);
  1571. if (lpvoid)
  1572. {
  1573. memcpy(lpvoid, (LPCTSTR) strClipboardText, dwSize);
  1574. ::GlobalUnlock(hMem);
  1575. SetClipboardData(CF_UNICODETEXT, hMem);
  1576. }
  1577. }
  1578. }
  1579. CloseClipboard();
  1580. }
  1581. }
  1582. //---------------------------------------------------------------------------
  1583. // Select all of the text in the list view.
  1584. //---------------------------------------------------------------------------
  1585. void CMSInfo::EditSelectAll()
  1586. {
  1587. CMSInfoCategory * pCategory = GetCurrentCategory();
  1588. if (pCategory && pCategory->GetDataSourceType() == NFO_410)
  1589. {
  1590. CMSInfo4Category * pCategory4 = (CMSInfo4Category *) pCategory;
  1591. CMSIControl * p4Ctrl = NULL;
  1592. if (CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pCategory4->m_strCLSID, p4Ctrl) && p4Ctrl)
  1593. p4Ctrl->MSInfoSelectAll();
  1594. }
  1595. else
  1596. {
  1597. int iCount = ListView_GetItemCount(m_list.m_hWnd);
  1598. for (int i = 0; i < iCount; i++)
  1599. ListView_SetItemState(m_list.m_hWnd, i, LVIS_SELECTED, LVIS_SELECTED);
  1600. }
  1601. }
  1602. void CMSInfo::GetMachineName(LPTSTR lpBuffer, LPDWORD lpnSize)
  1603. {
  1604. if (_tcslen(m_strMachine) == 0)
  1605. GetComputerName(lpBuffer, lpnSize);
  1606. else
  1607. _tcsncpy(lpBuffer, m_strMachine, *lpnSize);
  1608. }
  1609. //---------------------------------------------------------------------------
  1610. // Print the currently displayed information.
  1611. //---------------------------------------------------------------------------
  1612. void CMSInfo::DoPrint(BOOL fNoUI)
  1613. {
  1614. if (m_pCurrData == NULL)
  1615. return;
  1616. CMSInfoCategory * pRootCategory = m_pCurrData->GetRootCategory();
  1617. CMSInfoCategory * pSelectedCategory = GetCurrentCategory();
  1618. if (pRootCategory == NULL)
  1619. return;
  1620. DWORD dwFlags = PD_CURRENTPAGE | PD_NOPAGENUMS | PD_RETURNDC | PD_HIDEPRINTTOFILE | PD_USEDEVMODECOPIESANDCOLLATE;
  1621. if (pSelectedCategory == NULL)
  1622. dwFlags |= PD_NOCURRENTPAGE | PD_NOSELECTION | PD_ALLPAGES;
  1623. PRINTDLGEX pd;
  1624. ::ZeroMemory(&pd, sizeof(PRINTDLGEX));
  1625. pd.Flags = dwFlags;
  1626. pd.lStructSize = sizeof(PRINTDLGEX);
  1627. pd.hwndOwner = this->m_hWnd;
  1628. pd.ExclusionFlags = PD_EXCL_COPIESANDCOLLATE;
  1629. pd.nStartPage = START_PAGE_GENERAL;
  1630. if (fNoUI)
  1631. pd.Flags |= PD_RETURNDEFAULT;
  1632. if (SUCCEEDED(::PrintDlgEx(&pd)) && pd.dwResultAction == PD_RESULT_PRINT)
  1633. {
  1634. BOOL fPrintCategory = ((pd.Flags & PD_SELECTION) != 0) || ((pd.Flags & PD_CURRENTPAGE) != 0);
  1635. BOOL fPrintRecursive = ((pd.Flags & PD_CURRENTPAGE) == 0);
  1636. CMSInfoCategory * pPrintCategory = (fPrintCategory) ? pSelectedCategory : pRootCategory;
  1637. if (pPrintCategory)
  1638. {
  1639. if (pPrintCategory->GetDataSourceType() == LIVE_DATA)
  1640. {
  1641. RefreshData((CLiveDataSource *)m_pCurrData, (CMSInfoLiveCategory *)pPrintCategory);
  1642. }
  1643. else if (pPrintCategory->GetDataSourceType() == NFO_410)
  1644. {
  1645. ((CMSInfo4Category *) pPrintCategory)->RefreshAllForPrint(m_hWnd,this->GetOCXRect());
  1646. }
  1647. else if (pPrintCategory->GetDataSourceType() == XML_SNAPSHOT)
  1648. {
  1649. ((CXMLSnapshotCategory*) pPrintCategory)->Refresh((CXMLDataSource*) m_pCurrData, TRUE);
  1650. }
  1651. DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
  1652. LPTSTR lpMachineName = new TCHAR[dwSize];
  1653. GetMachineName(lpMachineName, &dwSize);
  1654. pPrintCategory->Print(pd.hDC, fPrintRecursive, -1, -1, lpMachineName); // -1's to include all pages
  1655. delete [] lpMachineName;
  1656. }
  1657. }
  1658. }
  1659. //---------------------------------------------------------------------------
  1660. // Update the tools menu to match the contents of the tools map.
  1661. //---------------------------------------------------------------------------
  1662. void CMSInfo::UpdateToolsMenu()
  1663. {
  1664. if (NULL == m_hmenu)
  1665. return;
  1666. HMENU hmenuTool = ::GetSubMenu(m_hmenu, 3);
  1667. if (hmenuTool)
  1668. {
  1669. // Remove all the current tools in the menu.
  1670. while (DeleteMenu(hmenuTool, 0, MF_BYPOSITION));
  1671. // Add the tools from the map. This will add the top level tools.
  1672. WORD wCommand;
  1673. CMSInfoTool * pTool;
  1674. for (POSITION pos = m_mapIDToTool.GetStartPosition(); pos != NULL; )
  1675. {
  1676. m_mapIDToTool.GetNextAssoc(pos, wCommand, (void * &) pTool);
  1677. if (pTool && pTool->GetParentID() == 0)
  1678. {
  1679. if (!pTool->HasSubitems())
  1680. InsertMenu(hmenuTool, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, (UINT) pTool->GetID(), pTool->GetName());
  1681. else
  1682. {
  1683. HMENU hmenuNew = CreatePopupMenu();
  1684. InsertMenu(hmenuTool, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT_PTR) hmenuNew, pTool->GetName());
  1685. pTool->SetHMENU(hmenuNew);
  1686. }
  1687. }
  1688. }
  1689. // Now add the second level tools (the subitems).
  1690. for (pos = m_mapIDToTool.GetStartPosition(); pos != NULL; )
  1691. {
  1692. m_mapIDToTool.GetNextAssoc(pos, wCommand, (void * &) pTool);
  1693. if (pTool && pTool->GetParentID())
  1694. {
  1695. CMSInfoTool * pParentTool;
  1696. if (m_mapIDToTool.Lookup((WORD) pTool->GetParentID(), (void * &) pParentTool))
  1697. InsertMenu(pParentTool->GetHMENU(), 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, (UINT) pTool->GetID(), pTool->GetName());
  1698. }
  1699. }
  1700. }
  1701. }
  1702. //---------------------------------------------------------------------------
  1703. // Gets the right pane rect in which to display a MSInfo 4.x OCX.
  1704. //---------------------------------------------------------------------------
  1705. CRect CMSInfo::GetOCXRect()
  1706. {
  1707. CRect rectList;
  1708. m_list.GetWindowRect(&rectList);
  1709. ScreenToClient(&rectList);
  1710. rectList.DeflateRect(1, 1, 2, 2);
  1711. return rectList;
  1712. }
  1713. //=============================================================================
  1714. // Find Functionality
  1715. //=============================================================================
  1716. //-------------------------------------------------------------------------
  1717. // CancelFind does what is says. It also waits until the find is done
  1718. // before returning.
  1719. //-------------------------------------------------------------------------
  1720. void CMSInfo::CancelFind()
  1721. {
  1722. if (m_fInFind)
  1723. {
  1724. m_fCancelFind = TRUE;
  1725. m_fFindNext = FALSE;
  1726. GotoDlgCtrl(m_wndStopFind.m_hWnd);
  1727. UpdateFindControls();
  1728. if (m_pcatFind && m_pcatFind->GetDataSourceType() == LIVE_DATA)
  1729. {
  1730. CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData;
  1731. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  1732. pLiveDataSource->WaitForRefresh();
  1733. ::SetCursor(hc);
  1734. }
  1735. }
  1736. }
  1737. //-------------------------------------------------------------------------
  1738. // When the user clicks on Stop Find, it will either cancel the current
  1739. // find operation (if there is one in progress) or hide the find controls
  1740. // (if there is no find in progress).
  1741. //-------------------------------------------------------------------------
  1742. LRESULT CMSInfo::OnStopFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1743. {
  1744. if (m_fInFind)
  1745. {
  1746. m_fCancelFind = TRUE;
  1747. m_fFindNext = FALSE;
  1748. GotoDlgCtrl(m_wndStopFind.m_hWnd);
  1749. UpdateFindControls();
  1750. }
  1751. else
  1752. {
  1753. m_fFindNext = FALSE;
  1754. DispatchCommand(ID_EDIT_FIND);
  1755. }
  1756. return 0;
  1757. }
  1758. //-------------------------------------------------------------------------
  1759. // UpdateFindControls updates the state of the controls (the text and
  1760. // enabling/disabling) based on the settings of the find member vars.
  1761. //-------------------------------------------------------------------------
  1762. void CMSInfo::UpdateFindControls()
  1763. {
  1764. if (!m_fFindVisible)
  1765. return;
  1766. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1767. m_wndCancelFind.ShowWindow(m_fInFind ? SW_SHOW : SW_HIDE);
  1768. m_wndStopFind.ShowWindow(m_fInFind ? SW_HIDE : SW_SHOW);
  1769. m_wndFindNext.ShowWindow(m_fFindNext ? SW_SHOW : SW_HIDE);
  1770. m_wndStartFind.ShowWindow(m_fFindNext ? SW_HIDE : SW_SHOW);
  1771. m_wndStopFind.EnableWindow(!m_fInFind && ((m_fInFind && !m_fCancelFind) || !m_fInFind));
  1772. m_wndCancelFind.EnableWindow(m_fInFind && ((m_fInFind && !m_fCancelFind) || !m_fInFind));
  1773. m_wndStartFind.EnableWindow(!m_fFindNext && (!m_fInFind && !m_strFind.IsEmpty()));
  1774. m_wndFindNext.EnableWindow(m_fFindNext && (!m_fInFind && !m_strFind.IsEmpty()));
  1775. m_wndFindWhatLabel.EnableWindow(!m_fInFind);
  1776. m_wndFindWhat.EnableWindow(!m_fInFind);
  1777. m_wndSearchSelected.EnableWindow(!m_fInFind);
  1778. m_wndSearchCategories.EnableWindow(!m_fInFind);
  1779. }
  1780. //-------------------------------------------------------------------------
  1781. // When the user changes the text in the find what edit box, we need to
  1782. // make sure we keep track of the string, and that we are in "find" (rather
  1783. // than "find next") mode.
  1784. //-------------------------------------------------------------------------
  1785. LRESULT CMSInfo::OnChangeFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1786. {
  1787. m_fFindNext = FALSE;
  1788. // Get the find text from the rich edit control (use EM_GETTEXTEX
  1789. // to preserve its Unicode-ness).
  1790. TCHAR szBuffer[MAX_PATH];
  1791. GETTEXTEX gte;
  1792. gte.cb = MAX_PATH;
  1793. gte.flags = GT_DEFAULT;
  1794. gte.codepage = 1200; // Unicode
  1795. gte.lpDefaultChar = NULL;
  1796. gte.lpUsedDefChar = NULL;
  1797. m_wndFindWhat.SendMessage(EM_GETTEXTEX, (WPARAM)&gte, (LPARAM)szBuffer);
  1798. m_strFind = szBuffer;
  1799. UpdateFindControls();
  1800. SetMenuItems();
  1801. return 0;
  1802. }
  1803. //-------------------------------------------------------------------------
  1804. // When the user clicks on Find, it will either be for a "Find" or a
  1805. // "Find Next".
  1806. //-------------------------------------------------------------------------
  1807. LRESULT CMSInfo::OnFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1808. {
  1809. m_fSearchCatNamesOnly = IsDlgButtonChecked(IDC_CHECKSEARCHCATSONLY);
  1810. m_fSearchSelectedCatOnly = IsDlgButtonChecked(IDC_CHECKSEARCHSELECTED);
  1811. if (!m_fFindNext)
  1812. {
  1813. m_fInFind = TRUE;
  1814. m_fCancelFind = FALSE;
  1815. m_fFindNext = TRUE;
  1816. m_iFindLine = -2;
  1817. // Based on the user's setting of "Search selected category only", start
  1818. // with either the selected category or the root category.
  1819. if (m_fSearchSelectedCatOnly)
  1820. m_pcatFind = GetCurrentCategory();
  1821. else
  1822. m_pcatFind = m_pCurrData->GetRootCategory();
  1823. UpdateFindControls();
  1824. ::SetFocus(m_wndCancelFind.m_hWnd);
  1825. }
  1826. else
  1827. {
  1828. if (FindInCurrentCategory())
  1829. return 0;
  1830. m_fInFind = TRUE;
  1831. m_fCancelFind = FALSE;
  1832. UpdateFindControls();
  1833. ::SetFocus(m_wndCancelFind.m_hWnd);
  1834. }
  1835. // The refresh will post a message that data is ready, so we can search the
  1836. // specified category. If we aren't going to refresh the category, we'll just
  1837. // post the message ourselves.
  1838. if (m_pcatFind)
  1839. {
  1840. SetMessage(IDS_SEARCHMESSAGE, 0, TRUE);
  1841. if (m_pcatFind->GetDataSourceType() == LIVE_DATA && !m_fSearchCatNamesOnly)
  1842. ((CMSInfoLiveCategory *) m_pcatFind)->Refresh((CLiveDataSource *) m_pCurrData, FALSE);
  1843. else
  1844. PostMessage(WM_MSINFODATAREADY, 0, (LPARAM)m_pcatFind);
  1845. }
  1846. return 0;
  1847. }
  1848. //-------------------------------------------------------------------------
  1849. // This is the function that's called when the data ready message is
  1850. // received by the window. Look for the data in the current find category.
  1851. // If there is a match, it will be shown and the find operation stopped.
  1852. // Otherwise (unless the option's been selected to search only the current
  1853. // category) continue the find operation with the next category.
  1854. //-------------------------------------------------------------------------
  1855. void CMSInfo::FindRefreshComplete()
  1856. {
  1857. if (m_fCancelFind)
  1858. {
  1859. m_fInFind = FALSE;
  1860. m_fFindNext = FALSE;
  1861. GotoDlgCtrl(m_wndStopFind.m_hWnd);
  1862. // SetMessage(0);
  1863. SelectCategory(GetCurrentCategory());
  1864. UpdateFindControls();
  1865. ::SetFocus(m_wndStartFind.m_hWnd);
  1866. return;
  1867. }
  1868. if (FindInCurrentCategory())
  1869. return;
  1870. // If the user checked "Search selected category only", then we should
  1871. // not look through any additional categories.
  1872. if (m_fSearchSelectedCatOnly)
  1873. m_pcatFind = NULL;
  1874. else
  1875. {
  1876. m_iFindLine = -2;
  1877. CMSInfoCategory * pNextCategory;
  1878. pNextCategory = m_pcatFind->GetFirstChild();
  1879. if (pNextCategory == NULL)
  1880. while (m_pcatFind)
  1881. {
  1882. pNextCategory = m_pcatFind->GetNextSibling();
  1883. if (pNextCategory)
  1884. break;
  1885. m_pcatFind = m_pcatFind->GetParent();
  1886. }
  1887. m_pcatFind = pNextCategory;
  1888. }
  1889. // If the category is NULL, there are no more matches. Return the
  1890. // controls to a normal state and notify the user.
  1891. if (m_pcatFind == NULL)
  1892. {
  1893. m_fInFind = FALSE;
  1894. m_fFindNext = FALSE;
  1895. UpdateFindControls();
  1896. MSInfoMessageBox(IDS_NOMOREMATCHES);
  1897. SelectCategory(GetCurrentCategory());
  1898. GotoDlgCtrl(m_wndStopFind.m_hWnd);
  1899. return;
  1900. }
  1901. SetMessage(IDS_SEARCHMESSAGE);
  1902. if (m_pcatFind->GetDataSourceType() == LIVE_DATA && !m_fSearchCatNamesOnly)
  1903. ((CMSInfoLiveCategory *) m_pcatFind)->Refresh((CLiveDataSource *) m_pCurrData, FALSE);
  1904. else
  1905. PostMessage(WM_MSINFODATAREADY, 0, (LPARAM)m_pcatFind);
  1906. }
  1907. //-------------------------------------------------------------------------
  1908. // Look for the string in the current category. This function will be
  1909. // called when data is avaible for the category. If there is a match, show
  1910. // it and return TRUE, otherwise return FALSE.
  1911. //
  1912. // m_iFindLine contains the list view row number of the last match. If it
  1913. // is -1, it means we are just starting on this category (since we would
  1914. // start looking at row 0). If it is -2, then we should look for the string
  1915. // in the category name. (Note - this might be all we do, depending on the
  1916. // setting for m_fSearchCatNamesOnly.)
  1917. //-------------------------------------------------------------------------
  1918. BOOL CMSInfo::FindInCurrentCategory()
  1919. {
  1920. if (m_pcatFind == NULL)
  1921. return FALSE;
  1922. // The search is case insensitive, so convert our search string to lower case.
  1923. CString strLookFor(m_strFind);
  1924. strLookFor.TrimLeft(_T("\t\r\n "));
  1925. strLookFor.TrimRight(_T("\t\r\n "));
  1926. strLookFor.MakeLower();
  1927. // If m_iFindLine is -2, then we should look at the category name for a match.
  1928. if (m_iFindLine == -2)
  1929. {
  1930. m_iFindLine += 1;
  1931. CString strCatName;
  1932. m_pcatFind->GetNames(&strCatName, NULL);
  1933. strCatName.MakeLower();
  1934. if (strCatName.Find(strLookFor) != -1)
  1935. {
  1936. // There was a match. Get the HTREEITEM for the category and select it.
  1937. HTREEITEM hti = m_pcatFind->GetHTREEITEM();
  1938. if (hti)
  1939. {
  1940. m_fInFind = FALSE;
  1941. m_fFindNext = TRUE;
  1942. TreeView_EnsureVisible(m_tree.m_hWnd, hti);
  1943. TreeView_SelectItem(m_tree.m_hWnd, hti);
  1944. SetMessage(0);
  1945. UpdateFindControls();
  1946. GotoDlgCtrl(m_wndFindNext.m_hWnd);
  1947. return TRUE;
  1948. }
  1949. }
  1950. }
  1951. // If we are search category names only, then we stop here (before looking
  1952. // through the data for this category).
  1953. if (m_fSearchCatNamesOnly)
  1954. return FALSE;
  1955. // If m_iFindLine is -1, then we need to look in the data for this category
  1956. // to see if there is a match. If there is, then we select the category and
  1957. // start looking through the lines of the list view (we can't use the index
  1958. // we found looking through the data directly, because if the list view is
  1959. // sorted we would be searching out of order).
  1960. int iRow, iCol, iRowCount, iColCount;
  1961. if (!m_pcatFind->GetCategoryDimensions(&iColCount, &iRowCount))
  1962. return FALSE;
  1963. if (m_iFindLine == -1)
  1964. {
  1965. CString * pstrCell, strCell;
  1966. BOOL fFound = FALSE;
  1967. for (iRow = 0; iRow < iRowCount && !fFound; iRow++)
  1968. if (m_fAdvanced || !m_pcatFind->IsRowAdvanced(iRow))
  1969. for (iCol = 0; iCol < iColCount && !fFound; iCol++)
  1970. if (m_fAdvanced || !m_pcatFind->IsColumnAdvanced(iCol))
  1971. if (m_pcatFind->GetData(iRow, iCol, &pstrCell, NULL))
  1972. {
  1973. strCell = *pstrCell;
  1974. strCell.MakeLower();
  1975. if (strCell.Find(strLookFor) != -1)
  1976. fFound = TRUE;
  1977. }
  1978. if (!fFound)
  1979. return FALSE;
  1980. // We found data in this category. Select it so it populates the list view.
  1981. HTREEITEM hti = m_pcatFind->GetHTREEITEM();
  1982. if (hti)
  1983. {
  1984. TreeView_EnsureVisible(m_tree.m_hWnd, hti);
  1985. TreeView_SelectItem(m_tree.m_hWnd, hti);
  1986. SetMessage(0);
  1987. }
  1988. }
  1989. // If we get here, m_iFindLine will be >= -1, and represents the line in the
  1990. // list view after which we should start searching.
  1991. m_iFindLine += 1;
  1992. CString strData;
  1993. int iListRowCount = ListView_GetItemCount(m_list.m_hWnd);
  1994. int iListColCount = 0;
  1995. // Determine the number of columns in the list view.
  1996. for (iCol = 0; iCol < iColCount; iCol++)
  1997. if (m_fAdvanced || !m_pcatFind->IsColumnAdvanced(iCol))
  1998. iListColCount += 1;
  1999. while (m_iFindLine < iListRowCount)
  2000. {
  2001. for (iCol = 0; iCol < iListColCount; iCol++)
  2002. {
  2003. ListView_GetItemText(m_list.m_hWnd, m_iFindLine, iCol, strData.GetBuffer(MAX_PATH), MAX_PATH);
  2004. strData.ReleaseBuffer();
  2005. if (strData.GetLength())
  2006. {
  2007. strData.MakeLower();
  2008. if (strData.Find(strLookFor) != -1)
  2009. {
  2010. // We found a match. The category should already be selected,
  2011. // so all we need to do is select the line (and make sure
  2012. // all the other lines are not selected).
  2013. for (int iRow = 0; iRow < iListRowCount; iRow++)
  2014. if (iRow == m_iFindLine)
  2015. {
  2016. ListView_EnsureVisible(m_list.m_hWnd, iRow, TRUE);
  2017. ListView_SetItemState(m_list.m_hWnd, iRow, LVIS_SELECTED, LVIS_SELECTED);
  2018. }
  2019. else
  2020. {
  2021. ListView_SetItemState(m_list.m_hWnd, iRow, 0, LVIS_SELECTED);
  2022. }
  2023. m_fInFind = FALSE;
  2024. m_fFindNext = TRUE;
  2025. SetMessage(0);
  2026. UpdateFindControls();
  2027. GotoDlgCtrl(m_wndFindNext.m_hWnd);
  2028. return TRUE;
  2029. }
  2030. }
  2031. }
  2032. m_iFindLine += 1;
  2033. }
  2034. // If we fall through to here, then there were no more matches in the
  2035. // list view. Return FALSE.
  2036. return FALSE;
  2037. }
  2038. //-------------------------------------------------------------------------
  2039. // ShowFindControls is called to show or hide the dialog controls used
  2040. // for find.
  2041. //-------------------------------------------------------------------------
  2042. void CMSInfo::ShowFindControls()
  2043. {
  2044. int iShowCommand = (m_fFindVisible) ? SW_SHOW : SW_HIDE;
  2045. if (m_fFindVisible)
  2046. PositionFindControls();
  2047. m_wndFindWhatLabel.ShowWindow(iShowCommand);
  2048. m_wndFindWhat.ShowWindow(iShowCommand);
  2049. m_wndSearchSelected.ShowWindow(iShowCommand);
  2050. m_wndSearchCategories.ShowWindow(iShowCommand);
  2051. m_wndStartFind.ShowWindow(iShowCommand);
  2052. m_wndStopFind.ShowWindow(iShowCommand);
  2053. m_wndFindNext.ShowWindow(iShowCommand);
  2054. m_wndCancelFind.ShowWindow(iShowCommand);
  2055. if (iShowCommand == SW_HIDE)
  2056. {
  2057. m_wndFindWhatLabel.EnableWindow(FALSE);
  2058. m_wndFindWhat.EnableWindow(FALSE);
  2059. m_wndSearchSelected.EnableWindow(FALSE);
  2060. m_wndSearchCategories.EnableWindow(FALSE);
  2061. m_wndStartFind.EnableWindow(FALSE);
  2062. m_wndStopFind.EnableWindow(FALSE);
  2063. m_wndFindNext.EnableWindow(FALSE);
  2064. m_wndCancelFind.EnableWindow(FALSE);
  2065. }
  2066. if (!m_fFindVisible)
  2067. return;
  2068. }
  2069. //-------------------------------------------------------------------------
  2070. // Position the find controls on the control surface. This will be called
  2071. // when the find controls are shown, or when the control is resized.
  2072. //-------------------------------------------------------------------------
  2073. int CMSInfo::PositionFindControls()
  2074. {
  2075. if (!m_fFindVisible)
  2076. return 0;
  2077. // Get some useful sizes of the various controls we need to move around
  2078. // the window.
  2079. CRect rectFindWhatLabel, rectFindWhat, rectSearchSelected, rectSearchCategories;
  2080. CRect rectStartFind, rectStopFind, rectClient;
  2081. GetClientRect(&rectClient);
  2082. m_wndFindWhatLabel.GetWindowRect(&rectFindWhatLabel);
  2083. m_wndFindWhat.GetWindowRect(&rectFindWhat);
  2084. m_wndStartFind.GetWindowRect(&rectStartFind);
  2085. m_wndStopFind.GetWindowRect(&rectStopFind);
  2086. m_wndSearchSelected.GetWindowRect(&rectSearchSelected);
  2087. m_wndSearchCategories.GetWindowRect(&rectSearchCategories);
  2088. int iSpacer = 5;
  2089. // The control rect is the space we have to work with for placing the controls.
  2090. CRect rectControl(rectClient);
  2091. rectControl.DeflateRect(iSpacer, iSpacer);
  2092. // Determine if we have enough room to lay out the controls
  2093. // horizontally, or if we need to stack them. Horizontally, it looks like:
  2094. //
  2095. // <spacer><Find What label><spacer><Find What edit><spacer><Start Find><spacer><Stop Find><spacer>
  2096. // <spacer><Search Selected check><spacer><Search Cats check><spacer>
  2097. int cxTopLine = iSpacer * 5 + rectFindWhatLabel.Width() * 2 + rectStartFind.Width() + rectStopFind.Width();
  2098. int cxBottomLine = iSpacer * 3 + rectSearchSelected.Width() + rectSearchCategories.Width();
  2099. BOOL fHorizontal = (cxTopLine <= rectClient.Width() && cxBottomLine <= rectClient.Width());
  2100. // If it get's wider than a certain size, it becomes less usable. So put a reasonable
  2101. // limit on the width:
  2102. int cxMaxWidth = iSpacer * 5 + rectFindWhatLabel.Width() + rectSearchSelected.Width() + rectSearchCategories.Width() + rectStartFind.Width() + rectStopFind.Width();
  2103. if (fHorizontal && rectControl.Width() > cxMaxWidth)
  2104. rectControl.DeflateRect((rectControl.Width() - cxMaxWidth) / 2, 0);
  2105. // Figure the height of the control rectangle.
  2106. int cyControlRectHeight = rectStartFind.Height() + ((fHorizontal) ? 0 : rectStopFind.Height() + iSpacer);
  2107. int cyLeftSideHeight;
  2108. if (fHorizontal)
  2109. cyLeftSideHeight = rectFindWhat.Height() + iSpacer + rectSearchSelected.Height();
  2110. else
  2111. cyLeftSideHeight = rectFindWhat.Height() + iSpacer * 2 + rectSearchSelected.Height() * 2;
  2112. if (cyControlRectHeight < cyLeftSideHeight)
  2113. cyControlRectHeight = cyLeftSideHeight;
  2114. rectControl.top = rectControl.bottom - cyControlRectHeight;
  2115. // Position the buttons appropriately.
  2116. if (fHorizontal)
  2117. {
  2118. rectStopFind.OffsetRect(rectControl.right - rectStopFind.right, rectControl.top - rectStopFind.top);
  2119. rectStartFind.OffsetRect(rectStopFind.left - rectStartFind.right - iSpacer, rectControl.top - rectStartFind.top);
  2120. }
  2121. else
  2122. {
  2123. rectStartFind.OffsetRect(rectControl.right - rectStartFind.right, rectControl.top - rectStartFind.top);
  2124. rectStopFind.OffsetRect(rectControl.right - rectStopFind.right, rectStartFind.bottom + iSpacer - rectStopFind.top);
  2125. }
  2126. // Position the find label and the find edit box.
  2127. rectFindWhatLabel.OffsetRect(rectControl.left - rectFindWhatLabel.left, rectControl.top - rectFindWhatLabel.top + (rectFindWhat.Height() - rectFindWhatLabel.Height()) / 2);
  2128. rectFindWhat.OffsetRect(rectFindWhatLabel.right - rectFindWhat.left + iSpacer, rectControl.top - rectFindWhat.top);
  2129. rectFindWhat.right = rectStartFind.left - iSpacer;
  2130. // Position the check boxes.
  2131. rectSearchSelected.OffsetRect(rectControl.left - rectSearchSelected.left, rectFindWhat.bottom - rectSearchSelected.top + iSpacer);
  2132. if (fHorizontal)
  2133. rectSearchCategories.OffsetRect(rectSearchSelected.right - rectSearchCategories.left + iSpacer, rectSearchSelected.top - rectSearchCategories.top);
  2134. else
  2135. rectSearchCategories.OffsetRect(rectControl.left - rectSearchCategories.left, rectSearchSelected.bottom - rectSearchCategories.top + iSpacer);
  2136. // If the check boxes are going to overlap the buttons (we'd be very narrow), adjust the button
  2137. // position (which might end up off the control, but what're ya gonna do?).
  2138. int iRightMostCheckboxEdge = rectSearchCategories.right;
  2139. if (iRightMostCheckboxEdge < rectSearchSelected.right)
  2140. iRightMostCheckboxEdge = rectSearchSelected.right;
  2141. iRightMostCheckboxEdge += iSpacer;
  2142. if (!fHorizontal && rectStopFind.left < iRightMostCheckboxEdge)
  2143. {
  2144. rectStopFind.OffsetRect(iRightMostCheckboxEdge - rectStopFind.left, 0);
  2145. rectStartFind.OffsetRect(rectStopFind.left - rectStartFind.left, 0);
  2146. rectFindWhat.right = rectStartFind.left - iSpacer;
  2147. }
  2148. m_wndStopFind.MoveWindow(&rectStopFind);
  2149. m_wndStartFind.MoveWindow(&rectStartFind);
  2150. m_wndFindNext.MoveWindow(&rectStartFind);
  2151. m_wndCancelFind.MoveWindow(&rectStopFind);
  2152. m_wndFindWhatLabel.MoveWindow(&rectFindWhatLabel);
  2153. m_wndFindWhat.MoveWindow(&rectFindWhat);
  2154. m_wndSearchSelected.MoveWindow(&rectSearchSelected);
  2155. m_wndSearchCategories.MoveWindow(&rectSearchCategories);
  2156. return (rectControl.Height() + iSpacer * 2);
  2157. }
  2158. //-------------------------------------------------------------------------
  2159. // Refresh all of the data prior to saving, exporting, printing. This will
  2160. // present a dialog box with the refresh message and a progress bar, but
  2161. // will not return until the refresh is completed.
  2162. //-------------------------------------------------------------------------
  2163. void CMSInfo::RefreshData(CLiveDataSource * pSource, CMSInfoLiveCategory * pLiveCategory)
  2164. {
  2165. if (pSource == NULL || pSource->m_pThread == NULL)
  2166. return;
  2167. // Create the dialog with the refresh message and progress
  2168. // bar, and display it.
  2169. CWaitForRefreshDialog dlg;
  2170. dlg.DoRefresh(pSource, pLiveCategory);
  2171. }
  2172. //=============================================================================
  2173. // Functions for managing the DCO (the object providing history).
  2174. //=============================================================================
  2175. STDMETHODIMP CMSInfo::UpdateDCOProgress(VARIANT varPctDone)
  2176. {
  2177. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  2178. //V-stlowe 1/30/2001
  2179. VERIFY(SUCCEEDED(VariantChangeType(&varPctDone,&varPctDone,0,VT_INT)));
  2180. if (this->m_HistoryProgressDlg.IsWindow())//todo: is there a better state function to determine if dlg is modal?
  2181. {
  2182. HWND hWnd = m_HistoryProgressDlg.GetDlgItem(IDC_PROGRESS1);
  2183. if(::IsWindow(hWnd))
  2184. {
  2185. //int nOffset = varPctDone.iVal - (int) ::SendMessage(m_hWnd, PBM_GETPOS, 0, 0);
  2186. //To do: don't rely on 3 (current SAF progress step); find way to get offset.
  2187. ::SendMessage(hWnd, PBM_DELTAPOS,3, 0L);
  2188. }
  2189. }
  2190. return S_OK;
  2191. }
  2192. STDMETHODIMP CMSInfo::SetHistoryStream(IStream *pStream)
  2193. {
  2194. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2195. #ifdef A_STEPHL
  2196. ASSERT(0);
  2197. #endif
  2198. //v-stlowe 2/23/2001 shut down progress bar dialog
  2199. SetEvent(m_hEvtHistoryComplete);
  2200. HRESULT hr = pStream->QueryInterface(IID_IStream,(void**) &m_pHistoryStream);
  2201. if (FAILED(hr) || !m_pHistoryStream)
  2202. {
  2203. m_pHistoryStream = NULL;
  2204. return E_FAIL;
  2205. }
  2206. if (m_pLiveData)
  2207. ((CLiveDataSource *)m_pLiveData)->SetHistoryStream(m_pHistoryStream);
  2208. // When the history stream is available, we need to modify the UI to allow
  2209. // the user to select the history.
  2210. if (!m_fHistoryAvailable)
  2211. {
  2212. m_fHistoryAvailable = TRUE;//actually this should already be true...
  2213. SetMenuItems();
  2214. }
  2215. m_fHistorySaveAvailable = TRUE;
  2216. FillHistoryCombo();
  2217. //if history window is current view, refresh
  2218. if (m_history.IsWindowVisible())
  2219. {
  2220. CMSInfoCategory * pCategory = GetCurrentCategory();
  2221. if (pCategory != NULL && pCategory->GetDataSourceType() == LIVE_DATA)
  2222. {
  2223. m_pLastCurrentCategory = GetCurrentCategory();
  2224. int iIndex = (int)m_history.SendMessage(CB_GETCURSEL, 0, 0);
  2225. if (iIndex == CB_ERR)
  2226. {
  2227. iIndex = 0;
  2228. m_history.SendMessage(CB_SETCURSEL, (WPARAM)iIndex, 0);
  2229. }
  2230. ChangeHistoryView(iIndex);
  2231. }
  2232. }
  2233. else if (m_fShowPCH && !m_history.IsWindowVisible() && m_strMachine.IsEmpty())
  2234. {
  2235. // If m_fShowPCH is set, then the command line option to launch into
  2236. // the history view was selected.
  2237. DispatchCommand(ID_VIEW_HISTORY);
  2238. }
  2239. #ifdef A_STEPHL
  2240. //STATSTG streamStat;
  2241. //hr = m_pHistoryStream->Stat(&streamStat,STATFLAG_NONAME );
  2242. //ASSERT(SUCCEEDED(hr) && "couldn't get stream statistics");
  2243. //BYTE* pBuffer = new BYTE[streamStat.cbSize.LowPart];
  2244. //ULONG ulRead;
  2245. //m_pHistoryStream->Read(pBuffer,streamStat.cbSize.LowPart,&ulRead);
  2246. // CFile file;
  2247. //file.Open("c:\\history.xml", CFile::modeCreate | CFile::modeWrite);
  2248. // file.Write(pBuffer,ulRead);
  2249. // delete pBuffer;
  2250. #endif
  2251. return S_OK;
  2252. }
  2253. STDMETHODIMP CMSInfo::get_DCO_IUnknown(IUnknown **pVal)
  2254. {
  2255. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2256. if (m_pDCO == NULL)
  2257. return E_FAIL;
  2258. return (m_pDCO->QueryInterface(IID_IUnknown,(void**) pVal));
  2259. }
  2260. STDMETHODIMP CMSInfo::put_DCO_IUnknown(IUnknown *newVal)
  2261. {
  2262. //v-stlowe 2/23/2001
  2263. //beware situation where put_DCO_IUnknown gets called before control is finished initializing.
  2264. WaitForSingleObject(m_evtControlInit,INFINITE);
  2265. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2266. HRESULT hr = newVal->QueryInterface( __uuidof(ISAFDataCollection), (void**)&m_pDCO );
  2267. if (FAILED(hr))
  2268. return E_FAIL;
  2269. //end v-stlowe 2/23/2001
  2270. TCHAR szDataspecPath[MAX_PATH];
  2271. if (ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\config\\dataspec.xml"), szDataspecPath, MAX_PATH))
  2272. {
  2273. CComBSTR bstrPath(szDataspecPath);
  2274. if (m_pDCO != NULL && (BSTR)bstrPath != NULL)
  2275. {
  2276. hr = m_pDCO->put_MachineData_DataSpec(bstrPath);
  2277. hr = m_pDCO->put_History_DataSpec(bstrPath);
  2278. }
  2279. // This is done by the script now: m_pDCO->ExecuteAsync();
  2280. }
  2281. // Have to put this after the calls made using the DCO, so that the /pch
  2282. // flag (which is to start MSInfo with history showing) works.
  2283. if (!m_fHistoryAvailable)
  2284. {
  2285. m_fHistoryAvailable = TRUE;
  2286. if (m_fShowPCH && !m_history.IsWindowVisible() && m_strMachine.IsEmpty())
  2287. DispatchCommand(ID_VIEW_HISTORY);
  2288. SetMenuItems();
  2289. }
  2290. return S_OK;
  2291. }
  2292. //=============================================================================
  2293. // Interface methods to do a silent save of a file.
  2294. //=============================================================================
  2295. STDMETHODIMP CMSInfo::SaveFile(BSTR filename, BSTR computer, BSTR category)
  2296. {
  2297. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2298. CString strFilename(filename);
  2299. CString strComputer(computer);
  2300. CString strCategory(category);
  2301. HRESULT hr = E_FAIL;
  2302. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  2303. CLiveDataSource * pSilentSource = new CLiveDataSource;
  2304. if (pSilentSource)
  2305. hr = pSilentSource->Create(strComputer, NULL, strCategory);
  2306. if (SUCCEEDED(hr))
  2307. {
  2308. m_fNoUI = TRUE;
  2309. CDataSource * pOldSource = m_pCurrData;
  2310. m_pCurrData = pSilentSource;
  2311. if (strFilename.Right(4).CompareNoCase(CString(_T(".nfo"))) == 0)
  2312. SaveMSInfoFile(strFilename);
  2313. else
  2314. ExportFile(strFilename, 0);
  2315. m_pCurrData = pOldSource;
  2316. delete pSilentSource;
  2317. m_fNoUI = FALSE;
  2318. }
  2319. return hr;
  2320. }
  2321. LRESULT CHistoryRefreshDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2322. {
  2323. return 1; // Let the system set the focus
  2324. }