|
|
#include "precomp.h"
#include "viewlog.h"
using namespace ShimLib;
CSessionLogEntryArray g_arrSessionLog;
TCHAR g_szSingleLogFile[MAX_PATH] = _T("");
HWND g_hwndIssues = NULL; int g_cWidth; int g_cHeight;
HWND g_hwndDetails = NULL; int g_cWidthDetails; int g_cHeightDetails;
VLOG_LEVEL g_eMinLogLevel = VLOG_LEVEL_WARNING;
CSessionLogEntry *g_pDetailsEntry = NULL;
const int MAX_INSTANCE_REPEAT = 10;
//
// forward function declarations
//
INT_PTR CALLBACK DlgViewLogDetails( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
TCHAR* fGetLine( TCHAR* szLine, int nChars, FILE* file ) { if (_fgetts(szLine, nChars, file)) { int nLen = _tcslen(szLine); while (nLen && (szLine[nLen - 1] == _T('\n') || szLine[nLen - 1] == _T('\r'))) { szLine[nLen - 1] = 0; nLen--; } return szLine; } else { return NULL; } }
BOOL IsModuleInSystem32( LPCTSTR szModule ) { TCHAR szSysDir[MAX_PATH]; TCHAR szPath[MAX_PATH];
if (!GetSystemDirectory(szSysDir, MAX_PATH)) { return FALSE; }
if (FAILED(StringCchPrintf(szPath, ARRAY_LENGTH(szPath), _T("%s\\%s"), szSysDir, szModule))) { return FALSE; }
if (GetFileAttributes(szPath) == INVALID_FILE_ATTRIBUTES) { return FALSE; }
return TRUE;
}
BOOL GetSessionLogEntry( HWND hDlg, LPCTSTR szLogFullPath, CSessionLogEntryArray& arrEntries ) { TCHAR szLine[4096]; FILE * file = NULL; SYSTEMTIME stime; CSessionLogEntry *pEntryTemp = NULL; TCHAR *szBegin = NULL; TCHAR *szEnd = NULL; BOOL bSuccess = FALSE;
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) { DPF("[GetSessionLogEntry] '%ls' does not appear to be a AppVerifier log file.", szLogFullPath);
goto out; }
{ CSessionLogEntry EntryTemp;
EntryTemp.RunTime = stime; EntryTemp.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;
EntryTemp.strExePath = szBegin;
*szEnd = 0;
//
// split the path and get the name and extension
//
_tsplitpath(EntryTemp.strExePath.c_str(), NULL, NULL, szName, szExt);
EntryTemp.strExeName = szName; EntryTemp.strExeName += szExt; } }
arrEntries.push_back(EntryTemp);
bSuccess = TRUE; } }
out:
if (file) { fclose(file); file = NULL; }
return bSuccess; }
DWORD ReadSessionLog( HWND hDlg, CSessionLogEntryArray& arrEntries ) { TCHAR szLine[4096]; FILE * file = NULL; SYSTEMTIME stime; DWORD dwEntries = 0; DWORD cchSize; TCHAR *szBegin = NULL; TCHAR *szEnd = NULL;
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
//
cchSize = GetAppVerifierLogPath(szVLog, ARRAY_LENGTH(szVLog));
if (cchSize > ARRAY_LENGTH(szVLog) || cchSize == 0) { return 0; }
StringCchCopy(szLogSearch, ARRAY_LENGTH(szLogSearch), szVLog); StringCchCatW(szLogSearch, ARRAY_LENGTH(szLogSearch), _T("\\")); StringCchCat(szLogSearch, ARRAY_LENGTH(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; }
StringCchCopy(szLogFullPath, ARRAY_LENGTH(szLogFullPath), szVLog); StringCchCat(szLogFullPath, ARRAY_LENGTH(szLogFullPath), _T("\\")); StringCchCat(szLogFullPath, ARRAY_LENGTH(szLogFullPath), FindData.cFileName);
BOOL bSuccess = GetSessionLogEntry(hDlg, szLogFullPath, arrEntries); if (bSuccess) { dwEntries++; }
nextFile:
if (!FindNextFile(hFind, &FindData)) { FindClose(hFind); hFind = INVALID_HANDLE_VALUE; } }
return dwEntries; }
void FillTreeView( HWND hDlg ) { HWND hTree = GetDlgItem(hDlg, IDC_ISSUES); CProcessLogEntry *pProcessEntry = NULL;
if (!hTree) { return; }
TreeView_DeleteAllItems(hTree);
for (CSessionLogEntry* pSLogEntry = g_arrSessionLog.begin(); pSLogEntry != g_arrSessionLog.end(); pSLogEntry++) {
//
// Add it to the tree.
//
TVINSERTSTRUCT is;
WCHAR szItem[256];
StringCchPrintf(szItem, ARRAY_LENGTH(szItem), L"%ls - %d/%d/%d %d:%02d", pSLogEntry->strExeName.c_str(), pSLogEntry->RunTime.wMonth, pSLogEntry->RunTime.wDay, pSLogEntry->RunTime.wYear, pSLogEntry->RunTime.wHour, pSLogEntry->RunTime.wMinute);
is.hParent = TVI_ROOT; is.hInsertAfter = TVI_LAST; is.item.lParam = 0; is.item.mask = TVIF_TEXT; is.item.pszText = szItem;
pSLogEntry->hTreeItem = TreeView_InsertItem(hTree, &is);
//
// Add it to the tree
//
for (pProcessEntry = pSLogEntry->arrProcessLogEntries.begin(); pProcessEntry != pSLogEntry->arrProcessLogEntries.end(); pProcessEntry++ ) {
if (pProcessEntry->dwOccurences > 0 && pProcessEntry->eLevel >= g_eMinLogLevel) {
is.hParent = pSLogEntry->hTreeItem; is.hInsertAfter = TVI_LAST; is.item.lParam = (LPARAM)pProcessEntry; is.item.mask = TVIF_TEXT | TVIF_PARAM; is.item.pszText = (LPWSTR)pProcessEntry->strLogTitle.c_str();
pProcessEntry->hTreeItem = TreeView_InsertItem(hTree, &is);
TreeView_SetItemState(hTree, pProcessEntry->hTreeItem, INDEXTOSTATEIMAGEMASK(pProcessEntry->eLevel + 1), TVIS_STATEIMAGEMASK);
DWORD * pdwInstance; DWORD dwInstances = 0;
for (pdwInstance = pProcessEntry->arrLogInstances.begin(); pdwInstance != pProcessEntry->arrLogInstances.end(); pdwInstance++ ) {
wstring strInstText; WCHAR szTemp[50];
CProcessLogInstance *pInstance = &(pSLogEntry->arrProcessLogInstances[*pdwInstance]);
//
// check to see if we should filter out the logs from system DLLs
// Complicated test - we filter system dlls, but not the EXE under test.
// Filtering is only performed if we're not in NTDEV internal mode
//
BOOL bFilterSystem = FALSE; if (!g_bInternalMode && IsModuleInSystem32(pInstance->strModule.c_str()) && (_tcsicmp(pInstance->strModule.c_str(), pSLogEntry->strExeName.c_str()) != 0)) {
bFilterSystem = TRUE; }
if (!pInstance->bDuplicate && pInstance->eLevel >= g_eMinLogLevel && !bFilterSystem) { if (pInstance->strModule != L"?" && pInstance->dwOffset != 0) { StringCchPrintf(szTemp, ARRAY_LENGTH(szTemp), L"(%s:%08X) ", pInstance->strModule.c_str(), pInstance->dwOffset); strInstText += szTemp; } strInstText += pInstance->strText;
if (pInstance->dwNumRepeats > 1) { StringCchPrintf(szTemp, ARRAY_LENGTH(szTemp), L" [%dx]", pInstance->dwNumRepeats); strInstText += szTemp; }
is.hParent = pProcessEntry->hTreeItem; is.hInsertAfter = TVI_LAST; is.item.lParam = 0; is.item.mask = TVIF_TEXT; is.item.pszText = (LPWSTR)(strInstText.c_str());
HTREEITEM hItem = TreeView_InsertItem(hTree, &is); dwInstances++;
TreeView_SetItemState(hTree, hItem, INDEXTOSTATEIMAGEMASK(pInstance->eLevel + 1), TVIS_STATEIMAGEMASK); } }
if (dwInstances == 0) { //
// we didn't end up adding any children, so delete this entry
//
TreeView_DeleteItem(hTree, pProcessEntry->hTreeItem); pProcessEntry->hTreeItem = NULL; } } } } }
DWORD ReadProcessLog(HWND hDlg, CSessionLogEntry* pSLogEntry) { static TCHAR szLine[4096]; FILE * file = NULL; CProcessLogEntry *pProcessEntry = NULL; static TCHAR szShimName[4096]; DWORD dwEntries = 0; TCHAR * szTemp = NULL; DWORD dwEntry = 0; TCHAR *szBegin = NULL;
HWND hTree = GetDlgItem(hDlg, IDC_ISSUES);
if (!pSLogEntry) { return 0; }
file = _tfopen(pSLogEntry->strLogPath.c_str(), _T("rt"));
if (!file) { return 0; }
//
// first get the headers
//
szTemp = fGetLine(szLine, ARRAY_LENGTH(szLine), file); while (szTemp) {
if (szLine[0] != _T('#')) { goto nextLine; }
//
// relatively simplistic guard against overflow in szShimName in the scanf, below
//
if (_tcslen(szLine) >= ARRAY_LENGTH(szShimName)) { goto nextLine; }
if (_stscanf(szLine, _T("# LOGENTRY %s %d '"), szShimName, &dwEntry) == 2) { if (pProcessEntry) { pSLogEntry->arrProcessLogEntries.push_back(*pProcessEntry);
delete pProcessEntry; 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.size()) { 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, ARRAY_LENGTH(szLine), file);
}
//
// if we've still got an entry in process, save it
//
if (pProcessEntry) { pSLogEntry->arrProcessLogEntries.push_back(*pProcessEntry);
delete pProcessEntry; pProcessEntry = NULL;
dwEntries++; }
//
// go back to the beginning and read the log lines
//
if (fseek(file, 0, SEEK_SET) != 0) { return 0; }
szTemp = fGetLine(szLine, ARRAY_LENGTH(szLine), file);
while (szTemp) { CProcessLogEntry *pEntry; static TCHAR szName[4096]; DWORD dwOffset = 0; static TCHAR szModule[4096]; VLOG_LEVEL eLevel = VLOG_LEVEL_ERROR; DWORD dwLen;
StringCchCopyW(szModule, ARRAY_LENGTH(szModule), L"<unknown>");
if (szLine[0] != _T('|')) { goto nextInstance; }
//
// relatively simplistic guard against overflow in the scanf, below
//
dwLen = _tcslen(szLine); if (dwLen >= ARRAY_LENGTH(szName) || dwLen >= ARRAY_LENGTH(szModule) ) { goto nextLine; }
int nFields = _stscanf(szLine, _T("| %s %d | %d %s %x"), szName, &dwEntry, &eLevel, szModule, &dwOffset); if (nFields >= 2) { BOOL bFound = FALSE; CProcessLogInstance Instance;
Instance.strModule = szModule; Instance.eLevel = eLevel; Instance.dwOffset = dwOffset;
szBegin = _tcschr(szLine, _T('\'')); if (szBegin) { szBegin++;
Instance.strText = szBegin; }
//
// Get the associated entry (header) for this log instance
//
for (pEntry = pSLogEntry->arrProcessLogEntries.begin(); pEntry != pSLogEntry->arrProcessLogEntries.end(); pEntry++ ) {
if (pEntry->strShimName == szName && pEntry->dwLogNum == dwEntry) { bFound = TRUE;
break; }
} if (!bFound) { //
// no matching log entry found
//
DPF("[ReadProcessLog] Mo matching log header found for log instance '%ls'.", Instance.strText.c_str()); pEntry = NULL; goto nextInstance; }
Instance.dwProcessLogEntry = pEntry - pSLogEntry->arrProcessLogEntries.begin();
//
// check to see if this is a repeat of a previous entry
//
for (CProcessLogInstance *pInstance = pSLogEntry->arrProcessLogInstances.begin(); pInstance != pSLogEntry->arrProcessLogInstances.end(); pInstance++) { if (pInstance->strModule == Instance.strModule && pInstance->dwOffset == Instance.dwOffset && pInstance->strText == Instance.strText && pInstance->dwProcessLogEntry == Instance.dwProcessLogEntry && pInstance->bDuplicate == FALSE) {
//
// we won't save more than a certain number of repeats
//
if (pInstance->dwNumRepeats >= MAX_INSTANCE_REPEAT) { goto nextInstance; }
//
// it's a match, so count up the repeats on the one we found, and mark
// this one duplicate
//
pInstance->dwNumRepeats++; Instance.bDuplicate = TRUE;
break; } }
//
// save the instance in the chronological log
//
pSLogEntry->arrProcessLogInstances.push_back(Instance);
//
// update the cross-pointer in the entry object
//
pEntry->arrLogInstances.push_back(pSLogEntry->arrProcessLogInstances.size() - 1);
//
// now update the entry object's count of instances
//
pEntry->dwOccurences++;
//
// update the level
//
if (pEntry->eLevel < Instance.eLevel) { pEntry->eLevel = Instance.eLevel; } }
nextInstance:
szTemp = fGetLine(szLine, ARRAY_LENGTH(szLine), file);
}
out: 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);
g_arrSessionLog.clear();
if (g_szSingleLogFile[0]) { GetSessionLogEntry(hDlg, g_szSingleLogFile, g_arrSessionLog); SetLogDialogCaption(hDlg, IDS_LOG_TITLE_SINGLE, g_szSingleLogFile); } else { ReadSessionLog(hDlg, g_arrSessionLog); SetLogDialogCaption(hDlg, IDS_LOG_TITLE_LOCAL, NULL); }
for (CSessionLogEntry* pEntry = g_arrSessionLog.begin(); pEntry != g_arrSessionLog.end(); pEntry++ ) {
ReadProcessLog(hDlg, pEntry); }
FillTreeView(hDlg);
EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE);
}
void InitListViewDetails(HWND hDlg) { DWORD dwLine;
static const WCHAR *aszSeverity[3] = { L"Info", L"Warning", L"Error" };
if (!g_pDetailsEntry || !g_hwndDetails) { return; }
ListView_SetExtendedListViewStyleEx(g_hwndDetails, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; lvc.cx = 40; lvc.iSubItem = 0; lvc.pszText = L"Line";
ListView_InsertColumn(g_hwndDetails, 0, &lvc);
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; lvc.cx = 80; lvc.iSubItem = 1; lvc.pszText = L"Module";
ListView_InsertColumn(g_hwndDetails, 1, &lvc);
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; lvc.cx = 70; lvc.iSubItem = 2; lvc.pszText = L"Offset";
ListView_InsertColumn(g_hwndDetails, 2, &lvc);
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; lvc.cx = 70; lvc.iSubItem = 3; lvc.pszText = L"Severity";
ListView_InsertColumn(g_hwndDetails, 3, &lvc);
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; lvc.cx = 900; lvc.iSubItem = 4; lvc.pszText = L"Text";
ListView_InsertColumn(g_hwndDetails, 4, &lvc);
CProcessLogInstance* pInstance;
for (pInstance = g_pDetailsEntry->arrProcessLogInstances.begin(), dwLine = 0; pInstance != g_pDetailsEntry->arrProcessLogInstances.end(); pInstance++, dwLine++ ) {
WCHAR szTemp[1024]; LVITEM lvi;
//
// if we're in external mode, filter out logs from modules in system32
//
if (!g_bInternalMode && IsModuleInSystem32(pInstance->strModule.c_str()) && (_tcsicmp(pInstance->strModule.c_str(), g_pDetailsEntry->strExeName.c_str()) != 0)) {
dwLine--;
continue; }
szTemp[0] = 0;
StringCchPrintf(szTemp, ARRAY_LENGTH(szTemp), L"%04d", dwLine);
lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.pszText = szTemp; lvi.lParam = (LPARAM)pInstance; lvi.iItem = 99999; lvi.iSubItem = 0;
int nItem = ListView_InsertItem(g_hwndDetails, &lvi);
if (nItem == -1) { DPF("[InitListViewDetails] Couldn't add line %d.", dwLine); return; }
if (pInstance->strModule != L"?" && pInstance->dwOffset != 0) { ListView_SetItemText(g_hwndDetails, nItem, 1, (LPWSTR)pInstance->strModule.c_str()); }
if (pInstance->dwOffset != 0) { StringCchPrintf(szTemp, ARRAY_LENGTH(szTemp), L"%08X", pInstance->dwOffset);
ListView_SetItemText(g_hwndDetails, nItem, 2, szTemp); }
if (pInstance->eLevel <= VLOG_LEVEL_ERROR) { StringCchCopy(szTemp, ARRAY_LENGTH(szTemp), aszSeverity[pInstance->eLevel]); } else { StringCchCopy(szTemp, ARRAY_LENGTH(szTemp), L"<unknown>"); }
ListView_SetItemText(g_hwndDetails, nItem, 3, szTemp);
CProcessLogEntry* pEntry = &(g_pDetailsEntry->arrProcessLogEntries[pInstance->dwProcessLogEntry]);
StringCchPrintf(szTemp, ARRAY_LENGTH(szTemp), L"%s - %s", pEntry->strLogTitle.c_str(), pInstance->strText.c_str());
ListView_SetItemText(g_hwndDetails, nItem, 4, szTemp); }
}
void HandleSizing( HWND hDlg ) { int nWidth; int nHeight; RECT rDlg;
HDWP hdwp = BeginDeferWindowPos(0);
if (!hdwp) { return; }
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; }
void HandleSizingDetails( HWND hDlg ) { int nWidth; int nHeight; RECT rDlg;
HDWP hdwp = BeginDeferWindowPos(0);
if (!hdwp) { return; }
GetWindowRect(hDlg, &rDlg);
nWidth = rDlg.right - rDlg.left; nHeight = rDlg.bottom - rDlg.top;
int deltaW = nWidth - g_cWidthDetails; int deltaH = nHeight - g_cHeightDetails;
HWND hwnd; RECT r;
hwnd = GetDlgItem(hDlg, IDC_LIST_DETAILS);
GetWindowRect(hwnd, &r);
DeferWindowPos(hdwp, hwnd, NULL, 0, 0, r.right - r.left + deltaW, r.bottom - r.top + deltaH, SWP_NOMOVE | SWP_NOZORDER);
EndDeferWindowPos(hdwp);
g_cWidthDetails = nWidth; g_cHeightDetails = nHeight; }
CSessionLogEntry* GetSessionLogEntryFromHItem( HTREEITEM hItem ) { for (CSessionLogEntry* pEntry = g_arrSessionLog.begin(); pEntry != g_arrSessionLog.end(); pEntry++ ) {
if (pEntry->hTreeItem == hItem) { return pEntry; } }
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.c_str(), 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"); }
StringCchCopy(wszAppFullPath, ARRAY_LENGTH(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.c_str(), 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.c_str());
RefreshLog(hDlg);
}
void OpenSelectedLogDetails( 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
//
g_pDetailsEntry = GetSessionLogEntryFromHItem(hItem); if (!g_pDetailsEntry) { return; }
DialogBox(g_hInstance, (LPCTSTR)IDD_VIEW_LOG_DETAIL, hDlg, DlgViewLogDetails);
g_pDetailsEntry = NULL; }
void SetDescriptionText( HWND hDlg, CProcessLogEntry* pEntry ) { wstring strText;
if (pEntry) { strText = pEntry->strLogDescription; if (pEntry->strLogURL.size()) { wstring strIntro, strLink;
if (AVLoadString(IDS_URL_INTRO, strIntro) && AVLoadString(IDS_URL_LINK, strLink)) { strText += L" " + strIntro + L" <A HREF=\"" + pEntry->strLogURL + L"\">" + strLink + L"</A>"; } } }
if (strText.size() == 0) { AVLoadString(IDS_SOLUTION_DEFAULT, strText); }
SetDlgItemText(hDlg, IDC_ISSUE_DESCRIPTION, strText.c_str()); }
void HandleSelectionChanged( HWND hDlg, HTREEITEM hItem ) { CProcessLogEntry* pEntry = NULL; CSessionLogEntry* pSession = NULL; TVITEM ti; wstring strText;
if (!hDlg) { return; } if (!hItem) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_VIEW_DETAILS), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_EXPORT_LOG), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_LOG), FALSE); goto out; }
//
// first check if this is a top-level item
//
pSession = GetSessionLogEntryFromHItem(hItem); if (pSession) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_VIEW_DETAILS), TRUE); if (!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); } } else { EnableWindow(GetDlgItem(hDlg, IDC_BTN_VIEW_DETAILS), 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) { goto out; } }
pEntry = (CProcessLogEntry*)ti.lParam;
out:
SetDescriptionText(hDlg, pEntry); }
// Message handler for log view dialog.
INT_PTR 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); EnableWindow(GetDlgItem(hDlg, IDC_BTN_VIEW_DETAILS), FALSE);
if (g_eMinLogLevel == VLOG_LEVEL_INFO) { CheckRadioButton(hDlg, IDC_SHOW_ALL, IDC_SHOW_ERRORS, IDC_SHOW_ALL); } else { CheckRadioButton(hDlg, IDC_SHOW_ALL, IDC_SHOW_ERRORS, IDC_SHOW_ERRORS); }
if (g_szSingleLogFile[0]) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_DELETE_ALL), FALSE); }
g_hwndIssues = GetDlgItem(hDlg, IDC_ISSUES);
HIMAGELIST hImage = ImageList_LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_BULLETS), 16, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_LOADTRANSPARENT);
if (hImage != NULL) { TreeView_SetImageList(g_hwndIssues, hImage, TVSIL_STATE); }
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);
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 = NULL; 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;
SetDescriptionText(hDlg, pEntry);
if (pEntry) { sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = SEE_MASK_DOENVSUBST; sei.hwnd = hDlg; sei.nShow = SW_SHOWNORMAL; sei.lpFile = (LPWSTR)(pEntry->strLogURL.c_str());
ShellExecuteEx(&sei); } } } } break;
case WM_COMMAND: switch (LOWORD (wParam)) { case IDC_SHOW_ERRORS: g_eMinLogLevel = VLOG_LEVEL_WARNING; FillTreeView(hDlg); break;
case IDC_SHOW_ALL: g_eMinLogLevel = VLOG_LEVEL_INFO; FillTreeView(hDlg); break;
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 IDC_BTN_VIEW_DETAILS: OpenSelectedLogDetails(hDlg); break;
case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; break; } break;
} return FALSE; }
int CALLBACK DetailsCompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { WCHAR szTemp1[256], szTemp2[256];
szTemp1[0] = 0; szTemp2[0] = 0;
ListView_GetItemText(g_hwndDetails, lParam1, lParamSort, szTemp1, ARRAY_LENGTH(szTemp1)); ListView_GetItemText(g_hwndDetails, lParam2, lParamSort, szTemp2, ARRAY_LENGTH(szTemp2));
return _wcsicmp(szTemp1, szTemp2); }
// Message handler for details log view dialog.
INT_PTR CALLBACK DlgViewLogDetails( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { HDC hDC;
switch (message) { case WM_INITDIALOG: { g_hwndDetails = GetDlgItem(hDlg, IDC_LIST_DETAILS);
RECT r;
GetWindowRect(hDlg, &r);
g_cWidthDetails = r.right - r.left; g_cHeightDetails = r.bottom - r.top;
InitListViewDetails(hDlg);
return TRUE; } break;
case WM_SIZE: HandleSizingDetails(hDlg); break;
case WM_GETMINMAXINFO: { MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
pmmi->ptMinTrackSize.y = 300;
return 0; break; }
case WM_NOTIFY: if (wParam == IDC_LIST_DETAILS) {
LPNMHDR pnm = (LPNMHDR)lParam;
if (g_hwndIssues == NULL) { break; }
switch (pnm->code) { case LVN_COLUMNCLICK: { LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
ListView_SortItemsEx(g_hwndDetails, DetailsCompareFunc, pnmv->iSubItem); break; } } } break;
case WM_COMMAND: switch (LOWORD (wParam)) {
case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; break; } break;
} return FALSE; }
|