xref: /reactos/base/applications/regedit/hexedit.c (revision 470cef7b)
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
RegisterHexEditorClass(HINSTANCE hInstance)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
UnregisterHexEditorClass(HINSTANCE hInstance)77 UnregisterHexEditorClass(HINSTANCE hInstance)
78 {
79     return UnregisterClassW(HEX_EDIT_CLASS_NAME, hInstance);
80 }
81 
82 /*** Helper functions *********************************************************/
83 
84 static VOID
HEXEDIT_MoveCaret(PHEXEDIT_DATA hed,BOOL Scroll)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
HEXEDIT_Update(PHEXEDIT_DATA hed)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
HEXEDIT_GetFixedFont(VOID)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
HEXEDIT_PaintLines(PHEXEDIT_DATA hed,HDC hDC,DWORD ScrollPos,DWORD First,DWORD Last,RECT * rc)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
HEXEDIT_HitRegionTest(PHEXEDIT_DATA hed,POINTS pt)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
HEXEDIT_IndexFromPoint(PHEXEDIT_DATA hed,POINTS pt,DWORD Hit,POINT * EditPos,BOOL * EditField)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
HEXEDIT_Copy(PHEXEDIT_DATA hed)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
HEXEDIT_Delete(PHEXEDIT_DATA hed)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
HEXEDIT_Paste(PHEXEDIT_DATA hed)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
HEXEDIT_Cut(PHEXEDIT_DATA hed)535 HEXEDIT_Cut(PHEXEDIT_DATA hed)
536 {
537     HEXEDIT_Copy(hed);
538     HEXEDIT_Delete(hed);
539 }
540 
541 static VOID
HEXEDIT_SelectAll(PHEXEDIT_DATA hed)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
HEXEDIT_HEM_LOADBUFFER(PHEXEDIT_DATA hed,PVOID Buffer,DWORD Size)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
HEXEDIT_HEM_COPYBUFFER(PHEXEDIT_DATA hed,PVOID Buffer,DWORD Size)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
HEXEDIT_HEM_SETMAXBUFFERSIZE(PHEXEDIT_DATA hed,DWORD nMaxSize)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
HEXEDIT_WM_NCCREATE(HWND hWnd,CREATESTRUCT * cs)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
HEXEDIT_WM_NCDESTROY(PHEXEDIT_DATA hed)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
HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed)714 HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed)
715 {
716     UNREFERENCED_PARAMETER(hed);
717     return 1;
718 }
719 
720 static LRESULT
HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed)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
HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed)730 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed)
731 {
732     UNREFERENCED_PARAMETER(hed);
733     DestroyCaret();
734     return 0;
735 }
736 
737 static LRESULT
HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed,WORD ThumbPosition,WORD SbCmd)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
HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed,HFONT hFont,BOOL bRedraw)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
HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed)831 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed)
832 {
833     return (LRESULT)hed->hFont;
834 }
835 
836 static LRESULT
HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed)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
HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed,int cyMoveLines,WORD ButtonsDown,LPPOINTS MousePos)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
HEXEDIT_WM_GETDLGCODE(LPMSG Msg)928 HEXEDIT_WM_GETDLGCODE(LPMSG Msg)
929 {
930     UNREFERENCED_PARAMETER(Msg);
931     return DLGC_WANTARROWS | DLGC_WANTCHARS;
932 }
933 
934 static LRESULT
HEXEDIT_WM_LBUTTONDOWN(PHEXEDIT_DATA hed,INT Buttons,POINTS Pt)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
HEXEDIT_WM_LBUTTONUP(PHEXEDIT_DATA hed,INT Buttons,POINTS Pt)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
HEXEDIT_WM_MOUSEMOVE(PHEXEDIT_DATA hed,INT Buttons,POINTS Pt)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
HEXEDIT_WM_KEYDOWN(PHEXEDIT_DATA hed,INT VkCode)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
HEXEDIT_WM_CHAR(PHEXEDIT_DATA hed,WCHAR wch)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
HEXEDIT_WM_SIZE(PHEXEDIT_DATA hed,DWORD sType,WORD NewWidth,WORD NewHeight)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
HEXEDIT_WM_CONTEXTMENU(PHEXEDIT_DATA hed,INT x,INT y)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
HexEditWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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