[SHELL32] SHChangeNotify: Add drive, remove drive (#6782)
[reactos.git] / base / applications / mscutils / eventvwr / evtdetctl.c
1 /*
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>
8 */
9
10 #include "eventvwr.h"
11 #include "evtdetctl.h"
12
13 #include <shellapi.h>
14
15 // FIXME:
16 #define EVENT_MESSAGE_EVENTTEXT_BUFFER (1024*10)
17 extern WCHAR szTitle[];
18 extern HWND hwndListView;
19 extern BOOL
20 GetEventMessage(IN LPCWSTR KeyName,
21 IN LPCWSTR SourceName,
22 IN PEVENTLOGRECORD pevlr,
23 OUT PWCHAR EventText);
24
25
26 typedef struct _DETAILDATA
27 {
28 /* Data initialized from EVENTDETAIL_INFO */
29 PEVENTLOGFILTER EventLogFilter;
30 INT iEventItem;
31
32 BOOL bDisplayWords;
33 HFONT hMonospaceFont;
34
35 INT cxMin, cyMin;
36 INT cxOld, cyOld;
37 POINT scPos;
38 } DETAILDATA, *PDETAILDATA;
39
40
41 static
42 VOID
43 DisplayEvent(
44 _In_ HWND hDlg,
45 _In_ PDETAILDATA pDetailData)
46 {
47 PEVENTLOGFILTER EventLogFilter = pDetailData->EventLogFilter;
48 INT iItem = pDetailData->iEventItem;
49 LVITEMW li;
50 PEVENTLOGRECORD pevlr;
51 BOOL bEventData;
52
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];
62
63 li.mask = LVIF_PARAM;
64 li.iItem = iItem;
65 li.iSubItem = 0;
66 ListView_GetItem(hwndListView, &li);
67
68 pevlr = (PEVENTLOGRECORD)li.lParam;
69
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));
78
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);
87
88 bEventData = (pevlr->DataLength > 0);
89 EnableDlgItem(hDlg, IDC_BYTESRADIO, bEventData);
90 EnableDlgItem(hDlg, IDC_WORDRADIO, bEventData);
91
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);
95 }
96
97 static
98 UINT
99 PrintByteDataLine(PWCHAR pBuffer, UINT uOffset, PBYTE pData, UINT uLength)
100 {
101 PWCHAR p = pBuffer;
102 UINT n, i, r = 0;
103
104 if (uOffset != 0)
105 {
106 n = swprintf(p, L"\r\n");
107 p += n;
108 r += n;
109 }
110
111 n = swprintf(p, L"%04lx:", uOffset);
112 p += n;
113 r += n;
114
115 for (i = 0; i < uLength; i++)
116 {
117 n = swprintf(p, L" %02x", pData[i]);
118 p += n;
119 r += n;
120 }
121
122 for (i = 0; i < 9 - uLength; i++)
123 {
124 n = swprintf(p, L" ");
125 p += n;
126 r += n;
127 }
128
129 for (i = 0; i < uLength; i++)
130 {
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'.');
133 p += n;
134 r += n;
135 }
136
137 return r;
138 }
139
140 static
141 UINT
142 PrintWordDataLine(PWCHAR pBuffer, UINT uOffset, PULONG pData, UINT uLength)
143 {
144 PWCHAR p = pBuffer;
145 UINT n, i, r = 0;
146
147 if (uOffset != 0)
148 {
149 n = swprintf(p, L"\r\n");
150 p += n;
151 r += n;
152 }
153
154 n = swprintf(p, L"%04lx:", uOffset);
155 p += n;
156 r += n;
157
158 for (i = 0; i < uLength / sizeof(ULONG); i++)
159 {
160 n = swprintf(p, L" %08lx", pData[i]);
161 p += n;
162 r += n;
163 }
164
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++)
167 {
168 n = swprintf(p, L" %02x", ((PBYTE)pData)[i]);
169 p += n;
170 r += n;
171 }
172
173 return r;
174 }
175
176 static
177 VOID
178 DisplayEventData(
179 _In_ HWND hDlg,
180 _In_ PDETAILDATA pDetailData)
181 {
182 BOOL bDisplayWords = pDetailData->bDisplayWords;
183 INT iItem = pDetailData->iEventItem;
184 LVITEMW li;
185 PEVENTLOGRECORD pevlr;
186
187 LPBYTE pData;
188 UINT i, uOffset;
189 UINT uBufferSize, uLineLength;
190 PWCHAR pTextBuffer, pLine;
191
192 li.mask = LVIF_PARAM;
193 li.iItem = iItem;
194 li.iSubItem = 0;
195 ListView_GetItem(hwndListView, &li);
196
197 pevlr = (PEVENTLOGRECORD)li.lParam;
198 if (pevlr->DataLength == 0)
199 {
200 SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, L"");
201 return;
202 }
203
204 if (bDisplayWords)
205 uBufferSize = ((pevlr->DataLength / 8) + 1) * 26 * sizeof(WCHAR);
206 else
207 uBufferSize = ((pevlr->DataLength / 8) + 1) * 43 * sizeof(WCHAR);
208
209 pTextBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uBufferSize);
210 if (!pTextBuffer)
211 return;
212
213 pLine = pTextBuffer;
214 uOffset = 0;
215
216 for (i = 0; i < pevlr->DataLength / 8; i++)
217 {
218 pData = (LPBYTE)((LPBYTE)pevlr + pevlr->DataOffset + uOffset);
219
220 if (bDisplayWords)
221 uLineLength = PrintWordDataLine(pLine, uOffset, (PULONG)pData, 8);
222 else
223 uLineLength = PrintByteDataLine(pLine, uOffset, pData, 8);
224 pLine = pLine + uLineLength;
225
226 uOffset += 8;
227 }
228
229 if (pevlr->DataLength % 8 != 0)
230 {
231 pData = (LPBYTE)((LPBYTE)pevlr + pevlr->DataOffset + uOffset);
232
233 if (bDisplayWords)
234 PrintWordDataLine(pLine, uOffset, (PULONG)pData, pevlr->DataLength % 8);
235 else
236 PrintByteDataLine(pLine, uOffset, pData, pevlr->DataLength % 8);
237 }
238
239 SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, pTextBuffer);
240
241 HeapFree(GetProcessHeap(), 0, pTextBuffer);
242 }
243
244 static
245 HFONT
246 CreateMonospaceFont(VOID)
247 {
248 LOGFONTW tmpFont = {0};
249 HFONT hFont;
250 HDC hDC;
251
252 hDC = GetDC(NULL);
253
254 tmpFont.lfHeight = -MulDiv(8, GetDeviceCaps(hDC, LOGPIXELSY), 72);
255 tmpFont.lfWeight = FW_NORMAL;
256 wcscpy(tmpFont.lfFaceName, L"Courier New");
257
258 hFont = CreateFontIndirectW(&tmpFont);
259
260 ReleaseDC(NULL, hDC);
261
262 return hFont;
263 }
264
265 static
266 VOID
267 CopyEventEntry(HWND hWnd)
268 {
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];
279 ULONG size = 0;
280 LPWSTR output;
281 HGLOBAL hMem;
282
283 /* Try to open the clipboard */
284 if (!OpenClipboard(hWnd))
285 return;
286
287 /* Get the formatted text needed to place the content into */
288 size += LoadStringW(hInst, IDS_COPY, tmpHeader, ARRAYSIZE(tmpHeader));
289
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));
300
301 size++; /* Null-termination */
302 size *= sizeof(WCHAR);
303
304 /*
305 * Consolidate the information into one big piece and
306 * sort out the memory needed to write to the clipboard.
307 */
308 hMem = GlobalAlloc(GMEM_MOVEABLE, size);
309 if (hMem == NULL) goto Quit;
310
311 output = GlobalLock(hMem);
312 if (output == NULL)
313 {
314 GlobalFree(hMem);
315 goto Quit;
316 }
317
318 StringCbPrintfW(output, size,
319 tmpHeader, szEventType, szSource, szCategory, szEventID,
320 szDate, szTime, szUser, szComputer, evtDesc);
321
322 GlobalUnlock(hMem);
323
324 /* We succeeded, empty the clipboard and write the data in it */
325 EmptyClipboard();
326 SetClipboardData(CF_UNICODETEXT, hMem);
327
328 Quit:
329 /* Close the clipboard once we are done with it */
330 CloseClipboard();
331 }
332
333 static
334 VOID
335 OnLink(HWND hDlg, ENLINK* penLink)
336 {
337 LPWSTR pLink;
338 TEXTRANGE txtRange;
339
340 ASSERT(penLink->nmhdr.idFrom == IDC_EVENTTEXTEDIT);
341
342 /* Only act on left button up events */
343 if (penLink->msg != WM_LBUTTONUP)
344 return;
345
346 /* If the range is empty, do nothing */
347 if (penLink->chrg.cpMin == penLink->chrg.cpMax)
348 return;
349
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));
354 if (!pLink)
355 {
356 /* Not enough memory, bail out */
357 return;
358 }
359
360 txtRange.chrg = penLink->chrg;
361 txtRange.lpstrText = pLink;
362 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_GETTEXTRANGE, 0, (LPARAM)&txtRange);
363
364 /* Open the link */
365 ShellExecuteW(hDlg, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
366
367 /* Free the buffer */
368 HeapFree(GetProcessHeap(), 0, pLink);
369 }
370
371 static
372 VOID
373 OnScroll(HWND hDlg, PDETAILDATA pData, INT nBar, WORD sbCode)
374 {
375 RECT rect;
376
377 SCROLLINFO sInfo;
378 INT oldPos, Maximum;
379 PLONG pOriginXY;
380
381 ASSERT(nBar == SB_HORZ || nBar == SB_VERT);
382
383 GetClientRect(hDlg, &rect);
384
385 if (nBar == SB_HORZ)
386 {
387 Maximum = pData->cxMin - (rect.right-rect.left) /* pData->cxOld */;
388 pOriginXY = &pData->scPos.x;
389 }
390 else // if (nBar == SB_VERT)
391 {
392 Maximum = pData->cyMin - (rect.bottom-rect.top) /* pData->cyOld */;
393 pOriginXY = &pData->scPos.y;
394 }
395
396 /* Set scrollbar sizes */
397 sInfo.cbSize = sizeof(sInfo);
398 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
399
400 if (!GetScrollInfo(hDlg, nBar, &sInfo))
401 return;
402
403 oldPos = sInfo.nPos;
404
405 switch (sbCode)
406 {
407 case SB_LINEUP: // SB_LINELEFT:
408 sInfo.nPos--;
409 break;
410
411 case SB_LINEDOWN: // SB_LINERIGHT:
412 sInfo.nPos++;
413 break;
414
415 case SB_PAGEUP: // SB_PAGELEFT:
416 sInfo.nPos -= sInfo.nPage;
417 break;
418
419 case SB_PAGEDOWN: // SB_PAGERIGHT:
420 sInfo.nPos += sInfo.nPage;
421 break;
422
423 case SB_THUMBTRACK:
424 sInfo.nPos = sInfo.nTrackPos;
425 break;
426
427 case SB_THUMBPOSITION:
428 sInfo.nPos = sInfo.nTrackPos;
429 break;
430
431 case SB_TOP: // SB_LEFT:
432 sInfo.nPos = sInfo.nMin;
433 break;
434
435 case SB_BOTTOM: // SB_RIGHT:
436 sInfo.nPos = sInfo.nMax;
437 break;
438
439 default:
440 break;
441 }
442
443 sInfo.nPos = min(max(sInfo.nPos, 0), Maximum);
444
445 if (oldPos != sInfo.nPos)
446 {
447 POINT scOldPos = pData->scPos;
448
449 /* We now modify pData->scPos */
450 *pOriginXY = sInfo.nPos;
451
452 ScrollWindowEx(hDlg,
453 (scOldPos.x - pData->scPos.x),
454 (scOldPos.y - pData->scPos.y),
455 NULL,
456 NULL,
457 NULL,
458 NULL,
459 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
460
461 sInfo.fMask = SIF_POS;
462 SetScrollInfo(hDlg, nBar, &sInfo, TRUE);
463
464 // UpdateWindow(hDlg);
465 }
466 }
467
468 static
469 VOID
470 OnSize(HWND hDlg, PDETAILDATA pData, INT cx, INT cy)
471 {
472 LONG_PTR dwStyle;
473 INT sbVXSize, sbHYSize;
474 SCROLLINFO sInfo;
475 POINT scOldPos;
476 HDWP hdwp;
477 HWND hItemWnd;
478 RECT rect;
479 INT y = 0;
480
481 if (!pData)
482 return;
483
484 dwStyle = GetWindowLongPtrW(hDlg, GWL_STYLE);
485 sbVXSize = GetSystemMetrics(SM_CXVSCROLL);
486 sbHYSize = GetSystemMetrics(SM_CYHSCROLL);
487
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
491
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
495
496 /* Set scrollbar sizes */
497 sInfo.cbSize = sizeof(sInfo);
498
499 sInfo.fMask = SIF_POS;
500 if (GetScrollInfo(hDlg, SB_VERT, &sInfo))
501 scOldPos.y = sInfo.nPos;
502 else
503 scOldPos.y = pData->scPos.y;
504
505 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
506 sInfo.nMin = 0;
507 if (pData->cyMin > cy)
508 {
509 sInfo.nMax = pData->cyMin - 1;
510 sInfo.nPage = cy;
511 sInfo.nPos = pData->scPos.y;
512 SetScrollInfo(hDlg, SB_VERT, &sInfo, TRUE);
513
514 /* Display the scrollbar if needed */
515 if (!(dwStyle & WS_VSCROLL))
516 ShowScrollBar(hDlg, SB_VERT, TRUE);
517 }
518 else
519 {
520 scOldPos.y = 0;
521
522 sInfo.nMax = pData->cyMin - 1;
523 sInfo.nPage = cy;
524 sInfo.nPos = pData->scPos.y;
525 sInfo.nPos = scOldPos.y;
526 SetScrollInfo(hDlg, SB_VERT, &sInfo, TRUE);
527
528 ShowScrollBar(hDlg, SB_VERT, FALSE);
529
530 rect.left = cx - sbVXSize;
531 rect.right = cx;
532 rect.top = 0;
533 rect.bottom = cy;
534 InvalidateRect(hDlg, &rect, TRUE);
535 }
536
537 sInfo.fMask = SIF_POS;
538 if (GetScrollInfo(hDlg, SB_HORZ, &sInfo))
539 scOldPos.x = sInfo.nPos;
540 else
541 scOldPos.x = pData->scPos.x;
542
543 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
544 sInfo.nMin = 0;
545 if (pData->cxMin > cx)
546 {
547 sInfo.nMax = pData->cxMin - 1;
548 sInfo.nPage = cx;
549 sInfo.nPos = pData->scPos.x;
550 SetScrollInfo(hDlg, SB_HORZ, &sInfo, TRUE);
551
552 /* Display the scrollbar if needed */
553 if (!(dwStyle & WS_HSCROLL))
554 ShowScrollBar(hDlg, SB_HORZ, TRUE);
555 }
556 else
557 {
558 scOldPos.x = 0;
559
560 sInfo.nMax = pData->cxMin - 1;
561 sInfo.nPage = cx;
562 sInfo.nPos = pData->scPos.x;
563 sInfo.nPos = scOldPos.x;
564 SetScrollInfo(hDlg, SB_HORZ, &sInfo, TRUE);
565
566 ShowScrollBar(hDlg, SB_HORZ, FALSE);
567
568 rect.left = 0;
569 rect.right = cx;
570 rect.top = cy - sbHYSize;
571 rect.bottom = cy;
572 InvalidateRect(hDlg, &rect, TRUE);
573 }
574
575 if ((scOldPos.x != pData->scPos.x) || (scOldPos.y != pData->scPos.y))
576 {
577 ScrollWindowEx(hDlg,
578 // (scOldPos.x - pData->scPos.x),
579 (pData->scPos.x - scOldPos.x),
580 // (scOldPos.y - pData->scPos.y),
581 (pData->scPos.y - scOldPos.y),
582 NULL,
583 NULL,
584 NULL,
585 NULL,
586 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
587
588 pData->scPos = scOldPos;
589 }
590
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);
595
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;
599
600 if ((cx != pData->cxOld) || (cy != pData->cyOld))
601 {
602 hdwp = BeginDeferWindowPos(8);
603
604 /* Move the edit boxes */
605
606 GetWindowRect(hDlg, &rect);
607
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;
616 else
617 y -= (pData->cyOld - cy) / 2 + (pData->cyOld - cy) % 2;
618
619 if (hdwp)
620 hdwp = DeferWindowPos(hdwp,
621 hItemWnd,
622 0,
623 rect.left, rect.top,
624 (rect.right - rect.left) + (cx - pData->cxOld),
625 (rect.bottom - rect.top) + y,
626 /** SWP_NOMOVE | **/ SWP_NOZORDER | SWP_NOACTIVATE);
627
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);
632
633 if (hdwp)
634 hdwp = DeferWindowPos(hdwp,
635 hItemWnd,
636 0,
637 rect.left, rect.top + y,
638 0, 0,
639 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
640
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);
645
646 if (hdwp)
647 hdwp = DeferWindowPos(hdwp,
648 hItemWnd,
649 0,
650 rect.left, rect.top + y,
651 0, 0,
652 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
653
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);
658
659 if (hdwp)
660 hdwp = DeferWindowPos(hdwp,
661 hItemWnd,
662 0,
663 rect.left, rect.top + y,
664 0, 0,
665 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
666
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;
672
673 if (hdwp)
674 hdwp = DeferWindowPos(hdwp,
675 hItemWnd,
676 0,
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);
681
682 /* Move the buttons */
683
684 hItemWnd = GetDlgItem(hDlg, IDC_PREVIOUS);
685 GetWindowRect(hItemWnd, &rect);
686 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
687
688 if (hdwp)
689 hdwp = DeferWindowPos(hdwp,
690 hItemWnd,
691 0,
692 rect.left + (cx - pData->cxOld),
693 rect.top,
694 0, 0,
695 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
696
697 hItemWnd = GetDlgItem(hDlg, IDC_NEXT);
698 GetWindowRect(hItemWnd, &rect);
699 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
700
701 if (hdwp)
702 hdwp = DeferWindowPos(hdwp,
703 hItemWnd,
704 0,
705 rect.left + (cx - pData->cxOld),
706 rect.top,
707 0, 0,
708 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
709
710 hItemWnd = GetDlgItem(hDlg, IDC_COPY);
711 GetWindowRect(hItemWnd, &rect);
712 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
713
714 if (hdwp)
715 hdwp = DeferWindowPos(hdwp,
716 hItemWnd,
717 0,
718 rect.left + (cx - pData->cxOld),
719 rect.top,
720 0, 0,
721 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
722
723 if (hdwp)
724 EndDeferWindowPos(hdwp);
725
726 pData->cxOld = cx;
727 pData->cyOld = cy;
728 }
729 }
730
731 static
732 VOID
733 InitDetailsDlgCtrl(HWND hDlg, PDETAILDATA pData)
734 {
735 DWORD dwMask;
736
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);
740
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);
744
745 /* Set the default read-only RichEdit color */
746 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_3DFACE));
747
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);
751
752 /*
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
757 */
758 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_AUTOURLDETECT, AURL_ENABLEURL /* | AURL_ENABLEEAURLS */, 0);
759
760 /* Note that the RichEdit control never gets themed under WinXP+; one would have to write code to simulate Edit-control theming */
761
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);
764 }
765
766 /* Message handler for Event Details control */
767 static
768 INT_PTR CALLBACK
769 EventDetailsCtrl(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
770 {
771 PDETAILDATA pData;
772
773 pData = (PDETAILDATA)GetWindowLongPtrW(hDlg, DWLP_USER);
774
775 switch (uMsg)
776 {
777 case WM_INITDIALOG:
778 {
779 RECT rect;
780
781 pData = (PDETAILDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pData));
782 if (!pData)
783 {
784 EndDialog(hDlg, 0);
785 return (INT_PTR)TRUE;
786 }
787 SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)pData);
788
789 if (lParam != 0)
790 {
791 PEVENTDETAIL_INFO DetailInfo = (PEVENTDETAIL_INFO)lParam;
792 pData->EventLogFilter = DetailInfo->EventLogFilter;
793 pData->iEventItem = DetailInfo->iEventItem;
794 }
795 pData->bDisplayWords = FALSE;
796 pData->hMonospaceFont = CreateMonospaceFont();
797
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;
802
803 InitDetailsDlgCtrl(hDlg, pData);
804
805 // OnSize(hDlg, pData, pData->cxOld, pData->cyOld);
806 return (INT_PTR)TRUE;
807 }
808
809 case WM_DESTROY:
810 if (pData)
811 {
812 if (pData->hMonospaceFont)
813 DeleteObject(pData->hMonospaceFont);
814 HeapFree(GetProcessHeap(), 0, pData);
815 }
816 return (INT_PTR)TRUE;
817
818 case EVT_SETFILTER:
819 pData->EventLogFilter = (PEVENTLOGFILTER)lParam;
820 return (INT_PTR)TRUE;
821
822 case EVT_DISPLAY:
823 {
824 pData->iEventItem = (INT)lParam;
825 if (pData->EventLogFilter)
826 {
827 /* Show event info in control */
828 DisplayEvent(hDlg, pData);
829 DisplayEventData(hDlg, pData);
830 }
831 return (INT_PTR)TRUE;
832 }
833
834 case WM_COMMAND:
835 switch (LOWORD(wParam))
836 {
837 case IDC_PREVIOUS:
838 case IDC_NEXT:
839 {
840 BOOL bPrev = (LOWORD(wParam) == IDC_PREVIOUS);
841 INT iItem, iSel;
842
843 /* Select the previous/next item from our current one */
844 iItem = ListView_GetNextItem(hwndListView,
845 pData->iEventItem,
846 bPrev ? LVNI_ABOVE : LVNI_BELOW);
847 if (iItem == -1)
848 {
849 // TODO: Localization.
850 if (MessageBoxW(hDlg,
851 bPrev
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?",
854 szTitle,
855 MB_YESNO | MB_ICONQUESTION)
856 == IDNO)
857 {
858 break;
859 }
860
861 /* Determine from where to restart */
862 if (bPrev)
863 iItem = ListView_GetItemCount(hwndListView) - 1;
864 else
865 iItem = 0;
866 }
867
868 /*
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!)
872 */
873 iSel = -1;
874 while ((iSel = ListView_GetNextItem(hwndListView, iSel, LVNI_SELECTED)) != -1)
875 {
876 ListView_SetItemState(hwndListView, iSel,
877 0, LVIS_FOCUSED | LVIS_SELECTED);
878 }
879
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);
885
886 pData->iEventItem = iItem;
887
888 /* Show event info in control */
889 if (pData->EventLogFilter)
890 {
891 DisplayEvent(hDlg, pData);
892 DisplayEventData(hDlg, pData);
893 }
894 return (INT_PTR)TRUE;
895 }
896
897 case IDC_COPY:
898 if (pData->EventLogFilter)
899 CopyEventEntry(hDlg);
900 return (INT_PTR)TRUE;
901
902 case IDC_BYTESRADIO:
903 case IDC_WORDRADIO:
904 {
905 if (pData->EventLogFilter)
906 {
907 pData->bDisplayWords = (LOWORD(wParam) == IDC_WORDRADIO);
908 DisplayEventData(hDlg, pData);
909 }
910 return (INT_PTR)TRUE;
911 }
912
913 default:
914 break;
915 }
916 break;
917
918 case WM_NOTIFY:
919 {
920 LPNMHDR hdr = (LPNMHDR)lParam;
921
922 if (hdr->idFrom == IDC_EVENTTEXTEDIT)
923 {
924 switch (hdr->code)
925 {
926 case EN_LINK:
927 OnLink(hDlg, (ENLINK*)lParam);
928 break;
929 }
930 }
931 break;
932 }
933
934 case WM_HSCROLL:
935 case WM_VSCROLL:
936 {
937 OnScroll(hDlg, pData,
938 (uMsg == WM_HSCROLL) ? SB_HORZ : SB_VERT,
939 LOWORD(wParam));
940 SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
941 return (INT_PTR)TRUE;
942 }
943
944 case WM_SIZE:
945 OnSize(hDlg, pData, LOWORD(lParam), HIWORD(lParam));
946 SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
947 return (INT_PTR)TRUE;
948 }
949
950 return (INT_PTR)FALSE;
951 }
952
953 HWND
954 CreateEventDetailsCtrl(HINSTANCE hInstance,
955 HWND hParentWnd,
956 LPARAM lParam)
957 {
958 return CreateDialogParamW(hInstance,
959 MAKEINTRESOURCEW(IDD_EVENTDETAILS_CTRL),
960 hParentWnd, EventDetailsCtrl, lParam);
961 }