1 /* 2 * Hex editor control 3 * 4 * Copyright (C) 2004 Thomas Weidenmueller <w3seek@reactos.com> 5 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 6 */ 7 8 #include "regedit.h" 9 10 typedef struct 11 { 12 HWND hWndSelf; 13 HWND hWndParent; 14 HLOCAL hBuffer; 15 DWORD style; 16 DWORD MaxBuffer; 17 INT ColumnsPerLine; 18 INT nLines; 19 INT nVisibleLinesComplete; 20 INT nVisibleLines; 21 INT Index; 22 INT LineHeight; 23 INT CharWidth; 24 HFONT hFont; 25 BOOL SbVisible; 26 27 INT LeftMargin; 28 INT AddressSpacing; 29 INT SplitSpacing; 30 31 BOOL EditingField; 32 INT CaretCol; 33 INT CaretLine; 34 BOOL InMid; 35 36 INT SelStart; 37 INT SelEnd; 38 } HEXEDIT_DATA, *PHEXEDIT_DATA; 39 40 static const WCHAR ClipboardFormatName[] = L"RegEdit_HexData"; 41 static UINT ClipboardFormatID = 0; 42 43 /* hit test codes */ 44 #define HEHT_LEFTMARGIN (0x1) 45 #define HEHT_ADDRESS (0x2) 46 #define HEHT_ADDRESSSPACING (0x3) 47 #define HEHT_HEXDUMP (0x4) 48 #define HEHT_HEXDUMPSPACING (0x5) 49 #define HEHT_ASCIIDUMP (0x6) 50 #define HEHT_RIGHTMARGIN (0x7) 51 52 LRESULT CALLBACK HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 53 54 ATOM 55 WINAPI 56 RegisterHexEditorClass(HINSTANCE hInstance) 57 { 58 WNDCLASSEXW WndClass; 59 60 ClipboardFormatID = RegisterClipboardFormatW(ClipboardFormatName); 61 62 ZeroMemory(&WndClass, sizeof(WNDCLASSEXW)); 63 WndClass.cbSize = sizeof(WNDCLASSEXW); 64 WndClass.style = CS_DBLCLKS; 65 WndClass.lpfnWndProc = HexEditWndProc; 66 WndClass.cbWndExtra = sizeof(PHEXEDIT_DATA); 67 WndClass.hInstance = hInstance; 68 WndClass.hCursor = LoadCursorW(NULL, IDC_IBEAM); 69 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 70 WndClass.lpszClassName = HEX_EDIT_CLASS_NAME; 71 72 return RegisterClassEx(&WndClass); 73 } 74 75 BOOL 76 WINAPI 77 UnregisterHexEditorClass(HINSTANCE hInstance) 78 { 79 return UnregisterClassW(HEX_EDIT_CLASS_NAME, hInstance); 80 } 81 82 /*** Helper functions *********************************************************/ 83 84 static VOID 85 HEXEDIT_MoveCaret(PHEXEDIT_DATA hed, BOOL Scroll) 86 { 87 SCROLLINFO si; 88 89 si.cbSize = sizeof(SCROLLINFO); 90 si.fMask = SIF_POS; 91 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 92 93 if(Scroll) 94 { 95 if(si.nPos > hed->CaretLine) 96 { 97 si.nPos = hed->CaretLine; 98 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE); 99 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 100 InvalidateRect(hed->hWndSelf, NULL, TRUE); 101 } 102 else if(hed->CaretLine >= (hed->nVisibleLinesComplete + si.nPos)) 103 { 104 si.nPos = hed->CaretLine - hed->nVisibleLinesComplete + 1; 105 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE); 106 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 107 InvalidateRect(hed->hWndSelf, NULL, TRUE); 108 } 109 } 110 111 if(hed->EditingField) 112 SetCaretPos(hed->LeftMargin + ((4 + hed->AddressSpacing + (3 * hed->CaretCol) + hed->InMid * 2) * hed->CharWidth) - 1, (hed->CaretLine - si.nPos) * hed->LineHeight); 113 else 114 SetCaretPos(hed->LeftMargin + ((4 + hed->AddressSpacing + hed->SplitSpacing + (3 * hed->ColumnsPerLine) + hed->CaretCol) * hed->CharWidth) - 2, (hed->CaretLine - si.nPos) * hed->LineHeight); 115 } 116 117 static VOID 118 HEXEDIT_Update(PHEXEDIT_DATA hed) 119 { 120 SCROLLINFO si; 121 RECT rcClient; 122 BOOL SbVisible; 123 INT bufsize, cvislines; 124 125 GetClientRect(hed->hWndSelf, &rcClient); 126 hed->style = GetWindowLongPtr(hed->hWndSelf, GWL_STYLE); 127 128 bufsize = (hed->hBuffer ? (INT) LocalSize(hed->hBuffer) : 0); 129 hed->nLines = max(bufsize / hed->ColumnsPerLine, 1); 130 if(bufsize > hed->ColumnsPerLine && (bufsize % hed->ColumnsPerLine) > 0) 131 { 132 hed->nLines++; 133 } 134 135 if(hed->LineHeight > 0) 136 { 137 hed->nVisibleLinesComplete = cvislines = rcClient.bottom / hed->LineHeight; 138 hed->nVisibleLines = hed->nVisibleLinesComplete; 139 if(rcClient.bottom % hed->LineHeight) 140 { 141 hed->nVisibleLines++; 142 } 143 } 144 else 145 { 146 hed->nVisibleLines = cvislines = 0; 147 } 148 149 SbVisible = bufsize > 0 && cvislines < hed->nLines; 150 ShowScrollBar(hed->hWndSelf, SB_VERT, SbVisible); 151 152 /* update scrollbar */ 153 si.cbSize = sizeof(SCROLLINFO); 154 si.fMask = SIF_RANGE | SIF_PAGE; 155 si.nMin = 0; 156 si.nMax = ((bufsize > 0) ? hed->nLines - 1 : 0); 157 si.nPage = ((hed->LineHeight > 0) ? rcClient.bottom / hed->LineHeight : 0); 158 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE); 159 160 if(IsWindowVisible(hed->hWndSelf) && SbVisible != hed->SbVisible) 161 { 162 InvalidateRect(hed->hWndSelf, NULL, TRUE); 163 } 164 165 hed->SbVisible = SbVisible; 166 } 167 168 static HFONT 169 HEXEDIT_GetFixedFont(VOID) 170 { 171 LOGFONT lf; 172 GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT), &lf); 173 return CreateFontIndirect(&lf); 174 } 175 176 static VOID 177 HEXEDIT_PaintLines(PHEXEDIT_DATA hed, HDC hDC, DWORD ScrollPos, DWORD First, DWORD Last, RECT *rc) 178 { 179 DWORD dx, dy, linestart; 180 INT i, isave, i0, i1, x; 181 PBYTE buf, current, end, line; 182 size_t bufsize; 183 WCHAR hex[3], addr[17]; 184 RECT rct, rct2; 185 186 FillRect(hDC, rc, (HBRUSH)(COLOR_WINDOW + 1)); 187 SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); 188 189 if (hed->SelStart < hed->SelEnd) 190 { 191 i0 = hed->SelStart; 192 i1 = hed->SelEnd; 193 } 194 else 195 { 196 i0 = hed->SelEnd; 197 i1 = hed->SelStart; 198 } 199 200 if(hed->hBuffer) 201 { 202 bufsize = LocalSize(hed->hBuffer); 203 buf = LocalLock(hed->hBuffer); 204 } 205 else 206 { 207 buf = NULL; 208 bufsize = 0; 209 210 if(ScrollPos + First == 0) 211 { 212 /* draw address */ 213 wsprintf(addr, L"%04X", 0); 214 TextOutW(hDC, hed->LeftMargin, First * hed->LineHeight, addr, 4); 215 } 216 } 217 218 if(buf) 219 { 220 end = buf + bufsize; 221 dy = First * hed->LineHeight; 222 linestart = (ScrollPos + First) * hed->ColumnsPerLine; 223 i = linestart; 224 current = buf + linestart; 225 Last = min(hed->nLines - ScrollPos, Last); 226 227 SetBkMode(hDC, TRANSPARENT); 228 while(First <= Last && current < end) 229 { 230 DWORD dh; 231 232 dx = hed->LeftMargin; 233 234 /* draw address */ 235 wsprintf(addr, L"%04lX", linestart); 236 TextOutW(hDC, dx, dy, addr, 4); 237 238 dx += ((4 + hed->AddressSpacing) * hed->CharWidth); 239 dh = (3 * hed->CharWidth); 240 241 rct.left = dx; 242 rct.top = dy; 243 rct.right = rct.left + dh; 244 rct.bottom = dy + hed->LineHeight; 245 246 /* draw hex map */ 247 dx += (hed->CharWidth / 2); 248 line = current; 249 isave = i; 250 for(x = 0; x < hed->ColumnsPerLine && current < end; x++) 251 { 252 rct.left += dh; 253 rct.right += dh; 254 255 wsprintf(hex, L"%02X", *(current++)); 256 if (i0 <= i && i < i1) 257 { 258 rct2.left = dx; 259 rct2.top = dy; 260 rct2.right = dx + hed->CharWidth * 2 + 1; 261 rct2.bottom = dy + hed->LineHeight; 262 InflateRect(&rct2, hed->CharWidth / 2, 0); 263 FillRect(hDC, &rct2, (HBRUSH)(COLOR_HIGHLIGHT + 1)); 264 SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); 265 ExtTextOutW(hDC, dx, dy, 0, &rct, hex, 2, NULL); 266 SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); 267 } 268 else 269 ExtTextOutW(hDC, dx, dy, ETO_OPAQUE, &rct, hex, 2, NULL); 270 dx += dh; 271 i++; 272 } 273 274 /* draw ascii map */ 275 dx = ((4 + hed->AddressSpacing + hed->SplitSpacing + (hed->ColumnsPerLine * 3)) * hed->CharWidth); 276 current = line; 277 i = isave; 278 for(x = 0; x < hed->ColumnsPerLine && current < end; x++) 279 { 280 wsprintf(hex, L"%C", *(current++)); 281 hex[0] = ((hex[0] & L'\x007f') >= L' ' ? hex[0] : L'.'); 282 if (i0 <= i && i < i1) 283 { 284 rct2.left = dx; 285 rct2.top = dy; 286 rct2.right = dx + hed->CharWidth; 287 rct2.bottom = dy + hed->LineHeight; 288 FillRect(hDC, &rct2, (HBRUSH)(COLOR_HIGHLIGHT + 1)); 289 SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); 290 TextOutW(hDC, dx, dy, hex, 1); 291 SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); 292 } 293 else 294 TextOutW(hDC, dx, dy, hex, 1); 295 dx += hed->CharWidth; 296 i++; 297 } 298 299 dy += hed->LineHeight; 300 linestart += hed->ColumnsPerLine; 301 First++; 302 } 303 } 304 305 LocalUnlock(hed->hBuffer); 306 } 307 308 static DWORD 309 HEXEDIT_HitRegionTest(PHEXEDIT_DATA hed, POINTS pt) 310 { 311 int d; 312 313 if(pt.x <= hed->LeftMargin) 314 { 315 return HEHT_LEFTMARGIN; 316 } 317 318 pt.x -= hed->LeftMargin; 319 d = (4 * hed->CharWidth); 320 if(pt.x <= d) 321 { 322 return HEHT_ADDRESS; 323 } 324 325 pt.x -= d; 326 d = (hed->AddressSpacing * hed->CharWidth); 327 if(pt.x <= d) 328 { 329 return HEHT_ADDRESSSPACING; 330 } 331 332 pt.x -= d; 333 d = ((3 * hed->ColumnsPerLine + 1) * hed->CharWidth); 334 if(pt.x <= d) 335 { 336 return HEHT_HEXDUMP; 337 } 338 339 pt.x -= d; 340 d = ((hed->SplitSpacing - 1) * hed->CharWidth); 341 if(pt.x <= d) 342 { 343 return HEHT_HEXDUMPSPACING; 344 } 345 346 pt.x -= d; 347 d = (hed->ColumnsPerLine * hed->CharWidth); 348 if(pt.x <= d) 349 { 350 return HEHT_ASCIIDUMP; 351 } 352 353 return HEHT_RIGHTMARGIN; 354 } 355 356 static DWORD 357 HEXEDIT_IndexFromPoint(PHEXEDIT_DATA hed, POINTS pt, DWORD Hit, POINT *EditPos, BOOL *EditField) 358 { 359 SCROLLINFO si; 360 DWORD Index, bufsize; 361 362 si.cbSize = sizeof(SCROLLINFO); 363 si.fMask = SIF_POS; 364 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 365 366 EditPos->x = 0; 367 368 if(hed->LineHeight > 0) 369 { 370 EditPos->y = min(si.nPos + (pt.y / hed->LineHeight), hed->nLines - 1); 371 } 372 else 373 { 374 EditPos->y = si.nPos; 375 } 376 377 switch(Hit) 378 { 379 case HEHT_LEFTMARGIN: 380 case HEHT_ADDRESS: 381 case HEHT_ADDRESSSPACING: 382 case HEHT_HEXDUMP: 383 pt.x -= (SHORT) hed->LeftMargin + ((4 + hed->AddressSpacing) * hed->CharWidth); 384 *EditField = TRUE; 385 break; 386 387 default: 388 pt.x -= hed->LeftMargin + ((4 + hed->AddressSpacing + hed->SplitSpacing + (3 * hed->ColumnsPerLine)) * hed->CharWidth); 389 *EditField = FALSE; 390 break; 391 } 392 393 if(pt.x > 0) 394 { 395 INT BlockWidth = (*EditField ? hed->CharWidth * 3 : hed->CharWidth); 396 EditPos->x = min(hed->ColumnsPerLine, (pt.x + BlockWidth / 2) / BlockWidth); 397 } 398 399 bufsize = (hed->hBuffer ? (DWORD) LocalSize(hed->hBuffer) : 0); 400 Index = (EditPos->y * hed->ColumnsPerLine) + EditPos->x; 401 if(Index > bufsize) 402 { 403 INT tmp = bufsize % hed->ColumnsPerLine; 404 Index = bufsize; 405 EditPos->x = (tmp == 0 ? hed->ColumnsPerLine : tmp); 406 } 407 return Index; 408 } 409 410 static VOID 411 HEXEDIT_Copy(PHEXEDIT_DATA hed) 412 { 413 PBYTE pb, buf; 414 UINT cb; 415 INT i0, i1; 416 HGLOBAL hGlobal; 417 418 if (hed->SelStart < hed->SelEnd) 419 { 420 i0 = hed->SelStart; 421 i1 = hed->SelEnd; 422 } 423 else 424 { 425 i0 = hed->SelEnd; 426 i1 = hed->SelStart; 427 } 428 429 cb = i1 - i0; 430 if (cb == 0) 431 return; 432 433 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, cb + sizeof(DWORD)); 434 if (hGlobal == NULL) 435 return; 436 437 pb = GlobalLock(hGlobal); 438 if (pb) 439 { 440 *(PDWORD)pb = cb; 441 pb += sizeof(DWORD); 442 buf = (PBYTE) LocalLock(hed->hBuffer); 443 if (buf) 444 { 445 CopyMemory(pb, buf + i0, cb); 446 LocalUnlock(hed->hBuffer); 447 } 448 GlobalUnlock(hGlobal); 449 450 if (OpenClipboard(hed->hWndSelf)) 451 { 452 EmptyClipboard(); 453 SetClipboardData(ClipboardFormatID, hGlobal); 454 CloseClipboard(); 455 } 456 } 457 else 458 GlobalFree(hGlobal); 459 } 460 461 static VOID 462 HEXEDIT_Delete(PHEXEDIT_DATA hed) 463 { 464 PBYTE buf; 465 INT i0, i1; 466 UINT bufsize; 467 468 if (hed->SelStart < hed->SelEnd) 469 { 470 i0 = hed->SelStart; 471 i1 = hed->SelEnd; 472 } 473 else 474 { 475 i0 = hed->SelEnd; 476 i1 = hed->SelStart; 477 } 478 479 if (i0 != i1) 480 { 481 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0); 482 buf = (PBYTE) LocalLock(hed->hBuffer); 483 if (buf) 484 { 485 MoveMemory(buf + i0, buf + i1, bufsize - i1); 486 LocalUnlock(hed->hBuffer); 487 } 488 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - (i1 - i0)); 489 hed->InMid = FALSE; 490 hed->Index = hed->SelStart = hed->SelEnd = i0; 491 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 492 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 493 InvalidateRect(hed->hWndSelf, NULL, TRUE); 494 HEXEDIT_MoveCaret(hed, TRUE); 495 } 496 } 497 498 static VOID 499 HEXEDIT_Paste(PHEXEDIT_DATA hed) 500 { 501 HGLOBAL hGlobal; 502 UINT bufsize; 503 PBYTE pb, buf; 504 DWORD cb; 505 506 HEXEDIT_Delete(hed); 507 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0); 508 509 if (OpenClipboard(hed->hWndSelf)) 510 { 511 hGlobal = GetClipboardData(ClipboardFormatID); 512 if (hGlobal != NULL) 513 { 514 pb = (PBYTE) GlobalLock(hGlobal); 515 cb = *(PDWORD) pb; 516 pb += sizeof(DWORD); 517 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize + cb); 518 buf = (PBYTE) LocalLock(hed->hBuffer); 519 if (buf) 520 { 521 MoveMemory(buf + hed->Index + cb, buf + hed->Index, 522 bufsize - hed->Index); 523 CopyMemory(buf + hed->Index, pb, cb); 524 LocalUnlock(hed->hBuffer); 525 } 526 GlobalUnlock(hGlobal); 527 } 528 CloseClipboard(); 529 } 530 InvalidateRect(hed->hWndSelf, NULL, TRUE); 531 HEXEDIT_MoveCaret(hed, TRUE); 532 } 533 534 static VOID 535 HEXEDIT_Cut(PHEXEDIT_DATA hed) 536 { 537 HEXEDIT_Copy(hed); 538 HEXEDIT_Delete(hed); 539 } 540 541 static VOID 542 HEXEDIT_SelectAll(PHEXEDIT_DATA hed) 543 { 544 INT bufsize; 545 546 bufsize = (hed->hBuffer ? (INT) LocalSize(hed->hBuffer) : 0); 547 hed->Index = hed->SelStart = 0; 548 hed->SelEnd = bufsize; 549 InvalidateRect(hed->hWndSelf, NULL, TRUE); 550 HEXEDIT_MoveCaret(hed, TRUE); 551 } 552 553 /*** Control specific messages ************************************************/ 554 555 static LRESULT 556 HEXEDIT_HEM_LOADBUFFER(PHEXEDIT_DATA hed, PVOID Buffer, DWORD Size) 557 { 558 if(Buffer != NULL && Size > 0) 559 { 560 LPVOID buf; 561 562 if(hed->MaxBuffer > 0 && Size > hed->MaxBuffer) 563 { 564 Size = hed->MaxBuffer; 565 } 566 567 if(hed->hBuffer) 568 { 569 if(Size > 0) 570 { 571 if(LocalSize(hed->hBuffer) != Size) 572 { 573 hed->hBuffer = LocalReAlloc(hed->hBuffer, Size, LMEM_MOVEABLE | LMEM_ZEROINIT); 574 } 575 } 576 else 577 { 578 hed->hBuffer = LocalFree(hed->hBuffer); 579 hed->Index = 0; 580 HEXEDIT_Update(hed); 581 582 return 0; 583 } 584 } 585 else if(Size > 0) 586 { 587 hed->hBuffer = LocalAlloc(LHND, Size); 588 } 589 590 if(Size > 0) 591 { 592 buf = LocalLock(hed->hBuffer); 593 if(buf) 594 { 595 memcpy(buf, Buffer, Size); 596 } 597 else 598 Size = 0; 599 LocalUnlock(hed->hBuffer); 600 } 601 602 hed->Index = 0; 603 HEXEDIT_Update(hed); 604 return Size; 605 } 606 else if(hed->hBuffer) 607 { 608 hed->Index = 0; 609 hed->hBuffer = LocalFree(hed->hBuffer); 610 HEXEDIT_Update(hed); 611 } 612 613 return 0; 614 } 615 616 static LRESULT 617 HEXEDIT_HEM_COPYBUFFER(PHEXEDIT_DATA hed, PVOID Buffer, DWORD Size) 618 { 619 size_t nCpy; 620 621 if(!hed->hBuffer) 622 { 623 return 0; 624 } 625 626 if(Buffer != NULL && Size > 0) 627 { 628 nCpy = min(Size, LocalSize(hed->hBuffer)); 629 if(nCpy > 0) 630 { 631 PVOID buf; 632 633 buf = LocalLock(hed->hBuffer); 634 if(buf) 635 { 636 memcpy(Buffer, buf, nCpy); 637 } 638 else 639 nCpy = 0; 640 LocalUnlock(hed->hBuffer); 641 } 642 return nCpy; 643 } 644 645 return (LRESULT)LocalSize(hed->hBuffer); 646 } 647 648 static LRESULT 649 HEXEDIT_HEM_SETMAXBUFFERSIZE(PHEXEDIT_DATA hed, DWORD nMaxSize) 650 { 651 hed->MaxBuffer = nMaxSize; 652 if (hed->MaxBuffer == 0) 653 { 654 hed->hBuffer = LocalFree(hed->hBuffer); 655 return 0; 656 } 657 if (hed->hBuffer) 658 hed->hBuffer = LocalReAlloc(hed->hBuffer, hed->MaxBuffer, LMEM_MOVEABLE); 659 else 660 hed->hBuffer = LocalAlloc(LMEM_MOVEABLE, hed->MaxBuffer); 661 HEXEDIT_Update(hed); 662 return 0; 663 } 664 665 /*** Message Proc *************************************************************/ 666 667 static LRESULT 668 HEXEDIT_WM_NCCREATE(HWND hWnd, CREATESTRUCT *cs) 669 { 670 PHEXEDIT_DATA hed; 671 672 if(!(hed = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HEXEDIT_DATA)))) 673 { 674 return FALSE; 675 } 676 677 hed->hWndSelf = hWnd; 678 hed->hWndParent = cs->hwndParent; 679 hed->style = cs->style; 680 681 hed->ColumnsPerLine = 8; 682 hed->LeftMargin = 2; 683 hed->AddressSpacing = 2; 684 hed->SplitSpacing = 2; 685 hed->EditingField = TRUE; /* in hexdump field */ 686 687 SetWindowLongPtr(hWnd, 0, (DWORD_PTR)hed); 688 HEXEDIT_Update(hed); 689 690 return TRUE; 691 } 692 693 static LRESULT 694 HEXEDIT_WM_NCDESTROY(PHEXEDIT_DATA hed) 695 { 696 if(hed->hBuffer) 697 { 698 //while(LocalUnlock(hed->hBuffer)); 699 LocalFree(hed->hBuffer); 700 } 701 702 if(hed->hFont) 703 { 704 DeleteObject(hed->hFont); 705 } 706 707 SetWindowLongPtr(hed->hWndSelf, 0, (DWORD_PTR)0); 708 HeapFree(GetProcessHeap(), 0, hed); 709 710 return 0; 711 } 712 713 static LRESULT 714 HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed) 715 { 716 UNREFERENCED_PARAMETER(hed); 717 return 1; 718 } 719 720 static LRESULT 721 HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed) 722 { 723 CreateCaret(hed->hWndSelf, 0, 1, hed->LineHeight); 724 HEXEDIT_MoveCaret(hed, FALSE); 725 ShowCaret(hed->hWndSelf); 726 return 0; 727 } 728 729 static LRESULT 730 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed) 731 { 732 UNREFERENCED_PARAMETER(hed); 733 DestroyCaret(); 734 return 0; 735 } 736 737 static LRESULT 738 HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed, WORD ThumbPosition, WORD SbCmd) 739 { 740 int ScrollY; 741 SCROLLINFO si; 742 743 UNREFERENCED_PARAMETER(ThumbPosition); 744 745 ZeroMemory(&si, sizeof(SCROLLINFO)); 746 si.cbSize = sizeof(SCROLLINFO); 747 si.fMask = SIF_ALL; 748 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 749 750 ScrollY = si.nPos; 751 switch(SbCmd) 752 { 753 case SB_TOP: 754 si.nPos = si.nMin; 755 break; 756 757 case SB_BOTTOM: 758 si.nPos = si.nMax; 759 break; 760 761 case SB_LINEUP: 762 si.nPos--; 763 break; 764 765 case SB_LINEDOWN: 766 si.nPos++; 767 break; 768 769 case SB_PAGEUP: 770 si.nPos -= si.nPage; 771 break; 772 773 case SB_PAGEDOWN: 774 si.nPos += si.nPage; 775 break; 776 777 case SB_THUMBTRACK: 778 si.nPos = si.nTrackPos; 779 break; 780 } 781 782 si.fMask = SIF_POS; 783 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE); 784 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 785 786 if(si.nPos != ScrollY) 787 { 788 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL); 789 UpdateWindow(hed->hWndSelf); 790 } 791 792 return 0; 793 } 794 795 static LRESULT 796 HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed, HFONT hFont, BOOL bRedraw) 797 { 798 HDC hDC; 799 TEXTMETRIC tm; 800 HFONT hOldFont = 0; 801 802 if(hFont == 0) 803 { 804 hFont = HEXEDIT_GetFixedFont(); 805 } 806 807 hed->hFont = hFont; 808 hDC = GetDC(hed->hWndSelf); 809 if(hFont) 810 { 811 hOldFont = SelectObject(hDC, hFont); 812 } 813 GetTextMetrics(hDC, &tm); 814 hed->LineHeight = tm.tmHeight; 815 hed->CharWidth = tm.tmAveCharWidth; 816 if(hOldFont) 817 { 818 SelectObject(hDC, hOldFont); 819 } 820 ReleaseDC(hed->hWndSelf, hDC); 821 822 if(bRedraw) 823 { 824 InvalidateRect(hed->hWndSelf, NULL, TRUE); 825 } 826 827 return 0; 828 } 829 830 static LRESULT 831 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed) 832 { 833 return (LRESULT)hed->hFont; 834 } 835 836 static LRESULT 837 HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed) 838 { 839 PAINTSTRUCT ps; 840 SCROLLINFO si; 841 RECT rc; 842 HBITMAP hbmp, hbmpold; 843 INT nLines, nFirst; 844 HFONT hOldFont; 845 HDC hTempDC; 846 DWORD height; 847 848 if(GetUpdateRect(hed->hWndSelf, &rc, FALSE) && (hed->LineHeight > 0)) 849 { 850 ZeroMemory(&si, sizeof(SCROLLINFO)); 851 si.cbSize = sizeof(SCROLLINFO); 852 si.fMask = SIF_POS; 853 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 854 855 height = (rc.bottom - rc.top); 856 nLines = height / hed->LineHeight; 857 if((height % hed->LineHeight) > 0) 858 { 859 nLines++; 860 } 861 if(nLines > hed->nLines - si.nPos) 862 { 863 nLines = hed->nLines - si.nPos; 864 } 865 nFirst = rc.top / hed->LineHeight; 866 867 BeginPaint(hed->hWndSelf, &ps); 868 if(!(hTempDC = CreateCompatibleDC(ps.hdc))) 869 { 870 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1)); 871 goto epaint; 872 } 873 if(!(hbmp = CreateCompatibleBitmap(ps.hdc, ps.rcPaint.right, ps.rcPaint.bottom))) 874 { 875 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1)); 876 DeleteDC(hTempDC); 877 goto epaint; 878 } 879 hbmpold = SelectObject(hTempDC, hbmp); 880 hOldFont = SelectObject(hTempDC, hed->hFont); 881 HEXEDIT_PaintLines(hed, hTempDC, si.nPos, nFirst, nFirst + nLines, &ps.rcPaint); 882 BitBlt(ps.hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hTempDC, rc.left, rc.top, SRCCOPY); 883 SelectObject(hTempDC, hOldFont); 884 SelectObject(hTempDC, hbmpold); 885 886 DeleteObject(hbmp); 887 DeleteDC(hTempDC); 888 889 epaint: 890 EndPaint(hed->hWndSelf, &ps); 891 } 892 893 return 0; 894 } 895 896 static LRESULT 897 HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed, int cyMoveLines, WORD ButtonsDown, LPPOINTS MousePos) 898 { 899 SCROLLINFO si; 900 int ScrollY; 901 902 UNREFERENCED_PARAMETER(ButtonsDown); 903 UNREFERENCED_PARAMETER(MousePos); 904 905 SetFocus(hed->hWndSelf); 906 907 si.cbSize = sizeof(SCROLLINFO); 908 si.fMask = SIF_ALL; 909 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 910 911 ScrollY = si.nPos; 912 913 si.fMask = SIF_POS; 914 si.nPos += cyMoveLines; 915 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE); 916 917 GetScrollInfo(hed->hWndSelf, SB_VERT, &si); 918 if(si.nPos != ScrollY) 919 { 920 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL); 921 UpdateWindow(hed->hWndSelf); 922 } 923 924 return 0; 925 } 926 927 static LRESULT 928 HEXEDIT_WM_GETDLGCODE(LPMSG Msg) 929 { 930 UNREFERENCED_PARAMETER(Msg); 931 return DLGC_WANTARROWS | DLGC_WANTCHARS; 932 } 933 934 static LRESULT 935 HEXEDIT_WM_LBUTTONDOWN(PHEXEDIT_DATA hed, INT Buttons, POINTS Pt) 936 { 937 BOOL NewField; 938 POINT EditPos; 939 DWORD Hit; 940 941 UNREFERENCED_PARAMETER(Buttons); 942 SetFocus(hed->hWndSelf); 943 944 if (GetAsyncKeyState(VK_SHIFT) < 0) 945 { 946 if (hed->EditingField) 947 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, HEHT_HEXDUMP, &EditPos, &NewField); 948 else 949 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, HEHT_ASCIIDUMP, &EditPos, &NewField); 950 hed->SelEnd = hed->Index; 951 } 952 else 953 { 954 Hit = HEXEDIT_HitRegionTest(hed, Pt); 955 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, Hit, &EditPos, &NewField); 956 hed->SelStart = hed->SelEnd = hed->Index; 957 hed->EditingField = NewField; 958 SetCapture(hed->hWndSelf); 959 } 960 hed->CaretCol = EditPos.x; 961 hed->CaretLine = EditPos.y; 962 hed->InMid = FALSE; 963 InvalidateRect(hed->hWndSelf, NULL, FALSE); 964 HEXEDIT_MoveCaret(hed, TRUE); 965 966 return 0; 967 } 968 969 static LRESULT 970 HEXEDIT_WM_LBUTTONUP(PHEXEDIT_DATA hed, INT Buttons, POINTS Pt) 971 { 972 BOOL NewField; 973 POINT EditPos; 974 if (GetCapture() == hed->hWndSelf) 975 { 976 if (hed->EditingField) 977 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, HEHT_HEXDUMP, &EditPos, &NewField); 978 else 979 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, HEHT_ASCIIDUMP, &EditPos, &NewField); 980 hed->CaretCol = EditPos.x; 981 hed->CaretLine = EditPos.y; 982 hed->SelEnd = hed->Index; 983 ReleaseCapture(); 984 InvalidateRect(hed->hWndSelf, NULL, FALSE); 985 HEXEDIT_MoveCaret(hed, TRUE); 986 } 987 return 0; 988 } 989 990 static LRESULT 991 HEXEDIT_WM_MOUSEMOVE(PHEXEDIT_DATA hed, INT Buttons, POINTS Pt) 992 { 993 BOOL NewField; 994 POINT EditPos; 995 if (GetCapture() == hed->hWndSelf) 996 { 997 if (hed->EditingField) 998 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, HEHT_HEXDUMP, &EditPos, &NewField); 999 else 1000 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, HEHT_ASCIIDUMP, &EditPos, &NewField); 1001 hed->CaretCol = EditPos.x; 1002 hed->CaretLine = EditPos.y; 1003 hed->SelEnd = hed->Index; 1004 InvalidateRect(hed->hWndSelf, NULL, FALSE); 1005 HEXEDIT_MoveCaret(hed, TRUE); 1006 } 1007 return 0; 1008 } 1009 1010 static BOOL 1011 HEXEDIT_WM_KEYDOWN(PHEXEDIT_DATA hed, INT VkCode) 1012 { 1013 size_t bufsize; 1014 PBYTE buf; 1015 INT i0, i1; 1016 1017 if(GetKeyState(VK_MENU) & 0x8000) 1018 { 1019 return FALSE; 1020 } 1021 1022 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0); 1023 1024 if (hed->SelStart < hed->SelEnd) 1025 { 1026 i0 = hed->SelStart; 1027 i1 = hed->SelEnd; 1028 } 1029 else 1030 { 1031 i0 = hed->SelEnd; 1032 i1 = hed->SelStart; 1033 } 1034 1035 switch(VkCode) 1036 { 1037 case 'X': 1038 if (GetAsyncKeyState(VK_SHIFT) >= 0 && 1039 GetAsyncKeyState(VK_CONTROL) < 0 && hed->SelStart != hed->SelEnd) 1040 HEXEDIT_Cut(hed); 1041 else 1042 return TRUE; 1043 break; 1044 1045 case 'C': 1046 if (GetAsyncKeyState(VK_SHIFT) >= 0 && 1047 GetAsyncKeyState(VK_CONTROL) < 0 && hed->SelStart != hed->SelEnd) 1048 HEXEDIT_Copy(hed); 1049 else 1050 return TRUE; 1051 break; 1052 1053 case 'V': 1054 if (GetAsyncKeyState(VK_SHIFT) >= 0 && GetAsyncKeyState(VK_CONTROL) < 0) 1055 HEXEDIT_Paste(hed); 1056 else 1057 return TRUE; 1058 break; 1059 1060 case 'A': 1061 if (GetAsyncKeyState(VK_SHIFT) >= 0 && GetAsyncKeyState(VK_CONTROL) < 0) 1062 HEXEDIT_SelectAll(hed); 1063 else 1064 return TRUE; 1065 break; 1066 1067 case VK_INSERT: 1068 if (hed->SelStart != hed->SelEnd) 1069 { 1070 if (GetAsyncKeyState(VK_SHIFT) >= 0 && GetAsyncKeyState(VK_CONTROL) < 0) 1071 HEXEDIT_Copy(hed); 1072 } 1073 if (GetAsyncKeyState(VK_SHIFT) < 0 && GetAsyncKeyState(VK_CONTROL) >= 0) 1074 HEXEDIT_Paste(hed); 1075 break; 1076 1077 case VK_DELETE: 1078 if (GetAsyncKeyState(VK_SHIFT) < 0 && GetAsyncKeyState(VK_CONTROL) >= 0 && 1079 hed->SelStart != hed->SelEnd) 1080 HEXEDIT_Copy(hed); 1081 if (i0 != i1) 1082 { 1083 buf = (PBYTE) LocalLock(hed->hBuffer); 1084 if (buf) 1085 { 1086 MoveMemory(buf + i0, buf + i1, bufsize - i1); 1087 LocalUnlock(hed->hBuffer); 1088 } 1089 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - (i1 - i0)); 1090 hed->InMid = FALSE; 1091 hed->Index = hed->SelStart = hed->SelEnd = i0; 1092 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1093 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1094 } 1095 else 1096 { 1097 if (hed->InMid && hed->EditingField) 1098 { 1099 buf = (PBYTE) LocalLock(hed->hBuffer); 1100 if (buf) 1101 { 1102 MoveMemory(buf + hed->Index, buf + hed->Index + 1, 1103 bufsize - hed->Index - 1); 1104 LocalUnlock(hed->hBuffer); 1105 } 1106 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1); 1107 hed->InMid = FALSE; 1108 } 1109 else if (hed->Index < bufsize) 1110 { 1111 buf = (PBYTE) LocalLock(hed->hBuffer); 1112 if (buf) 1113 { 1114 MoveMemory(buf + hed->Index, buf + hed->Index + 1, 1115 bufsize - hed->Index - 1); 1116 LocalUnlock(hed->hBuffer); 1117 } 1118 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1); 1119 } 1120 } 1121 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1122 HEXEDIT_MoveCaret(hed, TRUE); 1123 break; 1124 1125 case VK_BACK: 1126 if (i0 != i1) 1127 { 1128 buf = (PBYTE) LocalLock(hed->hBuffer); 1129 if (buf) 1130 { 1131 MoveMemory(buf + i0, buf + i1, bufsize - i1); 1132 LocalUnlock(hed->hBuffer); 1133 } 1134 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - (i1 - i0)); 1135 hed->InMid = FALSE; 1136 hed->Index = hed->SelStart = hed->SelEnd = i0; 1137 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1138 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1139 } 1140 else 1141 { 1142 if (hed->InMid && hed->EditingField) 1143 { 1144 buf = (PBYTE) LocalLock(hed->hBuffer); 1145 if (buf) 1146 { 1147 MoveMemory(buf + hed->Index, buf + hed->Index + 1, 1148 bufsize - hed->Index - 1); 1149 LocalUnlock(hed->hBuffer); 1150 } 1151 } 1152 else if (hed->Index > 0) 1153 { 1154 buf = (PBYTE) LocalLock(hed->hBuffer); 1155 if (buf) 1156 { 1157 MoveMemory(buf + hed->Index - 1, buf + hed->Index, 1158 bufsize - hed->Index); 1159 LocalUnlock(hed->hBuffer); 1160 } 1161 hed->Index--; 1162 hed->SelStart = hed->SelEnd = hed->Index; 1163 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1164 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1165 } 1166 else 1167 return TRUE; 1168 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1); 1169 hed->InMid = FALSE; 1170 } 1171 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1172 HEXEDIT_MoveCaret(hed, TRUE); 1173 break; 1174 1175 case VK_LEFT: 1176 if (hed->Index > 0) 1177 { 1178 hed->Index--; 1179 if (GetAsyncKeyState(VK_SHIFT) < 0) 1180 hed->SelEnd = hed->Index; 1181 else 1182 hed->SelStart = hed->SelEnd = hed->Index; 1183 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1184 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1185 hed->InMid = FALSE; 1186 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1187 HEXEDIT_MoveCaret(hed, TRUE); 1188 } 1189 break; 1190 1191 case VK_RIGHT: 1192 if (hed->Index < (INT)bufsize) 1193 { 1194 hed->Index++; 1195 if (GetAsyncKeyState(VK_SHIFT) < 0) 1196 hed->SelEnd = hed->Index; 1197 else 1198 hed->SelStart = hed->SelEnd = hed->Index; 1199 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1200 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1201 hed->InMid = FALSE; 1202 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1203 HEXEDIT_MoveCaret(hed, TRUE); 1204 } 1205 break; 1206 1207 case VK_UP: 1208 if (hed->Index >= hed->ColumnsPerLine) 1209 { 1210 hed->Index -= hed->ColumnsPerLine; 1211 if (GetAsyncKeyState(VK_SHIFT) < 0) 1212 hed->SelEnd = hed->Index; 1213 else 1214 hed->SelStart = hed->SelEnd = hed->Index; 1215 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1216 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1217 hed->InMid = FALSE; 1218 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1219 HEXEDIT_MoveCaret(hed, TRUE); 1220 } 1221 break; 1222 1223 case VK_DOWN: 1224 if (hed->Index + hed->ColumnsPerLine <= (INT) bufsize) 1225 hed->Index += hed->ColumnsPerLine; 1226 else 1227 hed->Index = bufsize; 1228 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1229 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1230 if (GetAsyncKeyState(VK_SHIFT) < 0) 1231 hed->SelEnd = hed->Index; 1232 else 1233 hed->SelStart = hed->SelEnd = hed->Index; 1234 hed->InMid = FALSE; 1235 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1236 HEXEDIT_MoveCaret(hed, TRUE); 1237 break; 1238 1239 default: 1240 return TRUE; 1241 } 1242 1243 return FALSE; 1244 } 1245 1246 static BOOL 1247 HEXEDIT_WM_CHAR(PHEXEDIT_DATA hed, WCHAR wch) 1248 { 1249 size_t bufsize; 1250 CHAR ch = (CHAR)wch; // keep the lowest octet. 1251 PBYTE buf; 1252 INT i0, i1; 1253 1254 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0); 1255 if (hed->SelStart < hed->SelEnd) 1256 { 1257 i0 = hed->SelStart; 1258 i1 = hed->SelEnd; 1259 } 1260 else 1261 { 1262 i0 = hed->SelEnd; 1263 i1 = hed->SelStart; 1264 } 1265 if (!hed->EditingField) 1266 { 1267 if (0x20 <= ch && ch <= 0xFF) 1268 { 1269 if (hed->SelStart != hed->SelEnd) 1270 { 1271 buf = (PBYTE) LocalLock(hed->hBuffer); 1272 if (buf) 1273 { 1274 MoveMemory(buf + i0, buf + i1, bufsize - i1); 1275 LocalUnlock(hed->hBuffer); 1276 } 1277 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - (i1 - i0)); 1278 hed->InMid = FALSE; 1279 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0); 1280 hed->Index = hed->SelStart = hed->SelEnd = i0; 1281 } 1282 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize + 1); 1283 buf = (PBYTE) LocalLock(hed->hBuffer); 1284 if (buf) 1285 { 1286 MoveMemory(buf + hed->Index + 1, buf + hed->Index, 1287 bufsize - hed->Index); 1288 buf[hed->Index] = ch; 1289 LocalUnlock(hed->hBuffer); 1290 } 1291 hed->Index++; 1292 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1293 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1294 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1295 HEXEDIT_MoveCaret(hed, TRUE); 1296 return FALSE; 1297 } 1298 } 1299 else 1300 { 1301 if (('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') || 1302 ('a' <= ch && ch <= 'f')) 1303 { 1304 if (hed->SelStart != hed->SelEnd) 1305 { 1306 buf = (PBYTE) LocalLock(hed->hBuffer); 1307 if (buf) 1308 { 1309 MoveMemory(buf + i0, buf + i1, bufsize - i1); 1310 LocalUnlock(hed->hBuffer); 1311 } 1312 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - (i1 - i0)); 1313 hed->InMid = FALSE; 1314 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0); 1315 hed->Index = hed->SelStart = hed->SelEnd = i0; 1316 } 1317 if (hed->InMid) 1318 { 1319 buf = (PBYTE) LocalLock(hed->hBuffer); 1320 if (buf) 1321 { 1322 if ('0' <= ch && ch <= '9') 1323 buf[hed->Index] |= ch - '0'; 1324 else if ('A' <= ch && ch <= 'F') 1325 buf[hed->Index] |= ch + 10 - 'A'; 1326 else if ('a' <= ch && ch <= 'f') 1327 buf[hed->Index] |= ch + 10 - 'a'; 1328 LocalUnlock(hed->hBuffer); 1329 } 1330 hed->InMid = FALSE; 1331 hed->Index++; 1332 } 1333 else 1334 { 1335 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize + 1); 1336 buf = (PBYTE) LocalLock(hed->hBuffer); 1337 if (buf) 1338 { 1339 MoveMemory(buf + hed->Index + 1, buf + hed->Index, 1340 bufsize - hed->Index); 1341 if ('0' <= ch && ch <= '9') 1342 buf[hed->Index] = (ch - '0') << 4; 1343 else if ('A' <= ch && ch <= 'F') 1344 buf[hed->Index] = (ch + 10 - 'A') << 4; 1345 else if ('a' <= ch && ch <= 'f') 1346 buf[hed->Index] = (ch + 10 - 'a') << 4; 1347 LocalUnlock(hed->hBuffer); 1348 } 1349 hed->InMid = TRUE; 1350 } 1351 hed->CaretCol = hed->Index % hed->ColumnsPerLine; 1352 hed->CaretLine = hed->Index / hed->ColumnsPerLine; 1353 InvalidateRect(hed->hWndSelf, NULL, TRUE); 1354 HEXEDIT_MoveCaret(hed, TRUE); 1355 return FALSE; 1356 } 1357 } 1358 return TRUE; 1359 } 1360 1361 static LRESULT 1362 HEXEDIT_WM_SIZE(PHEXEDIT_DATA hed, DWORD sType, WORD NewWidth, WORD NewHeight) 1363 { 1364 UNREFERENCED_PARAMETER(sType); 1365 UNREFERENCED_PARAMETER(NewHeight); 1366 UNREFERENCED_PARAMETER(NewWidth); 1367 HEXEDIT_Update(hed); 1368 return 0; 1369 } 1370 1371 static VOID 1372 HEXEDIT_WM_CONTEXTMENU(PHEXEDIT_DATA hed, INT x, INT y) 1373 { 1374 HMENU hMenu; 1375 RECT rc; 1376 1377 if (x == -1 && y == -1) 1378 { 1379 GetWindowRect(hed->hWndSelf, &rc); 1380 x = rc.left; 1381 y = rc.top; 1382 } 1383 1384 hMenu = GetSubMenu(hPopupMenus, PM_HEXEDIT); 1385 if (hed->SelStart == hed->SelEnd) 1386 { 1387 EnableMenuItem(hMenu, ID_HEXEDIT_CUT, MF_GRAYED); 1388 EnableMenuItem(hMenu, ID_HEXEDIT_COPY, MF_GRAYED); 1389 EnableMenuItem(hMenu, ID_HEXEDIT_PASTE, MF_GRAYED); 1390 EnableMenuItem(hMenu, ID_HEXEDIT_DELETE, MF_GRAYED); 1391 } 1392 else 1393 { 1394 EnableMenuItem(hMenu, ID_HEXEDIT_CUT, MF_ENABLED); 1395 EnableMenuItem(hMenu, ID_HEXEDIT_COPY, MF_ENABLED); 1396 EnableMenuItem(hMenu, ID_HEXEDIT_PASTE, MF_ENABLED); 1397 EnableMenuItem(hMenu, ID_HEXEDIT_DELETE, MF_ENABLED); 1398 } 1399 1400 SetForegroundWindow(hed->hWndSelf); 1401 TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, x, y, 0, hed->hWndSelf, NULL); 1402 PostMessageW(hed->hWndSelf, WM_NULL, 0, 0); 1403 } 1404 1405 LRESULT CALLBACK 1406 HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 1407 { 1408 PHEXEDIT_DATA hed; 1409 POINTS p; 1410 1411 hed = (PHEXEDIT_DATA)GetWindowLongPtr(hWnd, (DWORD_PTR)0); 1412 switch(uMsg) 1413 { 1414 case WM_ERASEBKGND: 1415 return TRUE; 1416 1417 case WM_PAINT: 1418 return HEXEDIT_WM_PAINT(hed); 1419 1420 case WM_KEYDOWN: 1421 return HEXEDIT_WM_KEYDOWN(hed, (INT)wParam); 1422 1423 case WM_CHAR: 1424 return HEXEDIT_WM_CHAR(hed, (WCHAR)wParam); 1425 1426 case WM_VSCROLL: 1427 return HEXEDIT_WM_VSCROLL(hed, HIWORD(wParam), LOWORD(wParam)); 1428 1429 case WM_SIZE: 1430 return HEXEDIT_WM_SIZE(hed, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam)); 1431 1432 case WM_LBUTTONDOWN: 1433 { 1434 p.x = LOWORD(lParam); 1435 p.y = HIWORD(lParam); 1436 return HEXEDIT_WM_LBUTTONDOWN(hed, (INT)wParam, p); 1437 } 1438 1439 case WM_LBUTTONUP: 1440 { 1441 p.x = LOWORD(lParam); 1442 p.y = HIWORD(lParam); 1443 return HEXEDIT_WM_LBUTTONUP(hed, (INT)wParam, p); 1444 } 1445 1446 case WM_MOUSEMOVE: 1447 { 1448 p.x = LOWORD(lParam); 1449 p.y = HIWORD(lParam); 1450 return HEXEDIT_WM_MOUSEMOVE(hed, (INT)wParam, p); 1451 } 1452 1453 case WM_MOUSEWHEEL: 1454 { 1455 UINT nScrollLines = 3; 1456 int delta = 0; 1457 1458 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0); 1459 delta -= (SHORT)HIWORD(wParam); 1460 if(abs(delta) >= WHEEL_DELTA && nScrollLines != 0) 1461 { 1462 p.x = LOWORD(lParam); 1463 p.y = HIWORD(lParam); 1464 return HEXEDIT_WM_MOUSEWHEEL(hed, nScrollLines * (delta / WHEEL_DELTA), LOWORD(wParam), &p); 1465 } 1466 break; 1467 } 1468 1469 case HEM_LOADBUFFER: 1470 return HEXEDIT_HEM_LOADBUFFER(hed, (PVOID)wParam, (DWORD)lParam); 1471 1472 case HEM_COPYBUFFER: 1473 return HEXEDIT_HEM_COPYBUFFER(hed, (PVOID)wParam, (DWORD)lParam); 1474 1475 case HEM_SETMAXBUFFERSIZE: 1476 return HEXEDIT_HEM_SETMAXBUFFERSIZE(hed, (DWORD)lParam); 1477 1478 case WM_SETFOCUS: 1479 return HEXEDIT_WM_SETFOCUS(hed); 1480 1481 case WM_KILLFOCUS: 1482 return HEXEDIT_WM_KILLFOCUS(hed); 1483 1484 case WM_GETDLGCODE: 1485 return HEXEDIT_WM_GETDLGCODE((LPMSG)lParam); 1486 1487 case WM_SETFONT: 1488 return HEXEDIT_WM_SETFONT(hed, (HFONT)wParam, (BOOL)LOWORD(lParam)); 1489 1490 case WM_GETFONT: 1491 return HEXEDIT_WM_GETFONT(hed); 1492 1493 case WM_CREATE: 1494 return HEXEDIT_WM_CREATE(hed); 1495 1496 case WM_NCCREATE: 1497 if(!hed) 1498 { 1499 return HEXEDIT_WM_NCCREATE(hWnd, (CREATESTRUCT*)lParam); 1500 } 1501 break; 1502 1503 case WM_NCDESTROY: 1504 if(hed) 1505 { 1506 return HEXEDIT_WM_NCDESTROY(hed); 1507 } 1508 break; 1509 1510 case WM_CONTEXTMENU: 1511 HEXEDIT_WM_CONTEXTMENU(hed, (short)LOWORD(lParam), (short)HIWORD(lParam)); 1512 break; 1513 1514 case WM_COMMAND: 1515 switch(LOWORD(wParam)) 1516 { 1517 case ID_HEXEDIT_CUT: 1518 HEXEDIT_Cut(hed); 1519 break; 1520 1521 case ID_HEXEDIT_COPY: 1522 HEXEDIT_Copy(hed); 1523 break; 1524 1525 case ID_HEXEDIT_PASTE: 1526 HEXEDIT_Paste(hed); 1527 break; 1528 1529 case ID_HEXEDIT_DELETE: 1530 HEXEDIT_Delete(hed); 1531 break; 1532 1533 case ID_HEXEDIT_SELECT_ALL: 1534 HEXEDIT_SelectAll(hed); 1535 break; 1536 } 1537 break; 1538 } 1539 1540 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 1541 } 1542