[EVENTVWR] Additions for the Event Viewer.
[reactos.git] / base / applications / mscutils / eventvwr / evtdetctl.c
1 /*
2 * PROJECT: ReactOS Event Log Viewer
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/mscutils/eventvwr/evtdetctl.c
5 * PURPOSE: Event Details Control
6 * PROGRAMMERS: Marc Piulachs (marc.piulachs at codexchange [dot] net)
7 * Eric Kohl
8 * Hermes Belusca-Maito
9 */
10
11 #include "eventvwr.h"
12 #include "evtdetctl.h"
13
14 #include <shellapi.h>
15
16 // FIXME:
17 #define EVENT_MESSAGE_EVENTTEXT_BUFFER 1024*10
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 PEVENTLOGFILTER EventLogFilter;
29
30 BOOL bDisplayWords;
31 HFONT hMonospaceFont;
32
33 INT cxMin, cyMin;
34 INT cxOld, cyOld;
35 POINT scPos;
36 } DETAILDATA, *PDETAILDATA;
37
38
39 static
40 VOID
41 DisplayEvent(HWND hDlg, PEVENTLOGFILTER EventLogFilter)
42 {
43 WCHAR szEventType[MAX_PATH];
44 WCHAR szTime[MAX_PATH];
45 WCHAR szDate[MAX_PATH];
46 WCHAR szUser[MAX_PATH];
47 WCHAR szComputer[MAX_PATH];
48 WCHAR szSource[MAX_PATH];
49 WCHAR szCategory[MAX_PATH];
50 WCHAR szEventID[MAX_PATH];
51 WCHAR szEventText[EVENT_MESSAGE_EVENTTEXT_BUFFER];
52 BOOL bEventData = FALSE;
53 LVITEMW li;
54 PEVENTLOGRECORD pevlr;
55 int iIndex;
56
57 /* Get index of selected item */
58 iIndex = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED | LVNI_FOCUSED);
59 if (iIndex == -1)
60 {
61 MessageBoxW(hDlg,
62 L"No Items in ListView",
63 L"Error",
64 MB_OK | MB_ICONINFORMATION);
65 return;
66 }
67
68 li.mask = LVIF_PARAM;
69 li.iItem = iIndex;
70 li.iSubItem = 0;
71
72 ListView_GetItem(hwndListView, &li);
73
74 pevlr = (PEVENTLOGRECORD)li.lParam;
75
76 ListView_GetItemText(hwndListView, iIndex, 0, szEventType, ARRAYSIZE(szEventType));
77 ListView_GetItemText(hwndListView, iIndex, 1, szDate, ARRAYSIZE(szDate));
78 ListView_GetItemText(hwndListView, iIndex, 2, szTime, ARRAYSIZE(szTime));
79 ListView_GetItemText(hwndListView, iIndex, 3, szSource, ARRAYSIZE(szSource));
80 ListView_GetItemText(hwndListView, iIndex, 4, szCategory, ARRAYSIZE(szCategory));
81 ListView_GetItemText(hwndListView, iIndex, 5, szEventID, ARRAYSIZE(szEventID));
82 ListView_GetItemText(hwndListView, iIndex, 6, szUser, ARRAYSIZE(szUser));
83 ListView_GetItemText(hwndListView, iIndex, 7, szComputer, ARRAYSIZE(szComputer));
84
85 SetDlgItemTextW(hDlg, IDC_EVENTDATESTATIC, szDate);
86 SetDlgItemTextW(hDlg, IDC_EVENTTIMESTATIC, szTime);
87 SetDlgItemTextW(hDlg, IDC_EVENTUSERSTATIC, szUser);
88 SetDlgItemTextW(hDlg, IDC_EVENTSOURCESTATIC, szSource);
89 SetDlgItemTextW(hDlg, IDC_EVENTCOMPUTERSTATIC, szComputer);
90 SetDlgItemTextW(hDlg, IDC_EVENTCATEGORYSTATIC, szCategory);
91 SetDlgItemTextW(hDlg, IDC_EVENTIDSTATIC, szEventID);
92 SetDlgItemTextW(hDlg, IDC_EVENTTYPESTATIC, szEventType);
93
94 bEventData = (pevlr->DataLength > 0);
95 EnableDlgItem(hDlg, IDC_BYTESRADIO, bEventData);
96 EnableDlgItem(hDlg, IDC_WORDRADIO, bEventData);
97
98 // FIXME: At the moment we support only one event log in the filter
99 GetEventMessage(EventLogFilter->EventLogs[0]->LogName, szSource, pevlr, szEventText);
100 SetDlgItemTextW(hDlg, IDC_EVENTTEXTEDIT, szEventText);
101 }
102
103 static
104 UINT
105 PrintByteDataLine(PWCHAR pBuffer, UINT uOffset, PBYTE pData, UINT uLength)
106 {
107 PWCHAR p = pBuffer;
108 UINT n, i, r = 0;
109
110 if (uOffset != 0)
111 {
112 n = swprintf(p, L"\r\n");
113 p += n;
114 r += n;
115 }
116
117 n = swprintf(p, L"%04lx:", uOffset);
118 p += n;
119 r += n;
120
121 for (i = 0; i < uLength; i++)
122 {
123 n = swprintf(p, L" %02x", pData[i]);
124 p += n;
125 r += n;
126 }
127
128 for (i = 0; i < 9 - uLength; i++)
129 {
130 n = swprintf(p, L" ");
131 p += n;
132 r += n;
133 }
134
135 for (i = 0; i < uLength; i++)
136 {
137 // NOTE: Normally iswprint should return FALSE for tabs...
138 n = swprintf(p, L"%c", (iswprint(pData[i]) && (pData[i] != L'\t')) ? pData[i] : L'.');
139 p += n;
140 r += n;
141 }
142
143 return r;
144 }
145
146 static
147 UINT
148 PrintWordDataLine(PWCHAR pBuffer, UINT uOffset, PULONG pData, UINT uLength)
149 {
150 PWCHAR p = pBuffer;
151 UINT n, i, r = 0;
152
153 if (uOffset != 0)
154 {
155 n = swprintf(p, L"\r\n");
156 p += n;
157 r += n;
158 }
159
160 n = swprintf(p, L"%04lx:", uOffset);
161 p += n;
162 r += n;
163
164 for (i = 0; i < uLength / sizeof(ULONG); i++)
165 {
166 n = swprintf(p, L" %08lx", pData[i]);
167 p += n;
168 r += n;
169 }
170
171 /* Display the remaining bytes if uLength was not a multiple of sizeof(ULONG) */
172 for (i = (uLength / sizeof(ULONG)) * sizeof(ULONG); i < uLength; i++)
173 {
174 n = swprintf(p, L" %02x", ((PBYTE)pData)[i]);
175 p += n;
176 r += n;
177 }
178
179 return r;
180 }
181
182 static
183 VOID
184 DisplayEventData(HWND hDlg, BOOL bDisplayWords)
185 {
186 LVITEMW li;
187 PEVENTLOGRECORD pevlr;
188 int iIndex;
189
190 LPBYTE pData;
191 UINT i, uOffset;
192 UINT uBufferSize, uLineLength;
193 PWCHAR pTextBuffer, pLine;
194
195 /* Get index of selected item */
196 iIndex = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED | LVNI_FOCUSED);
197 if (iIndex == -1)
198 {
199 MessageBoxW(hDlg,
200 L"No Items in ListView",
201 L"Error",
202 MB_OK | MB_ICONINFORMATION);
203 return;
204 }
205
206 li.mask = LVIF_PARAM;
207 li.iItem = iIndex;
208 li.iSubItem = 0;
209
210 ListView_GetItem(hwndListView, &li);
211
212 pevlr = (PEVENTLOGRECORD)li.lParam;
213 if (pevlr->DataLength == 0)
214 {
215 SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, L"");
216 return;
217 }
218
219 if (bDisplayWords)
220 uBufferSize = ((pevlr->DataLength / 8) + 1) * 26 * sizeof(WCHAR);
221 else
222 uBufferSize = ((pevlr->DataLength / 8) + 1) * 43 * sizeof(WCHAR);
223
224 pTextBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uBufferSize);
225 if (!pTextBuffer)
226 return;
227
228 pLine = pTextBuffer;
229 uOffset = 0;
230
231 for (i = 0; i < pevlr->DataLength / 8; i++)
232 {
233 pData = (LPBYTE)((LPBYTE)pevlr + pevlr->DataOffset + uOffset);
234
235 if (bDisplayWords)
236 uLineLength = PrintWordDataLine(pLine, uOffset, (PULONG)pData, 8);
237 else
238 uLineLength = PrintByteDataLine(pLine, uOffset, pData, 8);
239 pLine = pLine + uLineLength;
240
241 uOffset += 8;
242 }
243
244 if (pevlr->DataLength % 8 != 0)
245 {
246 pData = (LPBYTE)((LPBYTE)pevlr + pevlr->DataOffset + uOffset);
247
248 if (bDisplayWords)
249 PrintWordDataLine(pLine, uOffset, (PULONG)pData, pevlr->DataLength % 8);
250 else
251 PrintByteDataLine(pLine, uOffset, pData, pevlr->DataLength % 8);
252 }
253
254 SetDlgItemTextW(hDlg, IDC_EVENTDATAEDIT, pTextBuffer);
255
256 HeapFree(GetProcessHeap(), 0, pTextBuffer);
257 }
258
259 static
260 HFONT
261 CreateMonospaceFont(VOID)
262 {
263 LOGFONTW tmpFont = {0};
264 HFONT hFont;
265 HDC hDC;
266
267 hDC = GetDC(NULL);
268
269 tmpFont.lfHeight = -MulDiv(8, GetDeviceCaps(hDC, LOGPIXELSY), 72);
270 tmpFont.lfWeight = FW_NORMAL;
271 wcscpy(tmpFont.lfFaceName, L"Courier New");
272
273 hFont = CreateFontIndirectW(&tmpFont);
274
275 ReleaseDC(NULL, hDC);
276
277 return hFont;
278 }
279
280 static
281 VOID
282 CopyEventEntry(HWND hWnd)
283 {
284 WCHAR tmpHeader[512];
285 WCHAR szEventType[MAX_PATH];
286 WCHAR szSource[MAX_PATH];
287 WCHAR szCategory[MAX_PATH];
288 WCHAR szEventID[MAX_PATH];
289 WCHAR szDate[MAX_PATH];
290 WCHAR szTime[MAX_PATH];
291 WCHAR szUser[MAX_PATH];
292 WCHAR szComputer[MAX_PATH];
293 WCHAR evtDesc[EVENT_MESSAGE_EVENTTEXT_BUFFER];
294 ULONG size = 0;
295 LPWSTR output;
296 HGLOBAL hMem;
297
298 /* Try to open the clipboard */
299 if (!OpenClipboard(hWnd))
300 return;
301
302 /* Get the formatted text needed to place the content into */
303 size += LoadStringW(hInst, IDS_COPY, tmpHeader, ARRAYSIZE(tmpHeader));
304
305 /* Grab all the information and get it ready for the clipboard */
306 size += GetDlgItemTextW(hWnd, IDC_EVENTTYPESTATIC, szEventType, ARRAYSIZE(szEventType));
307 size += GetDlgItemTextW(hWnd, IDC_EVENTSOURCESTATIC, szSource, ARRAYSIZE(szSource));
308 size += GetDlgItemTextW(hWnd, IDC_EVENTCATEGORYSTATIC, szCategory, ARRAYSIZE(szCategory));
309 size += GetDlgItemTextW(hWnd, IDC_EVENTIDSTATIC, szEventID, ARRAYSIZE(szEventID));
310 size += GetDlgItemTextW(hWnd, IDC_EVENTDATESTATIC, szDate, ARRAYSIZE(szDate));
311 size += GetDlgItemTextW(hWnd, IDC_EVENTTIMESTATIC, szTime, ARRAYSIZE(szTime));
312 size += GetDlgItemTextW(hWnd, IDC_EVENTUSERSTATIC, szUser, ARRAYSIZE(szUser));
313 size += GetDlgItemTextW(hWnd, IDC_EVENTCOMPUTERSTATIC, szComputer, ARRAYSIZE(szComputer));
314 size += GetDlgItemTextW(hWnd, IDC_EVENTTEXTEDIT, evtDesc, ARRAYSIZE(evtDesc));
315
316 size++; /* Null-termination */
317 size *= sizeof(WCHAR);
318
319 /*
320 * Consolidate the information into one big piece and
321 * sort out the memory needed to write to the clipboard.
322 */
323 hMem = GlobalAlloc(GMEM_MOVEABLE, size);
324 if (hMem == NULL) goto Quit;
325
326 output = GlobalLock(hMem);
327 if (output == NULL)
328 {
329 GlobalFree(hMem);
330 goto Quit;
331 }
332
333 StringCbPrintfW(output, size,
334 tmpHeader, szEventType, szSource, szCategory, szEventID,
335 szDate, szTime, szUser, szComputer, evtDesc);
336
337 GlobalUnlock(hMem);
338
339 /* We succeeded, empty the clipboard and write the data in it */
340 EmptyClipboard();
341 SetClipboardData(CF_UNICODETEXT, hMem);
342
343 Quit:
344 /* Close the clipboard once we are done with it */
345 CloseClipboard();
346 }
347
348 static
349 VOID
350 OnLink(HWND hDlg, ENLINK* penLink)
351 {
352 LPWSTR pLink;
353 TEXTRANGE txtRange;
354
355 ASSERT(penLink->nmhdr.idFrom == IDC_EVENTTEXTEDIT);
356
357 /* Only act on left button up events */
358 if (penLink->msg != WM_LBUTTONUP)
359 return;
360
361 /* If the range is empty, do nothing */
362 if (penLink->chrg.cpMin == penLink->chrg.cpMax)
363 return;
364
365 /* Allocate memory for the text link */
366 pLink = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
367 (max(penLink->chrg.cpMin, penLink->chrg.cpMax) -
368 min(penLink->chrg.cpMin, penLink->chrg.cpMax) + 1) * sizeof(WCHAR));
369 if (!pLink)
370 {
371 /* Not enough memory, bail out */
372 return;
373 }
374
375 txtRange.chrg = penLink->chrg;
376 txtRange.lpstrText = pLink;
377 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_GETTEXTRANGE, 0, (LPARAM)&txtRange);
378
379 /* Open the link */
380 ShellExecuteW(hDlg, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
381
382 /* Free the buffer */
383 HeapFree(GetProcessHeap(), 0, pLink);
384 }
385
386 static
387 VOID
388 OnScroll(HWND hDlg, PDETAILDATA pData, INT nBar, WORD sbCode)
389 {
390 RECT rect;
391
392 SCROLLINFO sInfo;
393 INT oldPos, Maximum;
394 PLONG pOriginXY;
395
396 ASSERT(nBar == SB_HORZ || nBar == SB_VERT);
397
398 GetClientRect(hDlg, &rect);
399
400 if (nBar == SB_HORZ)
401 {
402 Maximum = pData->cxMin - (rect.right-rect.left) /* pData->cxOld */;
403 pOriginXY = &pData->scPos.x;
404 }
405 else // if (nBar == SB_VERT)
406 {
407 Maximum = pData->cyMin - (rect.bottom-rect.top) /* pData->cyOld */;
408 pOriginXY = &pData->scPos.y;
409 }
410
411 /* Set scrollbar sizes */
412 sInfo.cbSize = sizeof(sInfo);
413 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
414
415 if (!GetScrollInfo(hDlg, nBar, &sInfo))
416 return;
417
418 oldPos = sInfo.nPos;
419
420 switch (sbCode)
421 {
422 case SB_LINEUP: // SB_LINELEFT:
423 sInfo.nPos--;
424 break;
425
426 case SB_LINEDOWN: // SB_LINERIGHT:
427 sInfo.nPos++;
428 break;
429
430 case SB_PAGEUP: // SB_PAGELEFT:
431 sInfo.nPos -= sInfo.nPage;
432 break;
433
434 case SB_PAGEDOWN: // SB_PAGERIGHT:
435 sInfo.nPos += sInfo.nPage;
436 break;
437
438 case SB_THUMBTRACK:
439 sInfo.nPos = sInfo.nTrackPos;
440 break;
441
442 case SB_THUMBPOSITION:
443 sInfo.nPos = sInfo.nTrackPos;
444 break;
445
446 case SB_TOP: // SB_LEFT:
447 sInfo.nPos = sInfo.nMin;
448 break;
449
450 case SB_BOTTOM: // SB_RIGHT:
451 sInfo.nPos = sInfo.nMax;
452 break;
453
454 default:
455 break;
456 }
457
458 sInfo.nPos = min(max(sInfo.nPos, 0), Maximum);
459
460 if (oldPos != sInfo.nPos)
461 {
462 POINT scOldPos = pData->scPos;
463
464 /* We now modify pData->scPos */
465 *pOriginXY = sInfo.nPos;
466
467 ScrollWindowEx(hDlg,
468 (scOldPos.x - pData->scPos.x),
469 (scOldPos.y - pData->scPos.y),
470 NULL,
471 NULL,
472 NULL,
473 NULL,
474 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
475
476 sInfo.fMask = SIF_POS;
477 SetScrollInfo(hDlg, nBar, &sInfo, TRUE);
478
479 // UpdateWindow(hDlg);
480 }
481 }
482
483 static VOID
484 OnSize(HWND hDlg, PDETAILDATA pData, INT cx, INT cy)
485 {
486 LONG_PTR dwStyle;
487 INT sbVXSize, sbHYSize;
488 SCROLLINFO sInfo;
489 POINT scOldPos;
490 HDWP hdwp;
491 HWND hItemWnd;
492 RECT rect;
493 INT y = 0;
494
495 if (!pData)
496 return;
497
498 dwStyle = GetWindowLongPtrW(hDlg, GWL_STYLE);
499 sbVXSize = GetSystemMetrics(SM_CXVSCROLL);
500 sbHYSize = GetSystemMetrics(SM_CYHSCROLL);
501
502 /* Compensate for existing scroll bars (because lParam values do not accommodate scroll bar) */
503 if (dwStyle & WS_HSCROLL) cy += sbHYSize; // Window currently has a horizontal scrollbar
504 if (dwStyle & WS_VSCROLL) cx += sbVXSize; // Window currently has a vertical scrollbar
505
506 /* Compensate for added scroll bars in window */
507 if (cx < pData->cxMin) cy -= sbHYSize; // Window will have a horizontal scroll bar
508 if (cy < pData->cyMin) cx -= sbVXSize; // Window will have a vertical scroll bar
509
510 /* Set scrollbar sizes */
511 sInfo.cbSize = sizeof(sInfo);
512
513 sInfo.fMask = SIF_POS;
514 if (GetScrollInfo(hDlg, SB_VERT, &sInfo))
515 scOldPos.y = sInfo.nPos;
516 else
517 scOldPos.y = pData->scPos.y;
518
519 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
520 sInfo.nMin = 0;
521 if (pData->cyMin > cy)
522 {
523 sInfo.nMax = pData->cyMin - 1;
524 sInfo.nPage = cy;
525 sInfo.nPos = pData->scPos.y;
526 SetScrollInfo(hDlg, SB_VERT, &sInfo, TRUE);
527
528 /* Display the scrollbar if needed */
529 if (!(dwStyle & WS_VSCROLL))
530 ShowScrollBar(hDlg, SB_VERT, TRUE);
531 }
532 else
533 {
534 scOldPos.y = 0;
535
536 sInfo.nMax = pData->cyMin - 1;
537 sInfo.nPage = cy;
538 sInfo.nPos = pData->scPos.y;
539 sInfo.nPos = scOldPos.y;
540 SetScrollInfo(hDlg, SB_VERT, &sInfo, TRUE);
541
542 ShowScrollBar(hDlg, SB_VERT, FALSE);
543
544 rect.left = cx - sbVXSize;
545 rect.right = cx;
546 rect.top = 0;
547 rect.bottom = cy;
548 InvalidateRect(hDlg, &rect, TRUE);
549 }
550
551 sInfo.fMask = SIF_POS;
552 if (GetScrollInfo(hDlg, SB_HORZ, &sInfo))
553 scOldPos.x = sInfo.nPos;
554 else
555 scOldPos.x = pData->scPos.x;
556
557 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
558 sInfo.nMin = 0;
559 if (pData->cxMin > cx)
560 {
561 sInfo.nMax = pData->cxMin - 1;
562 sInfo.nPage = cx;
563 sInfo.nPos = pData->scPos.x;
564 SetScrollInfo(hDlg, SB_HORZ, &sInfo, TRUE);
565
566 /* Display the scrollbar if needed */
567 if (!(dwStyle & WS_HSCROLL))
568 ShowScrollBar(hDlg, SB_HORZ, TRUE);
569 }
570 else
571 {
572 scOldPos.x = 0;
573
574 sInfo.nMax = pData->cxMin - 1;
575 sInfo.nPage = cx;
576 sInfo.nPos = pData->scPos.x;
577 sInfo.nPos = scOldPos.x;
578 SetScrollInfo(hDlg, SB_HORZ, &sInfo, TRUE);
579
580 ShowScrollBar(hDlg, SB_HORZ, FALSE);
581
582 rect.left = 0;
583 rect.right = cx;
584 rect.top = cy - sbHYSize;
585 rect.bottom = cy;
586 InvalidateRect(hDlg, &rect, TRUE);
587 }
588
589 if ((scOldPos.x != pData->scPos.x) || (scOldPos.y != pData->scPos.y))
590 {
591 ScrollWindowEx(hDlg,
592 // (scOldPos.x - pData->scPos.x),
593 (pData->scPos.x - scOldPos.x),
594 // (scOldPos.y - pData->scPos.y),
595 (pData->scPos.y - scOldPos.y),
596 NULL,
597 NULL,
598 NULL,
599 NULL,
600 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
601
602 pData->scPos = scOldPos;
603 }
604
605 // /* Adjust the start of the visible area if we are attempting to show nonexistent areas */
606 // if ((pData->cxMin - pData->scPos.x) < cx) pData->scPos.x = pData->cxMin - cx;
607 // if ((pData->cyMin - pData->scPos.y) < cy) pData->scPos.y = pData->cyMin - cy;
608 // // InvalidateRect(GuiData->hWindow, NULL, TRUE);
609
610 /* Forbid resizing the control smaller than its minimal size */
611 if (cx < pData->cxMin) cx = pData->cxMin;
612 if (cy < pData->cyMin) cy = pData->cyMin;
613
614 if ((cx != pData->cxOld) || (cy != pData->cyOld))
615 {
616 hdwp = BeginDeferWindowPos(8);
617
618 /* Move the edit boxes */
619
620 GetWindowRect(hDlg, &rect);
621
622 hItemWnd = GetDlgItem(hDlg, IDC_EVENTTEXTEDIT);
623 GetWindowRect(hItemWnd, &rect);
624 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
625 // OffsetRect(&rect, 0, y);
626 // y += (cy - pData->cyOld) / 2 ; // + (cy - pData->cyOld) % 2;
627 /** y += (cy - pData->cyOld) / 2 ; // + (cy - pData->cyOld) % 2; **/
628 if (cy >= pData->cyOld)
629 y += (cy - pData->cyOld) / 2 + (cy - pData->cyOld) % 2;
630 else
631 y -= (pData->cyOld - cy) / 2 + (pData->cyOld - cy) % 2;
632
633 if (hdwp)
634 hdwp = DeferWindowPos(hdwp,
635 hItemWnd,
636 0,
637 rect.left, rect.top,
638 (rect.right - rect.left) + (cx - pData->cxOld),
639 (rect.bottom - rect.top) + y,
640 /** SWP_NOMOVE | **/ SWP_NOZORDER | SWP_NOACTIVATE);
641
642 hItemWnd = GetDlgItem(hDlg, IDC_DETAILS_STATIC);
643 GetWindowRect(hItemWnd, &rect);
644 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
645 // OffsetRect(&rect, 0, y);
646
647 if (hdwp)
648 hdwp = DeferWindowPos(hdwp,
649 hItemWnd,
650 0,
651 rect.left, rect.top + y,
652 0, 0,
653 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
654
655 hItemWnd = GetDlgItem(hDlg, IDC_BYTESRADIO);
656 GetWindowRect(hItemWnd, &rect);
657 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
658 // OffsetRect(&rect, 0, y);
659
660 if (hdwp)
661 hdwp = DeferWindowPos(hdwp,
662 hItemWnd,
663 0,
664 rect.left, rect.top + y,
665 0, 0,
666 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
667
668 hItemWnd = GetDlgItem(hDlg, IDC_WORDRADIO);
669 GetWindowRect(hItemWnd, &rect);
670 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
671 // OffsetRect(&rect, 0, y);
672
673 if (hdwp)
674 hdwp = DeferWindowPos(hdwp,
675 hItemWnd,
676 0,
677 rect.left, rect.top + y,
678 0, 0,
679 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
680
681 hItemWnd = GetDlgItem(hDlg, IDC_EVENTDATAEDIT);
682 GetWindowRect(hItemWnd, &rect);
683 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
684 // OffsetRect(&rect, 0, y);
685 // // y -= (cy - pData->cyOld) % 2;
686
687 if (hdwp)
688 hdwp = DeferWindowPos(hdwp,
689 hItemWnd,
690 0,
691 rect.left, rect.top + y,
692 (rect.right - rect.left) + (cx - pData->cxOld),
693 (rect.bottom - rect.top) + y,
694 SWP_NOZORDER | SWP_NOACTIVATE);
695
696 /* Move the buttons */
697
698 hItemWnd = GetDlgItem(hDlg, IDC_PREVIOUS);
699 GetWindowRect(hItemWnd, &rect);
700 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
701
702 if (hdwp)
703 hdwp = DeferWindowPos(hdwp,
704 hItemWnd,
705 0,
706 rect.left + (cx - pData->cxOld),
707 rect.top,
708 0, 0,
709 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
710
711 hItemWnd = GetDlgItem(hDlg, IDC_NEXT);
712 GetWindowRect(hItemWnd, &rect);
713 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
714
715 if (hdwp)
716 hdwp = DeferWindowPos(hdwp,
717 hItemWnd,
718 0,
719 rect.left + (cx - pData->cxOld),
720 rect.top,
721 0, 0,
722 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
723
724 hItemWnd = GetDlgItem(hDlg, IDC_COPY);
725 GetWindowRect(hItemWnd, &rect);
726 MapWindowPoints(HWND_DESKTOP /*NULL*/, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
727
728 if (hdwp)
729 hdwp = DeferWindowPos(hdwp,
730 hItemWnd,
731 0,
732 rect.left + (cx - pData->cxOld),
733 rect.top,
734 0, 0,
735 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
736
737 if (hdwp)
738 EndDeferWindowPos(hdwp);
739
740 pData->cxOld = cx;
741 pData->cyOld = cy;
742 }
743 }
744
745 static
746 VOID
747 InitDetailsDlgCtrl(HWND hDlg, PDETAILDATA pData)
748 {
749 DWORD dwMask;
750
751 HANDLE nextIcon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_NEXT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
752 HANDLE prevIcon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_PREV), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
753 HANDLE copyIcon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_COPY), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
754
755 SendDlgItemMessageW(hDlg, IDC_NEXT, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)nextIcon);
756 SendDlgItemMessageW(hDlg, IDC_PREVIOUS, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)prevIcon);
757 SendDlgItemMessageW(hDlg, IDC_COPY, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)copyIcon);
758
759 /* Set the default read-only RichEdit color */
760 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_3DFACE));
761
762 /* Enable RichEdit coloured and underlined links */
763 dwMask = SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_GETEVENTMASK, 0, 0);
764 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_SETEVENTMASK, 0, dwMask | ENM_LINK | ENM_MOUSEEVENTS);
765
766 /*
767 * Activate automatic URL recognition by the RichEdit control. For more information, see:
768 * https://blogs.msdn.microsoft.com/murrays/2009/08/31/automatic-richedit-hyperlinks/
769 * https://blogs.msdn.microsoft.com/murrays/2009/09/24/richedit-friendly-name-hyperlinks/
770 * https://msdn.microsoft.com/en-us/library/windows/desktop/bb787991(v=vs.85).aspx
771 */
772 SendDlgItemMessageW(hDlg, IDC_EVENTTEXTEDIT, EM_AUTOURLDETECT, AURL_ENABLEURL /* | AURL_ENABLEEAURLS */, 0);
773
774 /* Note that the RichEdit control never gets themed under WinXP+; one would have to write code to simulate Edit-control theming */
775
776 SendDlgItemMessageW(hDlg, pData->bDisplayWords ? IDC_WORDRADIO : IDC_BYTESRADIO, BM_SETCHECK, BST_CHECKED, 0);
777 SendDlgItemMessageW(hDlg, IDC_EVENTDATAEDIT, WM_SETFONT, (WPARAM)pData->hMonospaceFont, (LPARAM)TRUE);
778 }
779
780 /* Message handler for Event Details control */
781 static
782 INT_PTR CALLBACK
783 EventDetailsCtrl(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
784 {
785 PDETAILDATA pData;
786
787 pData = (PDETAILDATA)GetWindowLongPtrW(hDlg, DWLP_USER);
788
789 switch (uMsg)
790 {
791 case WM_INITDIALOG:
792 {
793 RECT rect;
794
795 pData = (PDETAILDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pData));
796 if (!pData)
797 {
798 EndDialog(hDlg, 0);
799 return (INT_PTR)TRUE;
800 }
801 SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)pData);
802
803 pData->EventLogFilter = (PEVENTLOGFILTER)lParam;
804 pData->bDisplayWords = FALSE;
805 pData->hMonospaceFont = CreateMonospaceFont();
806
807 GetClientRect(hDlg, &rect);
808 pData->cxOld = pData->cxMin = rect.right - rect.left;
809 pData->cyOld = pData->cyMin = rect.bottom - rect.top;
810 pData->scPos.x = pData->scPos.y = 0;
811
812 InitDetailsDlgCtrl(hDlg, pData);
813
814 #if 0
815 /* Show event info on dialog box */
816 DisplayEvent(hDlg, pData->EventLogFilter);
817 DisplayEventData(hDlg, pData->bDisplayWords);
818 #endif
819
820 // OnSize(hDlg, pData, pData->cxOld, pData->cyOld);
821 return (INT_PTR)TRUE;
822 }
823
824 case WM_DESTROY:
825 if (pData)
826 {
827 if (pData->hMonospaceFont)
828 DeleteObject(pData->hMonospaceFont);
829 HeapFree(GetProcessHeap(), 0, pData);
830 }
831 return (INT_PTR)TRUE;
832
833 case EVT_SETFILTER:
834 pData->EventLogFilter = (PEVENTLOGFILTER)lParam;
835 return (INT_PTR)TRUE;
836
837 case EVT_DISPLAY:
838 if (pData->EventLogFilter)
839 {
840 /* Show event info on dialog box */
841 DisplayEvent(hDlg, pData->EventLogFilter);
842 DisplayEventData(hDlg, pData->bDisplayWords);
843 }
844 return (INT_PTR)TRUE;
845
846 case WM_COMMAND:
847 switch (LOWORD(wParam))
848 {
849 case IDC_PREVIOUS:
850 {
851 SendMessageW(hwndListView, WM_KEYDOWN, VK_UP, 0);
852
853 /* Show event info on dialog box */
854 if (pData->EventLogFilter)
855 {
856 DisplayEvent(hDlg, pData->EventLogFilter);
857 DisplayEventData(hDlg, pData->bDisplayWords);
858 }
859 return (INT_PTR)TRUE;
860 }
861
862 case IDC_NEXT:
863 {
864 SendMessageW(hwndListView, WM_KEYDOWN, VK_DOWN, 0);
865
866 /* Show event info on dialog box */
867 if (pData->EventLogFilter)
868 {
869 DisplayEvent(hDlg, pData->EventLogFilter);
870 DisplayEventData(hDlg, pData->bDisplayWords);
871 }
872 return (INT_PTR)TRUE;
873 }
874
875 case IDC_COPY:
876 if (pData->EventLogFilter)
877 CopyEventEntry(hDlg);
878 return (INT_PTR)TRUE;
879
880 case IDC_BYTESRADIO:
881 if (pData->EventLogFilter)
882 {
883 pData->bDisplayWords = FALSE;
884 DisplayEventData(hDlg, pData->bDisplayWords);
885 }
886 return (INT_PTR)TRUE;
887
888 case IDC_WORDRADIO:
889 if (pData->EventLogFilter)
890 {
891 pData->bDisplayWords = TRUE;
892 DisplayEventData(hDlg, pData->bDisplayWords);
893 }
894 return (INT_PTR)TRUE;
895
896 default:
897 break;
898 }
899 break;
900
901 case WM_NOTIFY:
902 {
903 LPNMHDR hdr = (LPNMHDR)lParam;
904
905 if (hdr->idFrom == IDC_EVENTTEXTEDIT)
906 {
907 switch (hdr->code)
908 {
909 case EN_LINK:
910 OnLink(hDlg, (ENLINK*)lParam);
911 break;
912 }
913 }
914 break;
915 }
916
917 case WM_HSCROLL:
918 OnScroll(hDlg, pData, SB_HORZ, LOWORD(wParam));
919 SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
920 return (INT_PTR)TRUE;
921
922 case WM_VSCROLL:
923 OnScroll(hDlg, pData, SB_VERT, LOWORD(wParam));
924 SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
925 return (INT_PTR)TRUE;
926
927 case WM_SIZE:
928 OnSize(hDlg, pData, LOWORD(lParam), HIWORD(lParam));
929 SetWindowLongPtrW(hDlg, DWLP_MSGRESULT, 0);
930 return (INT_PTR)TRUE;
931 }
932
933 return (INT_PTR)FALSE;
934 }
935
936 HWND
937 CreateEventDetailsCtrl(HINSTANCE hInstance,
938 HWND hParentWnd,
939 LPARAM lParam)
940 {
941 return CreateDialogParamW(hInstance,
942 MAKEINTRESOURCEW(IDD_EVENTDETAILS_CTRL),
943 hParentWnd, EventDetailsCtrl, lParam);
944 }