852 lines
20 KiB
C++
852 lines
20 KiB
C++
|
|
#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;
|
|
}
|
|
|
|
|