mirror of
https://github.com/reactos/reactos.git
synced 2024-08-27 05:38:41 +00:00
![Hermès Bélusca-Maïto](/assets/img/avatar_default.png)
CORE-11637, CORE-12269 - Implement support for remote connections to NT computers to view their event logs (and the event logs settings). For the moment the remote computer name specification is is only available via the command-line. Note that the paths to the event log files need also to be translated to network-share format. - Implement loading and saving the settings of the event viewer. - Implement showing/hiding the events description pane, the ListView grid, and whether or not to save the EventViewer settings. - Handle hypertext link click handling for the RichEdit edit box of the events description dialog.
945 lines
28 KiB
C
945 lines
28 KiB
C
/*
|
|
* PROJECT: ReactOS Event Log Viewer
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: base/applications/mscutils/eventvwr/evtdetctl.c
|
|
* PURPOSE: Event Details Control
|
|
* PROGRAMMERS: Marc Piulachs (marc.piulachs at codexchange [dot] net)
|
|
* Eric Kohl
|
|
* Hermes Belusca-Maito
|
|
*/
|
|
|
|
#include "eventvwr.h"
|
|
#include "evtdetctl.h"
|
|
|
|
#include <shellapi.h>
|
|
|
|
// FIXME:
|
|
#define EVENT_MESSAGE_EVENTTEXT_BUFFER 1024*10
|
|
extern HWND hwndListView;
|
|
extern BOOL
|
|
GetEventMessage(IN LPCWSTR KeyName,
|
|
IN LPCWSTR SourceName,
|
|
IN PEVENTLOGRECORD pevlr,
|
|
OUT PWCHAR EventText);
|
|
|
|
|
|
typedef struct _DETAILDATA
|
|
{
|
|
PEVENTLOGFILTER EventLogFilter;
|
|
|
|
BOOL bDisplayWords;
|
|
HFONT hMonospaceFont;
|
|
|
|
INT cxMin, cyMin;
|
|
INT cxOld, cyOld;
|
|
POINT scPos;
|
|
} DETAILDATA, *PDETAILDATA;
|
|
|
|
|
|
static
|
|
VOID
|
|
DisplayEvent(HWND hDlg, PEVENTLOGFILTER EventLogFilter)
|
|
{
|
|
WCHAR szEventType[MAX_PATH];
|
|
WCHAR szTime[MAX_PATH];
|
|
WCHAR szDate[MAX_PATH];
|
|
WCHAR szUser[MAX_PATH];
|
|
WCHAR szComputer[MAX_PATH];
|
|
WCHAR szSource[MAX_PATH];
|
|
WCHAR szCategory[MAX_PATH];
|
|
WCHAR szEventID[MAX_PATH];
|
|
WCHAR szEventText[EVENT_MESSAGE_EVENTTEXT_BUFFER];
|
|
BOOL bEventData = FALSE;
|
|
LVITEMW li;
|
|
PEVENTLOGRECORD pevlr;
|
|
int iIndex;
|
|
|
|
/* Get index of selected item */
|
|
iIndex = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED | LVNI_FOCUSED);
|
|
if (iIndex == -1)
|
|
{
|
|
MessageBoxW(hDlg,
|
|
L"No Items in ListView",
|
|
L"Error",
|
|
MB_OK | MB_ICONINFORMATION);
|
|
return;
|
|
}
|
|
|
|
li.mask = LVIF_PARAM;
|
|
li.iItem = iIndex;
|
|
li.iSubItem = 0;
|
|
|
|
ListView_GetItem(hwndListView, &li);
|
|
|
|
pevlr = (PEVENTLOGRECORD)li.lParam;
|
|
|
|
ListView_GetItemText(hwndListView, iIndex, 0, szEventType, ARRAYSIZE(szEventType));
|
|
ListView_GetItemText(hwndListView, iIndex, 1, szDate, ARRAYSIZE(szDate));
|
|
ListView_GetItemText(hwndListView, iIndex, 2, szTime, ARRAYSIZE(szTime));
|
|
ListView_GetItemText(hwndListView, iIndex, 3, szSource, ARRAYSIZE(szSource));
|
|
ListView_GetItemText(hwndListView, iIndex, 4, szCategory, ARRAYSIZE(szCategory));
|
|
ListView_GetItemText(hwndListView, iIndex, 5, szEventID, ARRAYSIZE(szEventID));
|
|
ListView_GetItemText(hwndListView, iIndex, 6, szUser, ARRAYSIZE(szUser));
|
|
ListView_GetItemText(hwndListView, iIndex, 7, szComputer, ARRAYSIZE(szComputer));
|
|
|
|
SetDlgItemTextW(hDlg, IDC_EVENTDATESTATIC, szDate);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTTIMESTATIC, szTime);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTUSERSTATIC, szUser);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTSOURCESTATIC, szSource);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTCOMPUTERSTATIC, szComputer);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTCATEGORYSTATIC, szCategory);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTIDSTATIC, szEventID);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTTYPESTATIC, szEventType);
|
|
|
|
bEventData = (pevlr->DataLength > 0);
|
|
EnableDlgItem(hDlg, IDC_BYTESRADIO, bEventData);
|
|
EnableDlgItem(hDlg, IDC_WORDRADIO, bEventData);
|
|
|
|
// FIXME: At the moment we support only one event log in the filter
|
|
GetEventMessage(EventLogFilter->EventLogs[0]->LogName, szSource, pevlr, szEventText);
|
|
SetDlgItemTextW(hDlg, IDC_EVENTTEXTEDIT, szEventText);
|
|
}
|
|
|
|
static
|
|
UINT
|
|
PrintByteDataLine(PWCHAR pBuffer, UINT uOffset, PBYTE pData, UINT uLength)
|
|
{
|
|
PWCHAR p = pBuffer;
|
|
UINT n, i, r = 0;
|
|
|
|
if (uOffset != 0)
|
|
{
|
|
n = swprintf(p, L"\r\n");
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
n = swprintf(p, L"%04lx:", uOffset);
|
|
p += n;
|
|
r += n;
|
|
|
|
for (i = 0; i < uLength; i++)
|
|
{
|
|
n = swprintf(p, L" %02x", pData[i]);
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
for (i = 0; i < 9 - uLength; i++)
|
|
{
|
|
n = swprintf(p, L" ");
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
for (i = 0; i < uLength; i++)
|
|
{
|
|
// NOTE: Normally iswprint should return FALSE for tabs...
|
|
n = swprintf(p, L"%c", (iswprint(pData[i]) && (pData[i] != L'\t')) ? pData[i] : L'.');
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static
|
|
UINT
|
|
PrintWordDataLine(PWCHAR pBuffer, UINT uOffset, PULONG pData, UINT uLength)
|
|
{
|
|
PWCHAR p = pBuffer;
|
|
UINT n, i, r = 0;
|
|
|
|
if (uOffset != 0)
|
|
{
|
|
n = swprintf(p, L"\r\n");
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
n = swprintf(p, L"%04lx:", uOffset);
|
|
p += n;
|
|
r += n;
|
|
|
|
for (i = 0; i < uLength / sizeof(ULONG); i++)
|
|
{
|
|
n = swprintf(p, L" %08lx", pData[i]);
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
/* Display the remaining bytes if uLength was not a multiple of sizeof(ULONG) */
|
|
for (i = (uLength / sizeof(ULONG)) * sizeof(ULONG); i < uLength; i++)
|
|
{
|
|
n = swprintf(p, L" %02x", ((PBYTE)pData)[i]);
|
|
p += n;
|
|
r += n;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
DisplayEventData(HWND hDlg, BOOL bDisplayWords)
|
|
{
|
|
LVITEMW li;
|
|
PEVENTLOGRECORD pevlr;
|
|
int iIndex;
|
|
|
|
LPBYTE pData;
|
|
UINT i, uOffset;
|
|
UINT uBufferSize, uLineLength;
|
|
PWCHAR pTextBuffer, pLine;
|
|
|
|
/* Get index of selected item */
|
|
iIndex = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED | LVNI_FOCUSED);
|
|
if (iIndex == -1)
|
|
{
|
|
MessageBoxW(hDlg,
|
|
L"No Items in ListView",
|
|
L"Error",
|
|
MB_OK | MB_ICONINFORMATION);
|
|
return;
|
|
}
|
|
|
|
li.mask = LVIF_PARAM;
|
|
li.iItem = iIndex;
|
|
li.iSubItem = 0;
|
|
|
|
ListView_GetItem(hwndListView, &li);
|
|
|
|
pevlr = (PEVENTLOGRECORD)li.lParam;
|
|
if (pevlr->DataLength == 0)
|
|
{
|
|
SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, L"");
|
|
return;
|
|
}
|
|
|
|
if (bDisplayWords)
|
|
uBufferSize = ((pevlr->DataLength / 8) + 1) * 26 * sizeof(WCHAR);
|
|
else
|
|
uBufferSize = ((pevlr->DataLength / 8) + 1) * 43 * sizeof(WCHAR);
|
|
|
|
pTextBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uBufferSize);
|
|
if (!pTextBuffer)
|
|
return;
|
|
|
|
pLine = pTextBuffer;
|
|
uOffset = 0;
|
|
|
|
for (i = 0; i < pevlr->DataLength / 8; i++)
|
|
{
|
|
pData = (LPBYTE)((LPBYTE)pevlr + pevlr->DataOffset + uOffset);
|
|
|
|
if (bDisplayWords)
|
|
uLineLength = PrintWordDataLine(pLine, uOffset, (PULONG)pData, 8);
|
|
else
|
|
uLineLength = PrintByteDataLine(pLine, uOffset, pData, 8);
|
|
pLine = pLine + uLineLength;
|
|
|
|
uOffset += 8;
|
|
}
|
|
|
|
if (pevlr->DataLength % 8 != 0)
|
|
{
|
|
pData = (LPBYTE)((LPBYTE)pevlr + pevlr->DataOffset + uOffset);
|
|
|
|
if (bDisplayWords)
|
|
PrintWordDataLine(pLine, uOffset, (PULONG)pData, pevlr->DataLength % 8);
|
|
else
|
|
PrintByteDataLine(pLine, uOffset, pData, pevlr->DataLength % 8);
|
|
}
|
|
|
|
SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, pTextBuffer);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pTextBuffer);
|
|
}
|
|
|
|
static
|
|
HFONT
|
|
CreateMonospaceFont(VOID)
|
|
{
|
|
LOGFONTW tmpFont = {0};
|
|
HFONT hFont;
|
|
HDC hDC;
|
|
|
|
hDC = GetDC(NULL);
|
|
|
|
tmpFont.lfHeight = -MulDiv(8, GetDeviceCaps(hDC, LOGPIXELSY), 72);
|
|
tmpFont.lfWeight = FW_NORMAL;
|
|
wcscpy(tmpFont.lfFaceName, L"Courier New");
|
|
|
|
hFont = CreateFontIndirectW(&tmpFont);
|
|
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
return hFont;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
CopyEventEntry(HWND hWnd)
|
|
{
|
|
WCHAR tmpHeader[512];
|
|
WCHAR szEventType[MAX_PATH];
|
|
WCHAR szSource[MAX_PATH];
|
|
WCHAR szCategory[MAX_PATH];
|
|
WCHAR szEventID[MAX_PATH];
|
|
WCHAR szDate[MAX_PATH];
|
|
WCHAR szTime[MAX_PATH];
|
|
WCHAR szUser[MAX_PATH];
|
|
WCHAR szComputer[MAX_PATH];
|
|
WCHAR evtDesc[EVENT_MESSAGE_EVENTTEXT_BUFFER];
|
|
ULONG size = 0;
|
|
LPWSTR output;
|
|
HGLOBAL hMem;
|
|
|
|
/* Try to open the clipboard */
|
|
if (!OpenClipboard(hWnd))
|
|
return;
|
|
|
|
/* Get the formatted text needed to place the content into */
|
|
size += LoadStringW(hInst, IDS_COPY, tmpHeader, ARRAYSIZE(tmpHeader));
|
|
|
|
/* Grab all the information and get it ready for the clipboard */
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTTYPESTATIC, szEventType, ARRAYSIZE(szEventType));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTSOURCESTATIC, szSource, ARRAYSIZE(szSource));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTCATEGORYSTATIC, szCategory, ARRAYSIZE(szCategory));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTIDSTATIC, szEventID, ARRAYSIZE(szEventID));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTDATESTATIC, szDate, ARRAYSIZE(szDate));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTTIMESTATIC, szTime, ARRAYSIZE(szTime));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTUSERSTATIC, szUser, ARRAYSIZE(szUser));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTCOMPUTERSTATIC, szComputer, ARRAYSIZE(szComputer));
|
|
size += GetDlgItemTextW(hWnd, IDC_EVENTTEXTEDIT, evtDesc, ARRAYSIZE(evtDesc));
|
|
|
|
size++; /* Null-termination */
|
|
size *= sizeof(WCHAR);
|
|
|
|
/*
|
|
* Consolidate the information into one big piece and
|
|
* sort out the memory needed to write to the clipboard.
|
|
*/
|
|
hMem = GlobalAlloc(GMEM_MOVEABLE, size);
|
|
if (hMem == NULL) goto Quit;
|
|
|
|
output = GlobalLock(hMem);
|
|
if (output == NULL)
|
|
{
|
|
GlobalFree(hMem);
|
|
goto Quit;
|
|
}
|
|
|
|
StringCbPrintfW(output, size,
|
|
tmpHeader, szEventType, szSource, szCategory, szEventID,
|
|
szDate, szTime, szUser, szComputer, evtDesc);
|
|
|
|
GlobalUnlock(hMem);
|
|
|
|
/* We succeeded, empty the clipboard and write the data in it */
|
|
EmptyClipboard();
|
|
SetClipboardData(CF_UNICODETEXT, hMem);
|
|
|
|
Quit:
|
|
/* Close the clipboard once we are done with it */
|
|
CloseClipboard();
|
|
}
|
|
|
|
static
|
|
VOID
|
|
OnLink(HWND hDlg, ENLINK* penLink)
|
|
{
|
|
LPWSTR pLink;
|
|
TEXTRANGE txtRange;
|
|
|
|
ASSERT(penLink->nmhdr.idFrom == IDC_EVENTTEXTEDIT);
|
|
|
|
/* Only act on left button up events */
|
|
if (penLink->msg != WM_LBUTTONUP)
|
|
return;
|
|
|
|
/* If the range is empty, do nothing */
|
|
if (penLink->chrg.cpMin == penLink->chrg.cpMax)
|
|
return;
|
|
|
|
/* Allocate memory for the text link */
|
|
pLink = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
(max(penLink->chrg.cpMin, penLink->chrg.cpMax) -
|
|
min(penLink->chrg.cpMin, penLink->chrg.cpMax) + 1) * sizeof(WCHAR));
|
|
if (!pLink)
|
|
{
|
|
/* Not enough memory, bail out */
|
|
return;
|
|
}
|
|
|
|
txtRange.chrg = penLink->chrg;
|
|
txtRange.lpstrText = pLink;
|
|
SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_GETTEXTRANGE, 0, (LPARAM)&txtRange);
|
|
|
|
/* Open the link */
|
|
ShellExecuteW(hDlg, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
|
|
|
|
/* Free the buffer */
|
|
HeapFree(GetProcessHeap(), 0, pLink);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
OnScroll(HWND hDlg, PDETAILDATA pData, INT nBar, WORD sbCode)
|
|
{
|
|
RECT rect;
|
|
|
|
SCROLLINFO sInfo;
|
|
INT oldPos, Maximum;
|
|
PLONG pOriginXY;
|
|
|
|
ASSERT(nBar == SB_HORZ || nBar == SB_VERT);
|
|
|
|
GetClientRect(hDlg, &rect);
|
|
|
|
if (nBar == SB_HORZ)
|
|
{
|
|
Maximum = pData->cxMin - (rect.right-rect.left) /* pData->cxOld */;
|
|
pOriginXY = &pData->scPos.x;
|
|
}
|
|
else // if (nBar == SB_VERT)
|
|
{
|
|
Maximum = pData->cyMin - (rect.bottom-rect.top) /* pData->cyOld */;
|
|
pOriginXY = &pData->scPos.y;
|
|
}
|
|
|
|
/* Set scrollbar sizes */
|
|
sInfo.cbSize = sizeof(sInfo);
|
|
sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
|
|
|
|
if (!GetScrollInfo(hDlg, nBar, &sInfo))
|
|
return;
|
|
|
|
oldPos = sInfo.nPos;
|
|
|
|
switch (sbCode)
|
|
{
|
|
case SB_LINEUP: // SB_LINELEFT:
|
|
sInfo.nPos--;
|
|
break;
|
|
|
|
case SB_LINEDOWN: // SB_LINERIGHT:
|
|
sInfo.nPos++;
|
|
break;
|
|
|
|
case SB_PAGEUP: // SB_PAGELEFT:
|
|
sInfo.nPos -= sInfo.nPage;
|
|
break;
|
|
|
|
case SB_PAGEDOWN: // SB_PAGERIGHT:
|
|
sInfo.nPos += sInfo.nPage;
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
sInfo.nPos = sInfo.nTrackPos;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
sInfo.nPos = sInfo.nTrackPos;
|
|
break;
|
|
|
|
case SB_TOP: // SB_LEFT:
|
|
sInfo.nPos = sInfo.nMin;
|
|
break;
|
|
|
|
case SB_BOTTOM: // SB_RIGHT:
|
|
sInfo.nPos = sInfo.nMax;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
sInfo.nPos = min(max(sInfo.nPos, 0), Maximum);
|
|
|
|
if (oldPos != sInfo.nPos)
|
|
{
|
|
POINT scOldPos = pData->scPos;
|
|
|
|
/* We now modify pData->scPos */
|
|
*pOriginXY = sInfo.nPos;
|
|
|
|
ScrollWindowEx(hDlg,
|
|
(scOldPos.x - pData->scPos.x),
|
|
(scOldPos.y - pData->scPos.y),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
|
|
|
|
sInfo.fMask = SIF_POS;
|
|
SetScrollInfo(hDlg, nBar, &sInfo, TRUE);
|
|
|
|
// UpdateWindow(hDlg);
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
OnSize(HWND hDlg, PDETAILDATA pData, INT cx, INT cy)
|
|
{
|
|
LONG_PTR dwStyle;
|
|
INT sbVXSize, sbHYSize;
|
|
SCROLLINFO sInfo;
|
|
POINT scOldPos;
|
|
HDWP hdwp;
|
|
HWND hItemWnd;
|
|
RECT rect;
|
|
INT y = 0;
|
|
|
|
if (!pData)
|
|
return;
|
|
|
|
dwStyle = GetWindowLongPtrW(hDlg, GWL_STYLE);
|
|
sbVXSize = GetSystemMetrics(SM_CXVSCROLL);
|
|
sbHYSize = GetSystemMetrics(SM_CYHSCROLL);
|
|
|
|
/* Compensate for existing scroll bars (because lParam values do not accommodate scroll bar) */
|
|
if (dwStyle & WS_HSCROLL) cy += sbHYSize; // Window currently has a horizontal scrollbar
|
|
if (dwStyle & WS_VSCROLL) cx += sbVXSize; // Window currently has a vertical scrollbar
|
|
|
|
/* Compensate for added scroll bars in window */
|
|
if (cx < pData->cxMin) cy -= sbHYSize; // Window will have a horizontal scroll bar
|
|
if (cy < pData->cyMin) cx -= sbVXSize; // Window will have a vertical scroll bar
|
|
|
|
/* Set scrollbar sizes */
|
|
sInfo.cbSize = sizeof(sInfo);
|
|
|
|
sInfo.fMask = SIF_POS;
|
|
if (GetScrollInfo(hDlg, SB_VERT, &sInfo))
|
|
scOldPos.y = sInfo.nPos;
|
|
else
|
|
scOldPos.y = pData->scPos.y;
|
|
|
|
sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
sInfo.nMin = 0;
|
|
if (pData->cyMin > cy)
|
|
{
|
|
sInfo.nMax = pData->cyMin - 1;
|
|
sInfo.nPage = cy;
|
|
sInfo.nPos = pData->scPos.y;
|
|
SetScrollInfo(hDlg, SB_VERT, &sInfo, TRUE);
|
|
|
|
/* Display the scrollbar if needed */
|
|
if (!(dwStyle & WS_VSCROLL))
|
|
ShowScrollBar(hDlg, SB_VERT, TRUE);
|
|
}
|
|
else
|
|
{
|
|
scOldPos.y = 0;
|
|
|
|
sInfo.nMax = pData->cyMin - 1;
|
|
sInfo.nPage = cy;
|
|
sInfo.nPos = pData->scPos.y;
|
|
sInfo.nPos = scOldPos.y;
|
|
SetScrollInfo(hDlg, SB_VERT, &sInfo, TRUE);
|
|
|
|
ShowScrollBar(hDlg, SB_VERT, FALSE);
|
|
|
|
rect.left = cx - sbVXSize;
|
|
rect.right = cx;
|
|
rect.top = 0;
|
|
rect.bottom = cy;
|
|
InvalidateRect(hDlg, &rect, TRUE);
|
|
}
|
|
|
|
sInfo.fMask = SIF_POS;
|
|
if (GetScrollInfo(hDlg, SB_HORZ, &sInfo))
|
|
scOldPos.x = sInfo.nPos;
|
|
else
|
|
scOldPos.x = pData->scPos.x;
|
|
|
|
sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
sInfo.nMin = 0;
|
|
if (pData->cxMin > cx)
|
|
{
|
|
sInfo.nMax = pData->cxMin - 1;
|
|
sInfo.nPage = cx;
|
|
sInfo.nPos = pData->scPos.x;
|
|
SetScrollInfo(hDlg, SB_HORZ, &sInfo, TRUE);
|
|
|
|
/* Display the scrollbar if needed */
|
|
if (!(dwStyle & WS_HSCROLL))
|
|
ShowScrollBar(hDlg, SB_HORZ, TRUE);
|
|
}
|
|
else
|
|
{
|
|
scOldPos.x = 0;
|
|
|
|
sInfo.nMax = pData->cxMin - 1;
|
|
sInfo.nPage = cx;
|
|
sInfo.nPos = pData->scPos.x;
|
|
sInfo.nPos = scOldPos.x;
|
|
SetScrollInfo(hDlg, SB_HORZ, &sInfo, TRUE);
|
|
|
|
ShowScrollBar(hDlg, SB_HORZ, FALSE);
|
|
|
|
rect.left = 0;
|
|
rect.right = cx;
|
|
rect.top = cy - sbHYSize;
|
|
rect.bottom = cy;
|
|
InvalidateRect(hDlg, &rect, TRUE);
|
|
}
|
|
|
|
if ((scOldPos.x != pData->scPos.x) || (scOldPos.y != pData->scPos.y))
|
|
{
|
|
ScrollWindowEx(hDlg,
|
|
// (scOldPos.x - pData->scPos.x),
|
|
(pData->scPos.x - scOldPos.x),
|
|
// (scOldPos.y - pData->scPos.y),
|
|
(pData->scPos.y - scOldPos.y),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
|
|
|
|
pData->scPos = scOldPos;
|
|
}
|
|
|
|
// /* Adjust the start of the visible area if we are attempting to show nonexistent areas */
|
|
// if ((pData->cxMin - pData->scPos.x) < cx) pData->scPos.x = pData->cxMin - cx;
|
|
// if ((pData->cyMin - pData->scPos.y) < cy) pData->scPos.y = pData->cyMin - cy;
|
|
// // InvalidateRect(GuiData->hWindow, NULL, TRUE);
|
|
|
|
/* Forbid resizing the control smaller than its minimal size */
|
|
if (cx < pData->cxMin) cx = pData->cxMin;
|
|
if (cy < pData->cyMin) cy = pData->cyMin;
|
|
|
|
if ((cx != pData->cxOld) || (cy != pData->cyOld))
|
|
{
|
|
hdwp = BeginDeferWindowPos(8);
|
|
|
|
/* Move the edit boxes */
|
|
|
|
GetWindowRect(hDlg, &rect);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_EVENTTEXTEDIT);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
// OffsetRect(&rect, 0, y);
|
|
// y += (cy - pData->cyOld) / 2 ; // + (cy - pData->cyOld) % 2;
|
|
/** y += (cy - pData->cyOld) / 2 ; // + (cy - pData->cyOld) % 2; **/
|
|
if (cy >= pData->cyOld)
|
|
y += (cy - pData->cyOld) / 2 + (cy - pData->cyOld) % 2;
|
|
else
|
|
y -= (pData->cyOld - cy) / 2 + (pData->cyOld - cy) % 2;
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left, rect.top,
|
|
(rect.right - rect.left) + (cx - pData->cxOld),
|
|
(rect.bottom - rect.top) + y,
|
|
/** SWP_NOMOVE | **/ SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_DETAILS_STATIC);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
// OffsetRect(&rect, 0, y);
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left, rect.top + y,
|
|
0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_BYTESRADIO);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
// OffsetRect(&rect, 0, y);
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left, rect.top + y,
|
|
0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_WORDRADIO);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
// OffsetRect(&rect, 0, y);
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left, rect.top + y,
|
|
0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_EVENTDATAEDIT);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
// OffsetRect(&rect, 0, y);
|
|
// // y -= (cy - pData->cyOld) % 2;
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left, rect.top + y,
|
|
(rect.right - rect.left) + (cx - pData->cxOld),
|
|
(rect.bottom - rect.top) + y,
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
/* Move the buttons */
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_PREVIOUS);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left + (cx - pData->cxOld),
|
|
rect.top,
|
|
0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_NEXT);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left + (cx - pData->cxOld),
|
|
rect.top,
|
|
0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
hItemWnd = GetDlgItem(hDlg, IDC_COPY);
|
|
GetWindowRect(hItemWnd, &rect);
|
|
MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
|
|
|
|
if (hdwp)
|
|
hdwp = DeferWindowPos(hdwp,
|
|
hItemWnd,
|
|
0,
|
|
rect.left + (cx - pData->cxOld),
|
|
rect.top,
|
|
0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
if (hdwp)
|
|
EndDeferWindowPos(hdwp);
|
|
|
|
pData->cxOld = cx;
|
|
pData->cyOld = cy;
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
InitDetailsDlgCtrl(HWND hDlg, PDETAILDATA pData)
|
|
{
|
|
DWORD dwMask;
|
|
|
|
HANDLE nextIcon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_NEXT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
|
|
HANDLE prevIcon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_PREV), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
|
|
HANDLE copyIcon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_COPY), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
|
|
|
|
SendDlgItemMessageW(hDlg, IDC_NEXT, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)nextIcon);
|
|
SendDlgItemMessageW(hDlg, IDC_PREVIOUS, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)prevIcon);
|
|
SendDlgItemMessageW(hDlg, IDC_COPY, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)copyIcon);
|
|
|
|
/* Set the default read-only RichEdit color */
|
|
SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_3DFACE));
|
|
|
|
/* Enable RichEdit coloured and underlined links */
|
|
dwMask = SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_GETEVENTMASK, 0, 0);
|
|
SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_SETEVENTMASK, 0, dwMask | ENM_LINK | ENM_MOUSEEVENTS);
|
|
|
|
/*
|
|
* Activate automatic URL recognition by the RichEdit control. For more information, see:
|
|
* https://blogs.msdn.microsoft.com/murrays/2009/08/31/automatic-richedit-hyperlinks/
|
|
* https://blogs.msdn.microsoft.com/murrays/2009/09/24/richedit-friendly-name-hyperlinks/
|
|
* https://msdn.microsoft.com/en-us/library/windows/desktop/bb787991(v=vs.85).aspx
|
|
*/
|
|
SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_AUTOURLDETECT, AURL_ENABLEURL /* | AURL_ENABLEEAURLS */, 0);
|
|
|
|
/* Note that the RichEdit control never gets themed under WinXP+; one would have to write code to simulate Edit-control theming */
|
|
|
|
SendDlgItemMessageW(hDlg, pData->bDisplayWords ? IDC_WORDRADIO : IDC_BYTESRADIO, BM_SETCHECK, BST_CHECKED, 0);
|
|
SendDlgItemMessageW(hDlg, IDC_EVENTDATAEDIT, WM_SETFONT, (WPARAM)pData->hMonospaceFont, (LPARAM)TRUE);
|
|
}
|
|
|
|
/* Message handler for Event Details control */
|
|
static
|
|
INT_PTR CALLBACK
|
|
EventDetailsCtrl(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PDETAILDATA pData;
|
|
|
|
pData = (PDETAILDATA)GetWindowLongPtrW(hDlg, DWLP_USER);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
RECT rect;
|
|
|
|
pData = (PDETAILDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pData));
|
|
if (!pData)
|
|
{
|
|
EndDialog(hDlg, 0);
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)pData);
|
|
|
|
pData->EventLogFilter = (PEVENTLOGFILTER)lParam;
|
|
pData->bDisplayWords = FALSE;
|
|
pData->hMonospaceFont = CreateMonospaceFont();
|
|
|
|
GetClientRect(hDlg, &rect);
|
|
pData->cxOld = pData->cxMin = rect.right - rect.left;
|
|
pData->cyOld = pData->cyMin = rect.bottom - rect.top;
|
|
pData->scPos.x = pData->scPos.y = 0;
|
|
|
|
InitDetailsDlgCtrl(hDlg, pData);
|
|
|
|
#if 0
|
|
/* Show event info on dialog box */
|
|
DisplayEvent(hDlg, pData->EventLogFilter);
|
|
DisplayEventData(hDlg, pData->bDisplayWords);
|
|
#endif
|
|
|
|
// OnSize(hDlg, pData, pData->cxOld, pData->cyOld);
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
if (pData)
|
|
{
|
|
if (pData->hMonospaceFont)
|
|
DeleteObject(pData->hMonospaceFont);
|
|
HeapFree(GetProcessHeap(), 0, pData);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
|
|
case EVT_SETFILTER:
|
|
pData->EventLogFilter = (PEVENTLOGFILTER)lParam;
|
|
return (INT_PTR)TRUE;
|
|
|
|
case EVT_DISPLAY:
|
|
if (pData->EventLogFilter)
|
|
{
|
|
/* Show event info on dialog box */
|
|
DisplayEvent(hDlg, pData->EventLogFilter);
|
|
DisplayEventData(hDlg, pData->bDisplayWords);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_PREVIOUS:
|
|
{
|
|
SendMessageW(hwndListView, WM_KEYDOWN, VK_UP, 0);
|
|
|
|
/* Show event info on dialog box */
|
|
if (pData->EventLogFilter)
|
|
{
|
|
DisplayEvent(hDlg, pData->EventLogFilter);
|
|
DisplayEventData(hDlg, pData->bDisplayWords);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
|
|
case IDC_NEXT:
|
|
{
|
|
SendMessageW(hwndListView, WM_KEYDOWN, VK_DOWN, 0);
|
|
|
|
/* Show event info on dialog box */
|
|
if (pData->EventLogFilter)
|
|
{
|
|
DisplayEvent(hDlg, pData->EventLogFilter);
|
|
DisplayEventData(hDlg, pData->bDisplayWords);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
|
|
case IDC_COPY:
|
|
if (pData->EventLogFilter)
|
|
CopyEventEntry(hDlg);
|
|
return (INT_PTR)TRUE;
|
|
|
|
case IDC_BYTESRADIO:
|
|
if (pData->EventLogFilter)
|
|
{
|
|
pData->bDisplayWords = FALSE;
|
|
DisplayEventData(hDlg, pData->bDisplayWords);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
|
|
case IDC_WORDRADIO:
|
|
if (pData->EventLogFilter)
|
|
{
|
|
pData->bDisplayWords = TRUE;
|
|
DisplayEventData(hDlg, pData->bDisplayWords);
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR hdr = (LPNMHDR)lParam;
|
|
|
|
if (hdr->idFrom == IDC_EVENTTEXTEDIT)
|
|
{
|
|
switch (hdr->code)
|
|
{
|
|
case EN_LINK:
|
|
OnLink(hDlg, (ENLINK*)lParam);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_HSCROLL:
|
|
OnScroll(hDlg, pData, SB_HORZ, LOWORD(wParam));
|
|
SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_VSCROLL:
|
|
OnScroll(hDlg, pData, SB_VERT, LOWORD(wParam));
|
|
SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_SIZE:
|
|
OnSize(hDlg, pData, LOWORD(lParam), HIWORD(lParam));
|
|
SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
}
|
|
|
|
HWND
|
|
CreateEventDetailsCtrl(HINSTANCE hInstance,
|
|
HWND hParentWnd,
|
|
LPARAM lParam)
|
|
{
|
|
return CreateDialogParamW(hInstance,
|
|
MAKEINTRESOURCEW(IDD_EVENTDETAILS_CTRL),
|
|
hParentWnd, EventDetailsCtrl, lParam);
|
|
}
|