Source code of Windows XP (NT5)
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.

851 lines
20 KiB

  1. #include "precomp.h"
  2. #include "viewlog.h"
  3. CSessionLogEntry* g_pSessionLogHead = NULL;
  4. TCHAR g_szSingleLogFile[MAX_PATH] = _T("");
  5. HWND g_hwndIssues;
  6. int g_cWidth;
  7. int g_cHeight;
  8. TCHAR*
  9. fGetLine(
  10. TCHAR* szLine,
  11. int nChars,
  12. FILE* file
  13. )
  14. {
  15. if (_fgetts(szLine, nChars, file)) {
  16. int nLen = _tcslen(szLine);
  17. while (szLine[nLen - 1] == _T('\n') || szLine[nLen - 1] == _T('\r')) {
  18. szLine[nLen - 1] = 0;
  19. nLen--;
  20. }
  21. return szLine;
  22. } else {
  23. return NULL;
  24. }
  25. }
  26. CSessionLogEntry*
  27. GetSessionLogEntry(
  28. HWND hDlg,
  29. LPCTSTR szLogFullPath
  30. )
  31. {
  32. TCHAR szLine[4096];
  33. FILE * file = NULL;
  34. SYSTEMTIME stime;
  35. CSessionLogEntry *pEntryTemp = NULL;
  36. TCHAR *szBegin = NULL;
  37. TCHAR *szEnd = NULL;
  38. HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
  39. file = _tfopen(szLogFullPath, _T("rt"));
  40. if (!file) {
  41. goto out;
  42. }
  43. if (fGetLine(szLine, 4096, file)) {
  44. ZeroMemory(&stime, sizeof(SYSTEMTIME));
  45. int nFields = _stscanf(szLine, _T("# LOG_BEGIN %hd/%hd/%hd %hd:%hd:%hd"),
  46. &stime.wMonth,
  47. &stime.wDay,
  48. &stime.wYear,
  49. &stime.wHour,
  50. &stime.wMinute,
  51. &stime.wSecond);
  52. //
  53. // if we parsed that line properly, then we've got a valid line.
  54. // Parse it.
  55. //
  56. if (nFields == 6) {
  57. pEntryTemp = new CSessionLogEntry;
  58. if (!pEntryTemp) {
  59. goto out;
  60. }
  61. pEntryTemp->RunTime = stime;
  62. pEntryTemp->strLogPath = szLogFullPath;
  63. //
  64. // get the log file and exe path
  65. //
  66. szBegin = _tcschr(szLine, _T('\''));
  67. if (szBegin) {
  68. szBegin++;
  69. szEnd = _tcschr(szBegin, _T('\''));
  70. if (szEnd) {
  71. TCHAR szName[MAX_PATH];
  72. TCHAR szExt[_MAX_EXT];
  73. *szEnd = 0;
  74. pEntryTemp->strExePath = szBegin;
  75. *szEnd = 0;
  76. //
  77. // split the path and get the name and extension
  78. //
  79. _tsplitpath(pEntryTemp->strExePath, NULL, NULL, szName, szExt);
  80. pEntryTemp->strExeName = szName;
  81. pEntryTemp->strExeName += szExt;
  82. }
  83. }
  84. //
  85. // Add it to the tree.
  86. //
  87. TVINSERTSTRUCT is;
  88. WCHAR szItem[256];
  89. wsprintf(szItem, L"%s - %d/%d/%d %d:%02d",
  90. pEntryTemp->strExeName,
  91. pEntryTemp->RunTime.wMonth,
  92. pEntryTemp->RunTime.wDay,
  93. pEntryTemp->RunTime.wYear,
  94. pEntryTemp->RunTime.wHour,
  95. pEntryTemp->RunTime.wMinute);
  96. is.hParent = TVI_ROOT;
  97. is.hInsertAfter = TVI_LAST;
  98. is.item.lParam = 0;
  99. is.item.mask = TVIF_TEXT;
  100. is.item.pszText = szItem;
  101. pEntryTemp->hTreeItem = TreeView_InsertItem(hTree, &is);
  102. }
  103. }
  104. out:
  105. if (file) {
  106. fclose(file);
  107. file = NULL;
  108. }
  109. return pEntryTemp;
  110. }
  111. DWORD
  112. ReadSessionLog(HWND hDlg, CSessionLogEntry **ppSessionLog)
  113. {
  114. TCHAR szLine[4096];
  115. FILE * file = NULL;
  116. SYSTEMTIME stime;
  117. CSessionLogEntry *pEntryTemp = NULL;
  118. DWORD dwEntries = 0;
  119. TCHAR *szBegin = NULL;
  120. TCHAR *szEnd = NULL;
  121. CSessionLogEntry **ppEnd = ppSessionLog;
  122. HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
  123. TCHAR szVLog[MAX_PATH];
  124. TCHAR szLogFullPath[MAX_PATH];
  125. WIN32_FIND_DATA FindData;
  126. HANDLE hFind = INVALID_HANDLE_VALUE;
  127. TCHAR szLogSearch[MAX_PATH];
  128. //
  129. // BUGBUG -- this is cheesy, but it's the fastest way to make the change
  130. // to remove session.log. Going forward, we should combine these two functions
  131. // into one, and switch to vectors instead of linked lists
  132. //
  133. GetSystemWindowsDirectory(szVLog, MAX_PATH);
  134. _tcscat(szVLog, _T("\\AppPatch\\VLog\\"));
  135. _tcscpy(szLogSearch, szVLog);
  136. _tcscat(szLogSearch, _T("*.log"));
  137. //
  138. // enumerate all the logs and make entries for them
  139. //
  140. hFind = FindFirstFile(szLogSearch, &FindData);
  141. while (hFind != INVALID_HANDLE_VALUE) {
  142. //
  143. // make sure to exclude session.log, in case we're using older shims
  144. //
  145. if (_tcsicmp(FindData.cFileName, _T("session.log")) == 0) {
  146. goto nextFile;
  147. }
  148. _tcscpy(szLogFullPath, szVLog);
  149. _tcscat(szLogFullPath, FindData.cFileName);
  150. pEntryTemp = GetSessionLogEntry(hDlg, szLogFullPath);
  151. if (pEntryTemp) {
  152. //
  153. // we want these in the order they appear in the log,
  154. // so we add to the end rather than the beginning.
  155. //
  156. *ppEnd = pEntryTemp;
  157. ppEnd = &(pEntryTemp->pNext);
  158. dwEntries++;
  159. }
  160. nextFile:
  161. if (!FindNextFile(hFind, &FindData)) {
  162. FindClose(hFind);
  163. hFind = INVALID_HANDLE_VALUE;
  164. }
  165. }
  166. return dwEntries;
  167. }
  168. DWORD
  169. ReadProcessLog(HWND hDlg, CSessionLogEntry* pSLogEntry)
  170. {
  171. TCHAR szLine[4096];
  172. FILE * file = NULL;
  173. CProcessLogEntry *pProcessEntry = NULL;
  174. TCHAR szShimName[256];
  175. DWORD dwEntries = 0;
  176. TCHAR * szTemp = NULL;
  177. DWORD dwEntry = 0;
  178. TCHAR *szBegin = NULL;
  179. CProcessLogEntry **ppProcessTail = &(pSLogEntry->pProcessLog);
  180. HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
  181. if (!pSLogEntry) {
  182. return 0;
  183. }
  184. file = _tfopen(pSLogEntry->strLogPath, _T("rt"));
  185. if (!file) {
  186. return 0;
  187. }
  188. //
  189. // first get the headers
  190. //
  191. szTemp = fGetLine(szLine, 4096, file);
  192. while (szTemp) {
  193. if (szLine[0] == _T('|')) {
  194. break;
  195. }
  196. if (szLine[0] != _T('#')) {
  197. goto nextLine;
  198. }
  199. if (_stscanf(szLine, _T("# LOGENTRY %s %d '"), szShimName, &dwEntry) == 2) {
  200. if (pProcessEntry) {
  201. *ppProcessTail = pProcessEntry;
  202. ppProcessTail = &(pProcessEntry->pNext);
  203. pProcessEntry = NULL;
  204. dwEntries++;
  205. }
  206. pProcessEntry = new CProcessLogEntry;
  207. if (!pProcessEntry) {
  208. goto out;
  209. }
  210. pProcessEntry->strShimName = szShimName;
  211. pProcessEntry->dwLogNum = dwEntry;
  212. szBegin = _tcschr(szLine, _T('\''));
  213. if (szBegin) {
  214. szBegin++;
  215. pProcessEntry->strLogTitle = szBegin;
  216. }
  217. } else if (_tcsncmp(szLine, _T("# DESCRIPTION BEGIN"), 19) == 0) {
  218. szTemp = fGetLine(szLine, 4096, file);
  219. while (szTemp) {
  220. if (_tcsncmp(szLine, _T("# DESCRIPTION END"), 17) == 0) {
  221. break;
  222. }
  223. if (pProcessEntry) {
  224. //
  225. // throw in a carriage return if necessary
  226. //
  227. if (pProcessEntry->strLogDescription.GetLength()) {
  228. pProcessEntry->strLogDescription += _T("\n");
  229. }
  230. pProcessEntry->strLogDescription += szLine;
  231. }
  232. szTemp = fGetLine(szLine, 4096, file);
  233. }
  234. } else if (_tcsncmp(szLine, _T("# URL '"), 7) == 0) {
  235. szBegin = _tcschr(szLine, _T('\''));
  236. if (szBegin) {
  237. szBegin++;
  238. pProcessEntry->strLogURL = szBegin;
  239. }
  240. }
  241. nextLine:
  242. szTemp = fGetLine(szLine, 4096, file);
  243. }
  244. //
  245. // if we've still got an entry in process, save it
  246. //
  247. if (pProcessEntry) {
  248. *ppProcessTail = pProcessEntry;
  249. ppProcessTail = &(pProcessEntry->pNext);
  250. pProcessEntry = NULL;
  251. dwEntries++;
  252. }
  253. //
  254. // now read all the log lines
  255. //
  256. while (szTemp) {
  257. CProcessLogEntry *pEntry;
  258. TCHAR szName[256];
  259. int nFields = _stscanf(szLine, _T("| %s %d '"), szName, &dwEntry);
  260. if (nFields == 2) {
  261. BOOL bFound = FALSE;
  262. pEntry = pSLogEntry->pProcessLog;
  263. while (pEntry) {
  264. if (pEntry->strShimName == szName && pEntry->dwLogNum == dwEntry) {
  265. pEntry->dwOccurences++;
  266. bFound = TRUE;
  267. //
  268. // here's where we would save the occurrence info
  269. //
  270. szBegin = _tcschr(szLine, _T('\''));
  271. if (szBegin) {
  272. szBegin++;
  273. pEntry->arrProblems.Add(szBegin);
  274. }
  275. break;
  276. }
  277. pEntry = pEntry->pNext;
  278. }
  279. if (!bFound) {
  280. //
  281. // need to dump a debug string -- no matching log entry found
  282. //
  283. ;
  284. }
  285. }
  286. szTemp = fGetLine(szLine, 4096, file);
  287. }
  288. out:
  289. //
  290. // Add it to the tree
  291. //
  292. pProcessEntry = pSLogEntry->pProcessLog;
  293. while (pProcessEntry != NULL) {
  294. if (pProcessEntry->dwOccurences > 0) {
  295. TVINSERTSTRUCT is;
  296. is.hParent = pSLogEntry->hTreeItem;
  297. is.hInsertAfter = TVI_LAST;
  298. is.item.lParam = (LPARAM)pProcessEntry;
  299. is.item.mask = TVIF_TEXT | TVIF_PARAM;
  300. is.item.pszText = pProcessEntry->strLogTitle.GetBuffer(0);
  301. pProcessEntry->hTreeItem = TreeView_InsertItem(hTree, &is);
  302. for (int i = 0; i < pProcessEntry->arrProblems.GetSize(); i++) {
  303. is.hParent = pProcessEntry->hTreeItem;
  304. is.hInsertAfter = TVI_LAST;
  305. is.item.lParam = 0;
  306. is.item.mask = TVIF_TEXT;
  307. is.item.pszText = pProcessEntry->arrProblems.GetAt(i).GetBuffer(0);
  308. TreeView_InsertItem(hTree, &is);
  309. }
  310. }
  311. pProcessEntry = pProcessEntry->pNext;
  312. }
  313. if (file) {
  314. fclose(file);
  315. file = NULL;
  316. }
  317. return dwEntries;
  318. }
  319. void
  320. SetLogDialogCaption(HWND hDlg, ULONG ulCaptionID, LPCWSTR szAdditional)
  321. {
  322. wstring wstrCaption;
  323. if (AVLoadString(ulCaptionID, wstrCaption)) {
  324. if (szAdditional) {
  325. wstrCaption += szAdditional;
  326. }
  327. SetWindowText(hDlg, wstrCaption.c_str());
  328. }
  329. }
  330. void
  331. RefreshLog(HWND hDlg)
  332. {
  333. TreeView_DeleteAllItems(g_hwndIssues);
  334. if (g_pSessionLogHead) {
  335. delete g_pSessionLogHead;
  336. g_pSessionLogHead = NULL;
  337. }
  338. if (g_szSingleLogFile[0]) {
  339. g_pSessionLogHead = GetSessionLogEntry(hDlg, g_szSingleLogFile);
  340. SetLogDialogCaption(hDlg, IDS_LOG_TITLE_SINGLE, g_szSingleLogFile);
  341. } else {
  342. ReadSessionLog(hDlg, &g_pSessionLogHead);
  343. SetLogDialogCaption(hDlg, IDS_LOG_TITLE_LOCAL, NULL);
  344. }
  345. CSessionLogEntry* pEntry = g_pSessionLogHead;
  346. while (pEntry) {
  347. ReadProcessLog(hDlg, pEntry);
  348. pEntry = pEntry->pNext;
  349. }
  350. EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE);
  351. }
  352. void
  353. HandleSizing(
  354. HWND hDlg
  355. )
  356. {
  357. int nWidth;
  358. int nHeight;
  359. RECT rDlg;
  360. HDWP hdwp = BeginDeferWindowPos(0);
  361. GetWindowRect(hDlg, &rDlg);
  362. nWidth = rDlg.right - rDlg.left;
  363. nHeight = rDlg.bottom - rDlg.top;
  364. int deltaW = nWidth - g_cWidth;
  365. int deltaH = nHeight - g_cHeight;
  366. HWND hwnd;
  367. RECT r;
  368. hwnd = GetDlgItem(hDlg, IDC_ISSUES);
  369. GetWindowRect(hwnd, &r);
  370. DeferWindowPos(hdwp,
  371. hwnd,
  372. NULL,
  373. 0,
  374. 0,
  375. r.right - r.left + deltaW,
  376. r.bottom - r.top + deltaH,
  377. SWP_NOMOVE | SWP_NOZORDER);
  378. hwnd = GetDlgItem(hDlg, IDC_SOLUTIONS_STATIC);
  379. GetWindowRect(hwnd, &r);
  380. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  381. DeferWindowPos(hdwp,
  382. hwnd,
  383. NULL,
  384. r.left,
  385. r.top + deltaH,
  386. 0,
  387. 0,
  388. SWP_NOSIZE | SWP_NOZORDER);
  389. hwnd = GetDlgItem(hDlg, IDC_ISSUE_DESCRIPTION);
  390. GetWindowRect(hwnd, &r);
  391. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  392. DeferWindowPos(hdwp,
  393. hwnd,
  394. NULL,
  395. r.left,
  396. r.top + deltaH,
  397. r.right - r.left + deltaW,
  398. r.bottom - r.top,
  399. SWP_NOZORDER);
  400. EndDeferWindowPos(hdwp);
  401. g_cWidth = nWidth;
  402. g_cHeight = nHeight;
  403. }
  404. CSessionLogEntry*
  405. GetSessionLogEntryFromHItem(
  406. HTREEITEM hItem
  407. )
  408. {
  409. CSessionLogEntry* pEntry = g_pSessionLogHead;
  410. while (pEntry) {
  411. if (pEntry->hTreeItem == hItem) {
  412. return pEntry;
  413. }
  414. pEntry = pEntry->pNext;
  415. }
  416. return NULL;
  417. }
  418. void
  419. DeleteAllLogs(
  420. HWND hDlg
  421. )
  422. {
  423. ResetVerifierLog();
  424. RefreshLog(hDlg);
  425. }
  426. void
  427. ExportSelectedLog(
  428. HWND hDlg
  429. )
  430. {
  431. HTREEITEM hItem = TreeView_GetSelection(g_hwndIssues);
  432. WCHAR szName[MAX_PATH];
  433. WCHAR szExt[MAX_PATH];
  434. wstring wstrName;
  435. if (hItem == NULL) {
  436. return;
  437. }
  438. CSessionLogEntry* pSession;
  439. TVITEM ti;
  440. //
  441. // first check if this is a top-level item
  442. //
  443. pSession = GetSessionLogEntryFromHItem(hItem);
  444. if (!pSession) {
  445. return;
  446. }
  447. _wsplitpath(pSession->strLogPath, NULL, NULL, szName, szExt);
  448. wstrName = szName;
  449. wstrName += szExt;
  450. WCHAR wszFilter[] = L"Log files (*.log)\0*.log\0";
  451. OPENFILENAME ofn;
  452. WCHAR wszAppFullPath[MAX_PATH];
  453. WCHAR wszAppShortName[MAX_PATH];
  454. wstring wstrTitle;
  455. if (!AVLoadString(IDS_EXPORT_LOG_TITLE, wstrTitle)) {
  456. wstrTitle = _T("Export Log");
  457. }
  458. wcscpy(wszAppFullPath, wstrName.c_str());
  459. ofn.lStructSize = sizeof(OPENFILENAME);
  460. ofn.hwndOwner = hDlg;
  461. ofn.hInstance = NULL;
  462. ofn.lpstrFilter = wszFilter;
  463. ofn.lpstrCustomFilter = NULL;
  464. ofn.nMaxCustFilter = 0;
  465. ofn.nFilterIndex = 0;
  466. ofn.lpstrFile = wszAppFullPath;
  467. ofn.nMaxFile = MAX_PATH;
  468. ofn.lpstrFileTitle = wszAppShortName;
  469. ofn.nMaxFileTitle = MAX_PATH;
  470. ofn.lpstrInitialDir = NULL;
  471. ofn.lpstrTitle = wstrTitle.c_str();
  472. ofn.Flags = OFN_HIDEREADONLY; // hide the "open read-only" checkbox
  473. ofn.lpstrDefExt = _T("log");
  474. if ( !GetSaveFileName(&ofn) )
  475. {
  476. return;
  477. }
  478. if (CopyFile(pSession->strLogPath, wszAppFullPath, FALSE) == 0) {
  479. DWORD dwErr = GetLastError();
  480. AVErrorResourceFormat(IDS_CANT_COPY, dwErr);
  481. }
  482. }
  483. void
  484. DeleteSelectedLog(
  485. HWND hDlg
  486. )
  487. {
  488. HTREEITEM hItem = TreeView_GetSelection(g_hwndIssues);
  489. if (hItem == NULL) {
  490. return;
  491. }
  492. CSessionLogEntry* pSession;
  493. TVITEM ti;
  494. //
  495. // first check if this is a top-level item
  496. //
  497. pSession = GetSessionLogEntryFromHItem(hItem);
  498. if (!pSession) {
  499. return;
  500. }
  501. DeleteFile(pSession->strLogPath);
  502. RefreshLog(hDlg);
  503. }
  504. void
  505. HandleSelectionChanged(
  506. HWND hDlg,
  507. HTREEITEM hItem
  508. )
  509. {
  510. CProcessLogEntry* pEntry;
  511. CSessionLogEntry* pSession;
  512. TVITEM ti;
  513. //
  514. // first check if this is a top-level item
  515. //
  516. pSession = GetSessionLogEntryFromHItem(hItem);
  517. if (pSession && !g_szSingleLogFile[0]) {
  518. EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), TRUE);
  519. EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), TRUE);
  520. } else {
  521. EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), FALSE);
  522. EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE);
  523. }
  524. ti.mask = TVIF_HANDLE | TVIF_PARAM;
  525. ti.hItem = hItem;
  526. TreeView_GetItem(g_hwndIssues, &ti);
  527. if (ti.lParam == 0) {
  528. hItem = TreeView_GetParent(g_hwndIssues, hItem);
  529. ti.mask = TVIF_HANDLE | TVIF_PARAM;
  530. ti.hItem = hItem;
  531. TreeView_GetItem(g_hwndIssues, &ti);
  532. if (ti.lParam == 0) {
  533. return;
  534. }
  535. }
  536. pEntry = (CProcessLogEntry*)ti.lParam;
  537. SetDlgItemText(hDlg, IDC_ISSUE_DESCRIPTION, pEntry->strLogDescription);
  538. }
  539. // Message handler for log view dialog.
  540. LRESULT CALLBACK
  541. DlgViewLog(
  542. HWND hDlg,
  543. UINT message,
  544. WPARAM wParam,
  545. LPARAM lParam
  546. )
  547. {
  548. HDC hDC;
  549. switch (message) {
  550. case WM_INITDIALOG:
  551. {
  552. EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE);
  553. EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), FALSE);
  554. if (g_szSingleLogFile[0]) {
  555. EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_ALL), FALSE);
  556. }
  557. g_hwndIssues = GetDlgItem(hDlg, IDC_ISSUES);
  558. RECT r;
  559. GetWindowRect(hDlg, &r);
  560. g_cWidth = r.right - r.left;
  561. g_cHeight = r.bottom - r.top;
  562. RefreshLog(hDlg);
  563. return TRUE;
  564. }
  565. break;
  566. case WM_SIZE:
  567. HandleSizing(hDlg);
  568. break;
  569. case WM_GETMINMAXINFO:
  570. {
  571. MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
  572. pmmi->ptMinTrackSize.y = 300;
  573. return 0;
  574. break;
  575. }
  576. case WM_NOTIFY:
  577. if (wParam == IDC_ISSUES) {
  578. LPNMHDR pnm = (LPNMHDR)lParam;
  579. if (g_hwndIssues == NULL) {
  580. break;
  581. }
  582. switch (pnm->code) {
  583. case NM_CLICK:
  584. {
  585. TVHITTESTINFO ht;
  586. HTREEITEM hItem;
  587. GetCursorPos(&ht.pt);
  588. ScreenToClient(g_hwndIssues, &ht.pt);
  589. TreeView_HitTest(g_hwndIssues, &ht);
  590. if (ht.hItem == NULL) {
  591. break;
  592. }
  593. HandleSelectionChanged(hDlg, ht.hItem);
  594. break;
  595. }
  596. case TVN_SELCHANGED:
  597. {
  598. NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pnm;
  599. HandleSelectionChanged(hDlg, pnmtv->itemNew.hItem);
  600. break;
  601. }
  602. }
  603. } else if (wParam == IDC_ISSUE_DESCRIPTION) {
  604. LPNMHDR pnm = (LPNMHDR)lParam;
  605. if (g_hwndIssues == NULL) {
  606. break;
  607. }
  608. switch (pnm->code) {
  609. case NM_CLICK:
  610. {
  611. SHELLEXECUTEINFO sei = { 0};
  612. HTREEITEM hItem = TreeView_GetSelection(g_hwndIssues);
  613. if (hItem == NULL) {
  614. break;
  615. }
  616. CProcessLogEntry* pEntry;
  617. TVITEM ti;
  618. ti.mask = TVIF_HANDLE | TVIF_PARAM;
  619. ti.hItem = hItem;
  620. TreeView_GetItem(g_hwndIssues, &ti);
  621. if (ti.lParam == 0) {
  622. hItem = TreeView_GetParent(g_hwndIssues, hItem);
  623. ti.mask = TVIF_HANDLE | TVIF_PARAM;
  624. ti.hItem = hItem;
  625. TreeView_GetItem(g_hwndIssues, &ti);
  626. if (ti.lParam == 0) {
  627. break;
  628. }
  629. }
  630. pEntry = (CProcessLogEntry*)ti.lParam;
  631. SetDlgItemText(hDlg, IDC_ISSUE_DESCRIPTION, pEntry->strLogDescription);
  632. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  633. sei.fMask = SEE_MASK_DOENVSUBST;
  634. sei.hwnd = hDlg;
  635. sei.nShow = SW_SHOWNORMAL;
  636. sei.lpFile = pEntry->strLogURL;
  637. ShellExecuteEx(&sei);
  638. }
  639. }
  640. }
  641. break;
  642. case WM_COMMAND:
  643. switch (LOWORD (wParam)) {
  644. case IDC_BTN_DELETE_LOG:
  645. DeleteSelectedLog(hDlg);
  646. break;
  647. case IDC_BTN_DELETE_ALL:
  648. DeleteAllLogs(hDlg);
  649. break;
  650. case IDC_BTN_EXPORT_LOG:
  651. ExportSelectedLog(hDlg);
  652. break;
  653. case IDOK:
  654. case IDCANCEL:
  655. EndDialog(hDlg, LOWORD(wParam));
  656. return TRUE;
  657. break;
  658. }
  659. break;
  660. }
  661. return FALSE;
  662. }