2 * PROJECT: ReactOS Event Log Viewer
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Event Details Control.
5 * COPYRIGHT: Copyright 2007 Marc Piulachs <marc.piulachs@codexchange.net>
6 * Copyright 2008-2016 Eric Kohl <eric.kohl@reactos.org>
7 * Copyright 2016-2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
11 #include "evtdetctl.h"
16 #define EVENT_MESSAGE_EVENTTEXT_BUFFER (1024*10)
17 extern WCHAR szTitle
[];
18 extern HWND hwndListView
;
20 GetEventMessage(IN LPCWSTR KeyName
,
21 IN LPCWSTR SourceName
,
22 IN PEVENTLOGRECORD pevlr
,
23 OUT PWCHAR EventText
);
26 typedef struct _DETAILDATA
28 /* Data initialized from EVENTDETAIL_INFO */
29 PEVENTLOGFILTER EventLogFilter
;
38 } DETAILDATA
, *PDETAILDATA
;
45 _In_ PDETAILDATA pDetailData
)
47 PEVENTLOGFILTER EventLogFilter
= pDetailData
->EventLogFilter
;
48 INT iItem
= pDetailData
->iEventItem
;
50 PEVENTLOGRECORD pevlr
;
53 WCHAR szEventType
[MAX_PATH
];
54 WCHAR szTime
[MAX_PATH
];
55 WCHAR szDate
[MAX_PATH
];
56 WCHAR szUser
[MAX_PATH
];
57 WCHAR szComputer
[MAX_PATH
];
58 WCHAR szSource
[MAX_PATH
];
59 WCHAR szCategory
[MAX_PATH
];
60 WCHAR szEventID
[MAX_PATH
];
61 WCHAR szEventText
[EVENT_MESSAGE_EVENTTEXT_BUFFER
];
66 ListView_GetItem(hwndListView
, &li
);
68 pevlr
= (PEVENTLOGRECORD
)li
.lParam
;
70 ListView_GetItemText(hwndListView
, iItem
, 0, szEventType
, ARRAYSIZE(szEventType
));
71 ListView_GetItemText(hwndListView
, iItem
, 1, szDate
, ARRAYSIZE(szDate
));
72 ListView_GetItemText(hwndListView
, iItem
, 2, szTime
, ARRAYSIZE(szTime
));
73 ListView_GetItemText(hwndListView
, iItem
, 3, szSource
, ARRAYSIZE(szSource
));
74 ListView_GetItemText(hwndListView
, iItem
, 4, szCategory
, ARRAYSIZE(szCategory
));
75 ListView_GetItemText(hwndListView
, iItem
, 5, szEventID
, ARRAYSIZE(szEventID
));
76 ListView_GetItemText(hwndListView
, iItem
, 6, szUser
, ARRAYSIZE(szUser
));
77 ListView_GetItemText(hwndListView
, iItem
, 7, szComputer
, ARRAYSIZE(szComputer
));
79 SetDlgItemTextW(hDlg
, IDC_EVENTDATESTATIC
, szDate
);
80 SetDlgItemTextW(hDlg
, IDC_EVENTTIMESTATIC
, szTime
);
81 SetDlgItemTextW(hDlg
, IDC_EVENTUSERSTATIC
, szUser
);
82 SetDlgItemTextW(hDlg
, IDC_EVENTSOURCESTATIC
, szSource
);
83 SetDlgItemTextW(hDlg
, IDC_EVENTCOMPUTERSTATIC
, szComputer
);
84 SetDlgItemTextW(hDlg
, IDC_EVENTCATEGORYSTATIC
, szCategory
);
85 SetDlgItemTextW(hDlg
, IDC_EVENTIDSTATIC
, szEventID
);
86 SetDlgItemTextW(hDlg
, IDC_EVENTTYPESTATIC
, szEventType
);
88 bEventData
= (pevlr
->DataLength
> 0);
89 EnableDlgItem(hDlg
, IDC_BYTESRADIO
, bEventData
);
90 EnableDlgItem(hDlg
, IDC_WORDRADIO
, bEventData
);
92 // FIXME: At the moment we support only one event log in the filter
93 GetEventMessage(EventLogFilter
->EventLogs
[0]->LogName
, szSource
, pevlr
, szEventText
);
94 SetDlgItemTextW(hDlg
, IDC_EVENTTEXTEDIT
, szEventText
);
99 PrintByteDataLine(PWCHAR pBuffer
, UINT uOffset
, PBYTE pData
, UINT uLength
)
106 n
= swprintf(p
, L
"\r\n");
111 n
= swprintf(p
, L
"%04lx:", uOffset
);
115 for (i
= 0; i
< uLength
; i
++)
117 n
= swprintf(p
, L
" %02x", pData
[i
]);
122 for (i
= 0; i
< 9 - uLength
; i
++)
124 n
= swprintf(p
, L
" ");
129 for (i
= 0; i
< uLength
; i
++)
131 // NOTE: Normally iswprint should return FALSE for tabs...
132 n
= swprintf(p
, L
"%c", (iswprint(pData
[i
]) && (pData
[i
] != L
'\t')) ? pData
[i
] : L
'.');
142 PrintWordDataLine(PWCHAR pBuffer
, UINT uOffset
, PULONG pData
, UINT uLength
)
149 n
= swprintf(p
, L
"\r\n");
154 n
= swprintf(p
, L
"%04lx:", uOffset
);
158 for (i
= 0; i
< uLength
/ sizeof(ULONG
); i
++)
160 n
= swprintf(p
, L
" %08lx", pData
[i
]);
165 /* Display the remaining bytes if uLength was not a multiple of sizeof(ULONG) */
166 for (i
= (uLength
/ sizeof(ULONG
)) * sizeof(ULONG
); i
< uLength
; i
++)
168 n
= swprintf(p
, L
" %02x", ((PBYTE
)pData
)[i
]);
180 _In_ PDETAILDATA pDetailData
)
182 BOOL bDisplayWords
= pDetailData
->bDisplayWords
;
183 INT iItem
= pDetailData
->iEventItem
;
185 PEVENTLOGRECORD pevlr
;
189 UINT uBufferSize
, uLineLength
;
190 PWCHAR pTextBuffer
, pLine
;
192 li
.mask
= LVIF_PARAM
;
195 ListView_GetItem(hwndListView
, &li
);
197 pevlr
= (PEVENTLOGRECORD
)li
.lParam
;
198 if (pevlr
->DataLength
== 0)
200 SetDlgItemTextW(hDlg
, IDC_EVENTDATAEDIT
, L
"");
205 uBufferSize
= ((pevlr
->DataLength
/ 8) + 1) * 26 * sizeof(WCHAR
);
207 uBufferSize
= ((pevlr
->DataLength
/ 8) + 1) * 43 * sizeof(WCHAR
);
209 pTextBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, uBufferSize
);
216 for (i
= 0; i
< pevlr
->DataLength
/ 8; i
++)
218 pData
= (LPBYTE
)((LPBYTE
)pevlr
+ pevlr
->DataOffset
+ uOffset
);
221 uLineLength
= PrintWordDataLine(pLine
, uOffset
, (PULONG
)pData
, 8);
223 uLineLength
= PrintByteDataLine(pLine
, uOffset
, pData
, 8);
224 pLine
= pLine
+ uLineLength
;
229 if (pevlr
->DataLength
% 8 != 0)
231 pData
= (LPBYTE
)((LPBYTE
)pevlr
+ pevlr
->DataOffset
+ uOffset
);
234 PrintWordDataLine(pLine
, uOffset
, (PULONG
)pData
, pevlr
->DataLength
% 8);
236 PrintByteDataLine(pLine
, uOffset
, pData
, pevlr
->DataLength
% 8);
239 SetDlgItemTextW(hDlg
, IDC_EVENTDATAEDIT
, pTextBuffer
);
241 HeapFree(GetProcessHeap(), 0, pTextBuffer
);
246 CreateMonospaceFont(VOID
)
248 LOGFONTW tmpFont
= {0};
254 tmpFont
.lfHeight
= -MulDiv(8, GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
255 tmpFont
.lfWeight
= FW_NORMAL
;
256 wcscpy(tmpFont
.lfFaceName
, L
"Courier New");
258 hFont
= CreateFontIndirectW(&tmpFont
);
260 ReleaseDC(NULL
, hDC
);
267 CopyEventEntry(HWND hWnd
)
269 WCHAR tmpHeader
[512];
270 WCHAR szEventType
[MAX_PATH
];
271 WCHAR szSource
[MAX_PATH
];
272 WCHAR szCategory
[MAX_PATH
];
273 WCHAR szEventID
[MAX_PATH
];
274 WCHAR szDate
[MAX_PATH
];
275 WCHAR szTime
[MAX_PATH
];
276 WCHAR szUser
[MAX_PATH
];
277 WCHAR szComputer
[MAX_PATH
];
278 WCHAR evtDesc
[EVENT_MESSAGE_EVENTTEXT_BUFFER
];
283 /* Try to open the clipboard */
284 if (!OpenClipboard(hWnd
))
287 /* Get the formatted text needed to place the content into */
288 size
+= LoadStringW(hInst
, IDS_COPY
, tmpHeader
, ARRAYSIZE(tmpHeader
));
290 /* Grab all the information and get it ready for the clipboard */
291 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTTYPESTATIC
, szEventType
, ARRAYSIZE(szEventType
));
292 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTSOURCESTATIC
, szSource
, ARRAYSIZE(szSource
));
293 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTCATEGORYSTATIC
, szCategory
, ARRAYSIZE(szCategory
));
294 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTIDSTATIC
, szEventID
, ARRAYSIZE(szEventID
));
295 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTDATESTATIC
, szDate
, ARRAYSIZE(szDate
));
296 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTTIMESTATIC
, szTime
, ARRAYSIZE(szTime
));
297 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTUSERSTATIC
, szUser
, ARRAYSIZE(szUser
));
298 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTCOMPUTERSTATIC
, szComputer
, ARRAYSIZE(szComputer
));
299 size
+= GetDlgItemTextW(hWnd
, IDC_EVENTTEXTEDIT
, evtDesc
, ARRAYSIZE(evtDesc
));
301 size
++; /* Null-termination */
302 size
*= sizeof(WCHAR
);
305 * Consolidate the information into one big piece and
306 * sort out the memory needed to write to the clipboard.
308 hMem
= GlobalAlloc(GMEM_MOVEABLE
, size
);
309 if (hMem
== NULL
) goto Quit
;
311 output
= GlobalLock(hMem
);
318 StringCbPrintfW(output
, size
,
319 tmpHeader
, szEventType
, szSource
, szCategory
, szEventID
,
320 szDate
, szTime
, szUser
, szComputer
, evtDesc
);
324 /* We succeeded, empty the clipboard and write the data in it */
326 SetClipboardData(CF_UNICODETEXT
, hMem
);
329 /* Close the clipboard once we are done with it */
335 OnLink(HWND hDlg
, ENLINK
* penLink
)
340 ASSERT(penLink
->nmhdr
.idFrom
== IDC_EVENTTEXTEDIT
);
342 /* Only act on left button up events */
343 if (penLink
->msg
!= WM_LBUTTONUP
)
346 /* If the range is empty, do nothing */
347 if (penLink
->chrg
.cpMin
== penLink
->chrg
.cpMax
)
350 /* Allocate memory for the text link */
351 pLink
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
352 (max(penLink
->chrg
.cpMin
, penLink
->chrg
.cpMax
) -
353 min(penLink
->chrg
.cpMin
, penLink
->chrg
.cpMax
) + 1) * sizeof(WCHAR
));
356 /* Not enough memory, bail out */
360 txtRange
.chrg
= penLink
->chrg
;
361 txtRange
.lpstrText
= pLink
;
362 SendDlgItemMessageW(hDlg
, IDC_EVENTTEXTEDIT
, EM_GETTEXTRANGE
, 0, (LPARAM
)&txtRange
);
365 ShellExecuteW(hDlg
, L
"open", pLink
, NULL
, NULL
, SW_SHOWNOACTIVATE
);
367 /* Free the buffer */
368 HeapFree(GetProcessHeap(), 0, pLink
);
373 OnScroll(HWND hDlg
, PDETAILDATA pData
, INT nBar
, WORD sbCode
)
381 ASSERT(nBar
== SB_HORZ
|| nBar
== SB_VERT
);
383 GetClientRect(hDlg
, &rect
);
387 Maximum
= pData
->cxMin
- (rect
.right
-rect
.left
) /* pData->cxOld */;
388 pOriginXY
= &pData
->scPos
.x
;
390 else // if (nBar == SB_VERT)
392 Maximum
= pData
->cyMin
- (rect
.bottom
-rect
.top
) /* pData->cyOld */;
393 pOriginXY
= &pData
->scPos
.y
;
396 /* Set scrollbar sizes */
397 sInfo
.cbSize
= sizeof(sInfo
);
398 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
400 if (!GetScrollInfo(hDlg
, nBar
, &sInfo
))
407 case SB_LINEUP
: // SB_LINELEFT:
411 case SB_LINEDOWN
: // SB_LINERIGHT:
415 case SB_PAGEUP
: // SB_PAGELEFT:
416 sInfo
.nPos
-= sInfo
.nPage
;
419 case SB_PAGEDOWN
: // SB_PAGERIGHT:
420 sInfo
.nPos
+= sInfo
.nPage
;
424 sInfo
.nPos
= sInfo
.nTrackPos
;
427 case SB_THUMBPOSITION
:
428 sInfo
.nPos
= sInfo
.nTrackPos
;
431 case SB_TOP
: // SB_LEFT:
432 sInfo
.nPos
= sInfo
.nMin
;
435 case SB_BOTTOM
: // SB_RIGHT:
436 sInfo
.nPos
= sInfo
.nMax
;
443 sInfo
.nPos
= min(max(sInfo
.nPos
, 0), Maximum
);
445 if (oldPos
!= sInfo
.nPos
)
447 POINT scOldPos
= pData
->scPos
;
449 /* We now modify pData->scPos */
450 *pOriginXY
= sInfo
.nPos
;
453 (scOldPos
.x
- pData
->scPos
.x
),
454 (scOldPos
.y
- pData
->scPos
.y
),
459 SW_INVALIDATE
| SW_ERASE
| SW_SCROLLCHILDREN
);
461 sInfo
.fMask
= SIF_POS
;
462 SetScrollInfo(hDlg
, nBar
, &sInfo
, TRUE
);
464 // UpdateWindow(hDlg);
470 OnSize(HWND hDlg
, PDETAILDATA pData
, INT cx
, INT cy
)
473 INT sbVXSize
, sbHYSize
;
484 dwStyle
= GetWindowLongPtrW(hDlg
, GWL_STYLE
);
485 sbVXSize
= GetSystemMetrics(SM_CXVSCROLL
);
486 sbHYSize
= GetSystemMetrics(SM_CYHSCROLL
);
488 /* Compensate for existing scroll bars (because lParam values do not accommodate scroll bar) */
489 if (dwStyle
& WS_HSCROLL
) cy
+= sbHYSize
; // Window currently has a horizontal scrollbar
490 if (dwStyle
& WS_VSCROLL
) cx
+= sbVXSize
; // Window currently has a vertical scrollbar
492 /* Compensate for added scroll bars in window */
493 if (cx
< pData
->cxMin
) cy
-= sbHYSize
; // Window will have a horizontal scroll bar
494 if (cy
< pData
->cyMin
) cx
-= sbVXSize
; // Window will have a vertical scroll bar
496 /* Set scrollbar sizes */
497 sInfo
.cbSize
= sizeof(sInfo
);
499 sInfo
.fMask
= SIF_POS
;
500 if (GetScrollInfo(hDlg
, SB_VERT
, &sInfo
))
501 scOldPos
.y
= sInfo
.nPos
;
503 scOldPos
.y
= pData
->scPos
.y
;
505 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
507 if (pData
->cyMin
> cy
)
509 sInfo
.nMax
= pData
->cyMin
- 1;
511 sInfo
.nPos
= pData
->scPos
.y
;
512 SetScrollInfo(hDlg
, SB_VERT
, &sInfo
, TRUE
);
514 /* Display the scrollbar if needed */
515 if (!(dwStyle
& WS_VSCROLL
))
516 ShowScrollBar(hDlg
, SB_VERT
, TRUE
);
522 sInfo
.nMax
= pData
->cyMin
- 1;
524 sInfo
.nPos
= pData
->scPos
.y
;
525 sInfo
.nPos
= scOldPos
.y
;
526 SetScrollInfo(hDlg
, SB_VERT
, &sInfo
, TRUE
);
528 ShowScrollBar(hDlg
, SB_VERT
, FALSE
);
530 rect
.left
= cx
- sbVXSize
;
534 InvalidateRect(hDlg
, &rect
, TRUE
);
537 sInfo
.fMask
= SIF_POS
;
538 if (GetScrollInfo(hDlg
, SB_HORZ
, &sInfo
))
539 scOldPos
.x
= sInfo
.nPos
;
541 scOldPos
.x
= pData
->scPos
.x
;
543 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
545 if (pData
->cxMin
> cx
)
547 sInfo
.nMax
= pData
->cxMin
- 1;
549 sInfo
.nPos
= pData
->scPos
.x
;
550 SetScrollInfo(hDlg
, SB_HORZ
, &sInfo
, TRUE
);
552 /* Display the scrollbar if needed */
553 if (!(dwStyle
& WS_HSCROLL
))
554 ShowScrollBar(hDlg
, SB_HORZ
, TRUE
);
560 sInfo
.nMax
= pData
->cxMin
- 1;
562 sInfo
.nPos
= pData
->scPos
.x
;
563 sInfo
.nPos
= scOldPos
.x
;
564 SetScrollInfo(hDlg
, SB_HORZ
, &sInfo
, TRUE
);
566 ShowScrollBar(hDlg
, SB_HORZ
, FALSE
);
570 rect
.top
= cy
- sbHYSize
;
572 InvalidateRect(hDlg
, &rect
, TRUE
);
575 if ((scOldPos
.x
!= pData
->scPos
.x
) || (scOldPos
.y
!= pData
->scPos
.y
))
578 // (scOldPos.x - pData->scPos.x),
579 (pData
->scPos
.x
- scOldPos
.x
),
580 // (scOldPos.y - pData->scPos.y),
581 (pData
->scPos
.y
- scOldPos
.y
),
586 SW_INVALIDATE
| SW_ERASE
| SW_SCROLLCHILDREN
);
588 pData
->scPos
= scOldPos
;
591 // /* Adjust the start of the visible area if we are attempting to show nonexistent areas */
592 // if ((pData->cxMin - pData->scPos.x) < cx) pData->scPos.x = pData->cxMin - cx;
593 // if ((pData->cyMin - pData->scPos.y) < cy) pData->scPos.y = pData->cyMin - cy;
594 // // InvalidateRect(GuiData->hWindow, NULL, TRUE);
596 /* Forbid resizing the control smaller than its minimal size */
597 if (cx
< pData
->cxMin
) cx
= pData
->cxMin
;
598 if (cy
< pData
->cyMin
) cy
= pData
->cyMin
;
600 if ((cx
!= pData
->cxOld
) || (cy
!= pData
->cyOld
))
602 hdwp
= BeginDeferWindowPos(8);
604 /* Move the edit boxes */
606 GetWindowRect(hDlg
, &rect
);
608 hItemWnd
= GetDlgItem(hDlg
, IDC_EVENTTEXTEDIT
);
609 GetWindowRect(hItemWnd
, &rect
);
610 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
611 // OffsetRect(&rect, 0, y);
612 // y += (cy - pData->cyOld) / 2 ; // + (cy - pData->cyOld) % 2;
613 /** y += (cy - pData->cyOld) / 2 ; // + (cy - pData->cyOld) % 2; **/
614 if (cy
>= pData
->cyOld
)
615 y
+= (cy
- pData
->cyOld
) / 2 + (cy
- pData
->cyOld
) % 2;
617 y
-= (pData
->cyOld
- cy
) / 2 + (pData
->cyOld
- cy
) % 2;
620 hdwp
= DeferWindowPos(hdwp
,
624 (rect
.right
- rect
.left
) + (cx
- pData
->cxOld
),
625 (rect
.bottom
- rect
.top
) + y
,
626 /** SWP_NOMOVE | **/ SWP_NOZORDER
| SWP_NOACTIVATE
);
628 hItemWnd
= GetDlgItem(hDlg
, IDC_DETAILS_STATIC
);
629 GetWindowRect(hItemWnd
, &rect
);
630 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
631 // OffsetRect(&rect, 0, y);
634 hdwp
= DeferWindowPos(hdwp
,
637 rect
.left
, rect
.top
+ y
,
639 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
641 hItemWnd
= GetDlgItem(hDlg
, IDC_BYTESRADIO
);
642 GetWindowRect(hItemWnd
, &rect
);
643 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
644 // OffsetRect(&rect, 0, y);
647 hdwp
= DeferWindowPos(hdwp
,
650 rect
.left
, rect
.top
+ y
,
652 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
654 hItemWnd
= GetDlgItem(hDlg
, IDC_WORDRADIO
);
655 GetWindowRect(hItemWnd
, &rect
);
656 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
657 // OffsetRect(&rect, 0, y);
660 hdwp
= DeferWindowPos(hdwp
,
663 rect
.left
, rect
.top
+ y
,
665 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
667 hItemWnd
= GetDlgItem(hDlg
, IDC_EVENTDATAEDIT
);
668 GetWindowRect(hItemWnd
, &rect
);
669 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
670 // OffsetRect(&rect, 0, y);
671 // // y -= (cy - pData->cyOld) % 2;
674 hdwp
= DeferWindowPos(hdwp
,
677 rect
.left
, rect
.top
+ y
,
678 (rect
.right
- rect
.left
) + (cx
- pData
->cxOld
),
679 (rect
.bottom
- rect
.top
) + y
,
680 SWP_NOZORDER
| SWP_NOACTIVATE
);
682 /* Move the buttons */
684 hItemWnd
= GetDlgItem(hDlg
, IDC_PREVIOUS
);
685 GetWindowRect(hItemWnd
, &rect
);
686 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
689 hdwp
= DeferWindowPos(hdwp
,
692 rect
.left
+ (cx
- pData
->cxOld
),
695 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
697 hItemWnd
= GetDlgItem(hDlg
, IDC_NEXT
);
698 GetWindowRect(hItemWnd
, &rect
);
699 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
702 hdwp
= DeferWindowPos(hdwp
,
705 rect
.left
+ (cx
- pData
->cxOld
),
708 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
710 hItemWnd
= GetDlgItem(hDlg
, IDC_COPY
);
711 GetWindowRect(hItemWnd
, &rect
);
712 MapWindowPoints(HWND_DESKTOP
/*NULL*/, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
715 hdwp
= DeferWindowPos(hdwp
,
718 rect
.left
+ (cx
- pData
->cxOld
),
721 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
724 EndDeferWindowPos(hdwp
);
733 InitDetailsDlgCtrl(HWND hDlg
, PDETAILDATA pData
)
737 HANDLE nextIcon
= LoadImageW(hInst
, MAKEINTRESOURCEW(IDI_NEXT
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
738 HANDLE prevIcon
= LoadImageW(hInst
, MAKEINTRESOURCEW(IDI_PREV
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
739 HANDLE copyIcon
= LoadImageW(hInst
, MAKEINTRESOURCEW(IDI_COPY
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
741 SendDlgItemMessageW(hDlg
, IDC_NEXT
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)nextIcon
);
742 SendDlgItemMessageW(hDlg
, IDC_PREVIOUS
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)prevIcon
);
743 SendDlgItemMessageW(hDlg
, IDC_COPY
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)copyIcon
);
745 /* Set the default read-only RichEdit color */
746 SendDlgItemMessageW(hDlg
, IDC_EVENTTEXTEDIT
, EM_SETBKGNDCOLOR
, 0, GetSysColor(COLOR_3DFACE
));
748 /* Enable RichEdit coloured and underlined links */
749 dwMask
= SendDlgItemMessageW(hDlg
, IDC_EVENTTEXTEDIT
, EM_GETEVENTMASK
, 0, 0);
750 SendDlgItemMessageW(hDlg
, IDC_EVENTTEXTEDIT
, EM_SETEVENTMASK
, 0, dwMask
| ENM_LINK
| ENM_MOUSEEVENTS
);
753 * Activate automatic URL recognition by the RichEdit control. For more information, see:
754 * https://blogs.msdn.microsoft.com/murrays/2009/08/31/automatic-richedit-hyperlinks/
755 * https://blogs.msdn.microsoft.com/murrays/2009/09/24/richedit-friendly-name-hyperlinks/
756 * https://msdn.microsoft.com/en-us/library/windows/desktop/bb787991(v=vs.85).aspx
758 SendDlgItemMessageW(hDlg
, IDC_EVENTTEXTEDIT
, EM_AUTOURLDETECT
, AURL_ENABLEURL
/* | AURL_ENABLEEAURLS */, 0);
760 /* Note that the RichEdit control never gets themed under WinXP+; one would have to write code to simulate Edit-control theming */
762 SendDlgItemMessageW(hDlg
, pData
->bDisplayWords
? IDC_WORDRADIO
: IDC_BYTESRADIO
, BM_SETCHECK
, BST_CHECKED
, 0);
763 SendDlgItemMessageW(hDlg
, IDC_EVENTDATAEDIT
, WM_SETFONT
, (WPARAM
)pData
->hMonospaceFont
, (LPARAM
)TRUE
);
766 /* Message handler for Event Details control */
769 EventDetailsCtrl(HWND hDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
773 pData
= (PDETAILDATA
)GetWindowLongPtrW(hDlg
, DWLP_USER
);
781 pData
= (PDETAILDATA
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pData
));
785 return (INT_PTR
)TRUE
;
787 SetWindowLongPtrW(hDlg
, DWLP_USER
, (LONG_PTR
)pData
);
791 PEVENTDETAIL_INFO DetailInfo
= (PEVENTDETAIL_INFO
)lParam
;
792 pData
->EventLogFilter
= DetailInfo
->EventLogFilter
;
793 pData
->iEventItem
= DetailInfo
->iEventItem
;
795 pData
->bDisplayWords
= FALSE
;
796 pData
->hMonospaceFont
= CreateMonospaceFont();
798 GetClientRect(hDlg
, &rect
);
799 pData
->cxOld
= pData
->cxMin
= rect
.right
- rect
.left
;
800 pData
->cyOld
= pData
->cyMin
= rect
.bottom
- rect
.top
;
801 pData
->scPos
.x
= pData
->scPos
.y
= 0;
803 InitDetailsDlgCtrl(hDlg
, pData
);
805 // OnSize(hDlg, pData, pData->cxOld, pData->cyOld);
806 return (INT_PTR
)TRUE
;
812 if (pData
->hMonospaceFont
)
813 DeleteObject(pData
->hMonospaceFont
);
814 HeapFree(GetProcessHeap(), 0, pData
);
816 return (INT_PTR
)TRUE
;
819 pData
->EventLogFilter
= (PEVENTLOGFILTER
)lParam
;
820 return (INT_PTR
)TRUE
;
824 pData
->iEventItem
= (INT
)lParam
;
825 if (pData
->EventLogFilter
)
827 /* Show event info in control */
828 DisplayEvent(hDlg
, pData
);
829 DisplayEventData(hDlg
, pData
);
831 return (INT_PTR
)TRUE
;
835 switch (LOWORD(wParam
))
840 BOOL bPrev
= (LOWORD(wParam
) == IDC_PREVIOUS
);
843 /* Select the previous/next item from our current one */
844 iItem
= ListView_GetNextItem(hwndListView
,
846 bPrev
? LVNI_ABOVE
: LVNI_BELOW
);
849 // TODO: Localization.
850 if (MessageBoxW(hDlg
,
852 ? L
"You have reached the beginning of the event log. Do you want to continue from the end?"
853 : L
"You have reached the end of the event log. Do you want to continue from the beginning?",
855 MB_YESNO
| MB_ICONQUESTION
)
861 /* Determine from where to restart */
863 iItem
= ListView_GetItemCount(hwndListView
) - 1;
869 * Deselect the currently selected items in the list view.
870 * (They may be different from our current one, if multiple
871 * event details are being displayed concurrently!)
874 while ((iSel
= ListView_GetNextItem(hwndListView
, iSel
, LVNI_SELECTED
)) != -1)
876 ListView_SetItemState(hwndListView
, iSel
,
877 0, LVIS_FOCUSED
| LVIS_SELECTED
);
880 /* Select the new item */
881 ListView_SetItemState(hwndListView
, iItem
,
882 LVIS_FOCUSED
| LVIS_SELECTED
,
883 LVIS_FOCUSED
| LVIS_SELECTED
);
884 ListView_EnsureVisible(hwndListView
, iItem
, FALSE
);
886 pData
->iEventItem
= iItem
;
888 /* Show event info in control */
889 if (pData
->EventLogFilter
)
891 DisplayEvent(hDlg
, pData
);
892 DisplayEventData(hDlg
, pData
);
894 return (INT_PTR
)TRUE
;
898 if (pData
->EventLogFilter
)
899 CopyEventEntry(hDlg
);
900 return (INT_PTR
)TRUE
;
905 if (pData
->EventLogFilter
)
907 pData
->bDisplayWords
= (LOWORD(wParam
) == IDC_WORDRADIO
);
908 DisplayEventData(hDlg
, pData
);
910 return (INT_PTR
)TRUE
;
920 LPNMHDR hdr
= (LPNMHDR
)lParam
;
922 if (hdr
->idFrom
== IDC_EVENTTEXTEDIT
)
927 OnLink(hDlg
, (ENLINK
*)lParam
);
937 OnScroll(hDlg
, pData
,
938 (uMsg
== WM_HSCROLL
) ? SB_HORZ
: SB_VERT
,
940 SetWindowLongPtrW(hDlg
, DWLP_MSGRESULT
, 0);
941 return (INT_PTR
)TRUE
;
945 OnSize(hDlg
, pData
, LOWORD(lParam
), HIWORD(lParam
));
946 SetWindowLongPtrW(hDlg
, DWLP_MSGRESULT
, 0);
947 return (INT_PTR
)TRUE
;
950 return (INT_PTR
)FALSE
;
954 CreateEventDetailsCtrl(HINSTANCE hInstance
,
958 return CreateDialogParamW(hInstance
,
959 MAKEINTRESOURCEW(IDD_EVENTDETAILS_CTRL
),
960 hParentWnd
, EventDetailsCtrl
, lParam
);