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