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