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