|
|
#include "precomp.h"
#include "viewlog.h"
CSessionLogEntry* g_pSessionLogHead = NULL;
TCHAR g_szSingleLogFile[MAX_PATH] = _T("");
HWND g_hwndIssues; int g_cWidth; int g_cHeight;
TCHAR* fGetLine( TCHAR* szLine, int nChars, FILE* file ) { if (_fgetts(szLine, nChars, file)) { int nLen = _tcslen(szLine); while (szLine[nLen - 1] == _T('\n') || szLine[nLen - 1] == _T('\r')) { szLine[nLen - 1] = 0; nLen--; } return szLine; } else { return NULL; } }
CSessionLogEntry* GetSessionLogEntry( HWND hDlg, LPCTSTR szLogFullPath ) { TCHAR szLine[4096]; FILE * file = NULL; SYSTEMTIME stime; CSessionLogEntry *pEntryTemp = NULL; TCHAR *szBegin = NULL; TCHAR *szEnd = NULL;
HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
file = _tfopen(szLogFullPath, _T("rt"));
if (!file) { goto out; }
if (fGetLine(szLine, 4096, file)) {
ZeroMemory(&stime, sizeof(SYSTEMTIME));
int nFields = _stscanf(szLine, _T("# LOG_BEGIN %hd/%hd/%hd %hd:%hd:%hd"), &stime.wMonth, &stime.wDay, &stime.wYear, &stime.wHour, &stime.wMinute, &stime.wSecond);
//
// if we parsed that line properly, then we've got a valid line.
// Parse it.
//
if (nFields == 6) { pEntryTemp = new CSessionLogEntry; if (!pEntryTemp) { goto out; } pEntryTemp->RunTime = stime; pEntryTemp->strLogPath = szLogFullPath;
//
// get the log file and exe path
//
szBegin = _tcschr(szLine, _T('\'')); if (szBegin) { szBegin++; szEnd = _tcschr(szBegin, _T('\'')); if (szEnd) { TCHAR szName[MAX_PATH]; TCHAR szExt[_MAX_EXT]; *szEnd = 0;
pEntryTemp->strExePath = szBegin;
*szEnd = 0;
//
// split the path and get the name and extension
//
_tsplitpath(pEntryTemp->strExePath, NULL, NULL, szName, szExt);
pEntryTemp->strExeName = szName; pEntryTemp->strExeName += szExt; } }
//
// Add it to the tree.
//
TVINSERTSTRUCT is;
WCHAR szItem[256];
wsprintf(szItem, L"%s - %d/%d/%d %d:%02d", pEntryTemp->strExeName, pEntryTemp->RunTime.wMonth, pEntryTemp->RunTime.wDay, pEntryTemp->RunTime.wYear, pEntryTemp->RunTime.wHour, pEntryTemp->RunTime.wMinute);
is.hParent = TVI_ROOT; is.hInsertAfter = TVI_LAST; is.item.lParam = 0; is.item.mask = TVIF_TEXT; is.item.pszText = szItem;
pEntryTemp->hTreeItem = TreeView_InsertItem(hTree, &is); } }
out:
if (file) { fclose(file); file = NULL; }
return pEntryTemp; }
DWORD ReadSessionLog(HWND hDlg, CSessionLogEntry **ppSessionLog) { TCHAR szLine[4096]; FILE * file = NULL; SYSTEMTIME stime; CSessionLogEntry *pEntryTemp = NULL; DWORD dwEntries = 0; TCHAR *szBegin = NULL; TCHAR *szEnd = NULL; CSessionLogEntry **ppEnd = ppSessionLog;
HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
TCHAR szVLog[MAX_PATH]; TCHAR szLogFullPath[MAX_PATH];
WIN32_FIND_DATA FindData; HANDLE hFind = INVALID_HANDLE_VALUE; TCHAR szLogSearch[MAX_PATH];
//
// BUGBUG -- this is cheesy, but it's the fastest way to make the change
// to remove session.log. Going forward, we should combine these two functions
// into one, and switch to vectors instead of linked lists
//
GetSystemWindowsDirectory(szVLog, MAX_PATH); _tcscat(szVLog, _T("\\AppPatch\\VLog\\")); _tcscpy(szLogSearch, szVLog); _tcscat(szLogSearch, _T("*.log"));
//
// enumerate all the logs and make entries for them
//
hFind = FindFirstFile(szLogSearch, &FindData); while (hFind != INVALID_HANDLE_VALUE) {
//
// make sure to exclude session.log, in case we're using older shims
//
if (_tcsicmp(FindData.cFileName, _T("session.log")) == 0) { goto nextFile; }
_tcscpy(szLogFullPath, szVLog); _tcscat(szLogFullPath, FindData.cFileName);
pEntryTemp = GetSessionLogEntry(hDlg, szLogFullPath); if (pEntryTemp) { //
// we want these in the order they appear in the log,
// so we add to the end rather than the beginning.
//
*ppEnd = pEntryTemp; ppEnd = &(pEntryTemp->pNext);
dwEntries++; }
nextFile:
if (!FindNextFile(hFind, &FindData)) { FindClose(hFind); hFind = INVALID_HANDLE_VALUE; } }
return dwEntries; }
DWORD ReadProcessLog(HWND hDlg, CSessionLogEntry* pSLogEntry) { TCHAR szLine[4096]; FILE * file = NULL; CProcessLogEntry *pProcessEntry = NULL; TCHAR szShimName[256]; DWORD dwEntries = 0; TCHAR * szTemp = NULL; DWORD dwEntry = 0; TCHAR *szBegin = NULL; CProcessLogEntry **ppProcessTail = &(pSLogEntry->pProcessLog);
HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
if (!pSLogEntry) { return 0; }
file = _tfopen(pSLogEntry->strLogPath, _T("rt"));
if (!file) { return 0; }
//
// first get the headers
//
szTemp = fGetLine(szLine, 4096, file); while (szTemp) {
if (szLine[0] == _T('|')) { break; } if (szLine[0] != _T('#')) { goto nextLine; }
if (_stscanf(szLine, _T("# LOGENTRY %s %d '"), szShimName, &dwEntry) == 2) { if (pProcessEntry) { *ppProcessTail = pProcessEntry; ppProcessTail = &(pProcessEntry->pNext); pProcessEntry = NULL; dwEntries++; }
pProcessEntry = new CProcessLogEntry; if (!pProcessEntry) { goto out; } pProcessEntry->strShimName = szShimName; pProcessEntry->dwLogNum = dwEntry;
szBegin = _tcschr(szLine, _T('\'')); if (szBegin) { szBegin++; pProcessEntry->strLogTitle = szBegin; } } else if (_tcsncmp(szLine, _T("# DESCRIPTION BEGIN"), 19) == 0) { szTemp = fGetLine(szLine, 4096, file); while (szTemp) { if (_tcsncmp(szLine, _T("# DESCRIPTION END"), 17) == 0) { break; } if (pProcessEntry) {
//
// throw in a carriage return if necessary
//
if (pProcessEntry->strLogDescription.GetLength()) { pProcessEntry->strLogDescription += _T("\n"); } pProcessEntry->strLogDescription += szLine; } szTemp = fGetLine(szLine, 4096, file); } } else if (_tcsncmp(szLine, _T("# URL '"), 7) == 0) { szBegin = _tcschr(szLine, _T('\'')); if (szBegin) { szBegin++; pProcessEntry->strLogURL = szBegin; } }
nextLine: szTemp = fGetLine(szLine, 4096, file);
}
//
// if we've still got an entry in process, save it
//
if (pProcessEntry) { *ppProcessTail = pProcessEntry; ppProcessTail = &(pProcessEntry->pNext);
pProcessEntry = NULL; dwEntries++; }
//
// now read all the log lines
//
while (szTemp) { CProcessLogEntry *pEntry; TCHAR szName[256];
int nFields = _stscanf(szLine, _T("| %s %d '"), szName, &dwEntry); if (nFields == 2) { BOOL bFound = FALSE; pEntry = pSLogEntry->pProcessLog; while (pEntry) { if (pEntry->strShimName == szName && pEntry->dwLogNum == dwEntry) { pEntry->dwOccurences++; bFound = TRUE;
//
// here's where we would save the occurrence info
//
szBegin = _tcschr(szLine, _T('\'')); if (szBegin) { szBegin++;
pEntry->arrProblems.Add(szBegin); }
break; }
pEntry = pEntry->pNext; }
if (!bFound) { //
// need to dump a debug string -- no matching log entry found
//
; } }
szTemp = fGetLine(szLine, 4096, file);
}
out: //
// Add it to the tree
//
pProcessEntry = pSLogEntry->pProcessLog;
while (pProcessEntry != NULL) { if (pProcessEntry->dwOccurences > 0) { TVINSERTSTRUCT is;
is.hParent = pSLogEntry->hTreeItem; is.hInsertAfter = TVI_LAST; is.item.lParam = (LPARAM)pProcessEntry; is.item.mask = TVIF_TEXT | TVIF_PARAM; is.item.pszText = pProcessEntry->strLogTitle.GetBuffer(0);
pProcessEntry->hTreeItem = TreeView_InsertItem(hTree, &is);
for (int i = 0; i < pProcessEntry->arrProblems.GetSize(); i++) { is.hParent = pProcessEntry->hTreeItem; is.hInsertAfter = TVI_LAST; is.item.lParam = 0; is.item.mask = TVIF_TEXT; is.item.pszText = pProcessEntry->arrProblems.GetAt(i).GetBuffer(0);
TreeView_InsertItem(hTree, &is); } }
pProcessEntry = pProcessEntry->pNext; }
if (file) { fclose(file); file = NULL; }
return dwEntries;
}
void SetLogDialogCaption(HWND hDlg, ULONG ulCaptionID, LPCWSTR szAdditional) { wstring wstrCaption;
if (AVLoadString(ulCaptionID, wstrCaption)) { if (szAdditional) { wstrCaption += szAdditional; }
SetWindowText(hDlg, wstrCaption.c_str()); } }
void RefreshLog(HWND hDlg) { TreeView_DeleteAllItems(g_hwndIssues);
if (g_pSessionLogHead) { delete g_pSessionLogHead; g_pSessionLogHead = NULL; }
if (g_szSingleLogFile[0]) { g_pSessionLogHead = GetSessionLogEntry(hDlg, g_szSingleLogFile); SetLogDialogCaption(hDlg, IDS_LOG_TITLE_SINGLE, g_szSingleLogFile); } else { ReadSessionLog(hDlg, &g_pSessionLogHead); SetLogDialogCaption(hDlg, IDS_LOG_TITLE_LOCAL, NULL); }
CSessionLogEntry* pEntry = g_pSessionLogHead;
while (pEntry) { ReadProcessLog(hDlg, pEntry); pEntry = pEntry->pNext; }
EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE);
}
void HandleSizing( HWND hDlg ) { int nWidth; int nHeight; RECT rDlg;
HDWP hdwp = BeginDeferWindowPos(0); GetWindowRect(hDlg, &rDlg);
nWidth = rDlg.right - rDlg.left; nHeight = rDlg.bottom - rDlg.top;
int deltaW = nWidth - g_cWidth; int deltaH = nHeight - g_cHeight;
HWND hwnd; RECT r;
hwnd = GetDlgItem(hDlg, IDC_ISSUES);
GetWindowRect(hwnd, &r);
DeferWindowPos(hdwp, hwnd, NULL, 0, 0, r.right - r.left + deltaW, r.bottom - r.top + deltaH, SWP_NOMOVE | SWP_NOZORDER);
hwnd = GetDlgItem(hDlg, IDC_SOLUTIONS_STATIC);
GetWindowRect(hwnd, &r); MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp, hwnd, NULL, r.left, r.top + deltaH, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
hwnd = GetDlgItem(hDlg, IDC_ISSUE_DESCRIPTION);
GetWindowRect(hwnd, &r); MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp, hwnd, NULL, r.left, r.top + deltaH, r.right - r.left + deltaW, r.bottom - r.top, SWP_NOZORDER);
EndDeferWindowPos(hdwp); g_cWidth = nWidth; g_cHeight = nHeight; }
CSessionLogEntry* GetSessionLogEntryFromHItem( HTREEITEM hItem ) { CSessionLogEntry* pEntry = g_pSessionLogHead;
while (pEntry) { if (pEntry->hTreeItem == hItem) { return pEntry; } pEntry = pEntry->pNext; }
return NULL; }
void DeleteAllLogs( HWND hDlg ) { ResetVerifierLog();
RefreshLog(hDlg); }
void ExportSelectedLog( HWND hDlg ) { HTREEITEM hItem = TreeView_GetSelection(g_hwndIssues); WCHAR szName[MAX_PATH]; WCHAR szExt[MAX_PATH]; wstring wstrName;
if (hItem == NULL) { return; }
CSessionLogEntry* pSession; TVITEM ti;
//
// first check if this is a top-level item
//
pSession = GetSessionLogEntryFromHItem(hItem); if (!pSession) { return; }
_wsplitpath(pSession->strLogPath, NULL, NULL, szName, szExt);
wstrName = szName; wstrName += szExt;
WCHAR wszFilter[] = L"Log files (*.log)\0*.log\0"; OPENFILENAME ofn; WCHAR wszAppFullPath[MAX_PATH]; WCHAR wszAppShortName[MAX_PATH]; wstring wstrTitle;
if (!AVLoadString(IDS_EXPORT_LOG_TITLE, wstrTitle)) { wstrTitle = _T("Export Log"); }
wcscpy(wszAppFullPath, wstrName.c_str());
ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hDlg; ofn.hInstance = NULL; ofn.lpstrFilter = wszFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = wszAppFullPath; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = wszAppShortName; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = wstrTitle.c_str(); ofn.Flags = OFN_HIDEREADONLY; // hide the "open read-only" checkbox
ofn.lpstrDefExt = _T("log");
if ( !GetSaveFileName(&ofn) ) { return; }
if (CopyFile(pSession->strLogPath, wszAppFullPath, FALSE) == 0) { DWORD dwErr = GetLastError();
AVErrorResourceFormat(IDS_CANT_COPY, dwErr); } }
void DeleteSelectedLog( HWND hDlg ) { HTREEITEM hItem = TreeView_GetSelection(g_hwndIssues);
if (hItem == NULL) { return; }
CSessionLogEntry* pSession; TVITEM ti;
//
// first check if this is a top-level item
//
pSession = GetSessionLogEntryFromHItem(hItem); if (!pSession) { return; }
DeleteFile(pSession->strLogPath);
RefreshLog(hDlg);
}
void HandleSelectionChanged( HWND hDlg, HTREEITEM hItem ) { CProcessLogEntry* pEntry; CSessionLogEntry* pSession; TVITEM ti;
//
// first check if this is a top-level item
//
pSession = GetSessionLogEntryFromHItem(hItem); if (pSession && !g_szSingleLogFile[0]) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), TRUE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), TRUE); } else { EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE); }
ti.mask = TVIF_HANDLE | TVIF_PARAM; ti.hItem = hItem;
TreeView_GetItem(g_hwndIssues, &ti);
if (ti.lParam == 0) {
hItem = TreeView_GetParent(g_hwndIssues, hItem);
ti.mask = TVIF_HANDLE | TVIF_PARAM; ti.hItem = hItem;
TreeView_GetItem(g_hwndIssues, &ti);
if (ti.lParam == 0) { return; } }
pEntry = (CProcessLogEntry*)ti.lParam;
SetDlgItemText(hDlg, IDC_ISSUE_DESCRIPTION, pEntry->strLogDescription); }
// Message handler for log view dialog.
LRESULT CALLBACK DlgViewLog( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { HDC hDC;
switch (message) { case WM_INITDIALOG: { EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), FALSE);
if (g_szSingleLogFile[0]) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_ALL), FALSE); }
g_hwndIssues = GetDlgItem(hDlg, IDC_ISSUES);
RECT r;
GetWindowRect(hDlg, &r);
g_cWidth = r.right - r.left; g_cHeight = r.bottom - r.top;
RefreshLog(hDlg);
return TRUE; } break;
case WM_SIZE: HandleSizing(hDlg); break;
case WM_GETMINMAXINFO: { MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
pmmi->ptMinTrackSize.y = 300;
return 0; break; }
case WM_NOTIFY: if (wParam == IDC_ISSUES) {
LPNMHDR pnm = (LPNMHDR)lParam;
if (g_hwndIssues == NULL) { break; }
switch (pnm->code) { case NM_CLICK: { TVHITTESTINFO ht; HTREEITEM hItem;
GetCursorPos(&ht.pt);
ScreenToClient(g_hwndIssues, &ht.pt);
TreeView_HitTest(g_hwndIssues, &ht);
if (ht.hItem == NULL) { break; }
HandleSelectionChanged(hDlg, ht.hItem); break; } case TVN_SELCHANGED: { NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pnm;
HandleSelectionChanged(hDlg, pnmtv->itemNew.hItem); break; } } } else if (wParam == IDC_ISSUE_DESCRIPTION) { LPNMHDR pnm = (LPNMHDR)lParam;
if (g_hwndIssues == NULL) { break; }
switch (pnm->code) { case NM_CLICK: { SHELLEXECUTEINFO sei = { 0};
HTREEITEM hItem = TreeView_GetSelection(g_hwndIssues);
if (hItem == NULL) { break; }
CProcessLogEntry* pEntry; TVITEM ti;
ti.mask = TVIF_HANDLE | TVIF_PARAM; ti.hItem = hItem;
TreeView_GetItem(g_hwndIssues, &ti);
if (ti.lParam == 0) { hItem = TreeView_GetParent(g_hwndIssues, hItem);
ti.mask = TVIF_HANDLE | TVIF_PARAM; ti.hItem = hItem;
TreeView_GetItem(g_hwndIssues, &ti);
if (ti.lParam == 0) { break; } }
pEntry = (CProcessLogEntry*)ti.lParam;
SetDlgItemText(hDlg, IDC_ISSUE_DESCRIPTION, pEntry->strLogDescription);
sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = SEE_MASK_DOENVSUBST; sei.hwnd = hDlg; sei.nShow = SW_SHOWNORMAL; sei.lpFile = pEntry->strLogURL;
ShellExecuteEx(&sei); } } } break;
case WM_COMMAND: switch (LOWORD (wParam)) { case IDC_BTN_DELETE_LOG: DeleteSelectedLog(hDlg); break;
case IDC_BTN_DELETE_ALL: DeleteAllLogs(hDlg); break;
case IDC_BTN_EXPORT_LOG: ExportSelectedLog(hDlg); break; case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; break; } break;
} return FALSE; }
|