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 } 962