xref: /reactos/base/applications/regedit/hexedit.c (revision 4561998a)
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 LRESULT 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 = 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 LRESULT CALLBACK
1419 HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1420 {
1421     PHEXEDIT_DATA hed;
1422     POINTS p;
1423 
1424     hed = (PHEXEDIT_DATA)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 }
1555