c127291036e161386e46e1c46fa0fbd6c11e267f
[reactos.git] / reactos / base / applications / regedit / hexedit.c
1 /*
2 * Hex editor control
3 *
4 * Copyright (C) 2004 Thomas Weidenmueller <w3seek@reactos.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <regedit.h>
22 typedef struct
23 {
24 HWND hWndSelf;
25 HWND hWndParent;
26 HLOCAL hBuffer;
27 DWORD style;
28 DWORD MaxBuffer;
29 INT ColumnsPerLine;
30 INT nLines;
31 INT nVisibleLinesComplete;
32 INT nVisibleLines;
33 INT Index;
34 INT LineHeight;
35 INT CharWidth;
36 HFONT hFont;
37 BOOL SbVisible;
38
39 INT LeftMargin;
40 INT AddressSpacing;
41 INT SplitSpacing;
42
43 BOOL EditingField;
44 INT CaretCol;
45 INT CaretLine;
46 BOOL InMid;
47 } HEXEDIT_DATA, *PHEXEDIT_DATA;
48
49 /* hit test codes */
50 #define HEHT_LEFTMARGIN (0x1)
51 #define HEHT_ADDRESS (0x2)
52 #define HEHT_ADDRESSSPACING (0x3)
53 #define HEHT_HEXDUMP (0x4)
54 #define HEHT_HEXDUMPSPACING (0x5)
55 #define HEHT_ASCIIDUMP (0x6)
56 #define HEHT_RIGHTMARGIN (0x7)
57
58 INT_PTR CALLBACK HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
59
60 ATOM
61 WINAPI
62 RegisterHexEditorClass(HINSTANCE hInstance)
63 {
64 WNDCLASSEX WndClass;
65
66 ZeroMemory(&WndClass, sizeof(WNDCLASSEX));
67 WndClass.cbSize = sizeof(WNDCLASSEX);
68 WndClass.style = CS_DBLCLKS;
69 WndClass.lpfnWndProc = (WNDPROC)HexEditWndProc;
70 WndClass.cbWndExtra = sizeof(PHEXEDIT_DATA);
71 WndClass.hInstance = hInstance;
72 WndClass.hCursor = LoadCursor(0, IDC_IBEAM);
73 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
74 WndClass.lpszClassName = HEX_EDIT_CLASS_NAME;
75
76 return RegisterClassEx(&WndClass);
77 }
78
79 BOOL
80 WINAPI
81 UnregisterHexEditorClass(HINSTANCE hInstance)
82 {
83 return UnregisterClass(HEX_EDIT_CLASS_NAME, hInstance);
84 }
85
86 /*** Helper functions *********************************************************/
87
88 static VOID
89 HEXEDIT_MoveCaret(PHEXEDIT_DATA hed, BOOL Scroll)
90 {
91 SCROLLINFO si;
92
93 si.cbSize = sizeof(SCROLLINFO);
94 si.fMask = SIF_POS;
95 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
96
97 if(Scroll)
98 {
99 if(si.nPos > hed->CaretLine)
100 {
101 si.nPos = hed->CaretLine;
102 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
103 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
104 InvalidateRect(hed->hWndSelf, NULL, TRUE);
105 }
106 else if(hed->CaretLine >= (hed->nVisibleLinesComplete + si.nPos))
107 {
108 si.nPos = hed->CaretLine - hed->nVisibleLinesComplete + 1;
109 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
110 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
111 InvalidateRect(hed->hWndSelf, NULL, TRUE);
112 }
113 }
114
115 if(hed->EditingField)
116 SetCaretPos(hed->LeftMargin + ((4 + hed->AddressSpacing + (3 * hed->CaretCol) + hed->InMid * 2) * hed->CharWidth) - 1, (hed->CaretLine - si.nPos) * hed->LineHeight);
117 else
118 SetCaretPos(hed->LeftMargin + ((4 + hed->AddressSpacing + hed->SplitSpacing + (3 * hed->ColumnsPerLine) + hed->CaretCol) * hed->CharWidth) - 2, (hed->CaretLine - si.nPos) * hed->LineHeight);
119 }
120
121 static VOID
122 HEXEDIT_Update(PHEXEDIT_DATA hed)
123 {
124 SCROLLINFO si;
125 RECT rcClient;
126 BOOL SbVisible;
127 INT bufsize, cvislines;
128
129 GetClientRect(hed->hWndSelf, &rcClient);
130 hed->style = GetWindowLongPtr(hed->hWndSelf, GWL_STYLE);
131
132 bufsize = (hed->hBuffer ? (INT) LocalSize(hed->hBuffer) : 0);
133 hed->nLines = max(bufsize / hed->ColumnsPerLine, 1);
134 if(bufsize > hed->ColumnsPerLine && (bufsize % hed->ColumnsPerLine) > 0)
135 {
136 hed->nLines++;
137 }
138
139 if(hed->LineHeight > 0)
140 {
141 hed->nVisibleLinesComplete = cvislines = rcClient.bottom / hed->LineHeight;
142 hed->nVisibleLines = hed->nVisibleLinesComplete;
143 if(rcClient.bottom % hed->LineHeight)
144 {
145 hed->nVisibleLines++;
146 }
147 }
148 else
149 {
150 hed->nVisibleLines = cvislines = 0;
151 }
152
153 SbVisible = bufsize > 0 && cvislines < hed->nLines;
154 ShowScrollBar(hed->hWndSelf, SB_VERT, SbVisible);
155
156 /* update scrollbar */
157 si.cbSize = sizeof(SCROLLINFO);
158 si.fMask = SIF_RANGE | SIF_PAGE;
159 si.nMin = 0;
160 si.nMax = ((bufsize > 0) ? hed->nLines - 1 : 0);
161 si.nPage = ((hed->LineHeight > 0) ? rcClient.bottom / hed->LineHeight : 0);
162 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
163
164 if(IsWindowVisible(hed->hWndSelf) && SbVisible != hed->SbVisible)
165 {
166 InvalidateRect(hed->hWndSelf, NULL, TRUE);
167 }
168
169 hed->SbVisible = SbVisible;
170 }
171
172 static HFONT
173 HEXEDIT_GetFixedFont(VOID)
174 {
175 LOGFONT lf;
176 GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT), &lf);
177 return CreateFontIndirect(&lf);
178 }
179
180 static VOID
181 HEXEDIT_PaintLines(PHEXEDIT_DATA hed, HDC hDC, DWORD ScrollPos, DWORD First, DWORD Last, RECT *rc)
182 {
183 DWORD dx, dy, linestart;
184 INT x;
185 PBYTE buf, current, end, line;
186 size_t bufsize;
187 TCHAR hex[3], addr[17];
188 RECT rct;
189
190 FillRect(hDC, rc, (HBRUSH)(COLOR_WINDOW + 1));
191
192 if(hed->hBuffer)
193 {
194 bufsize = LocalSize(hed->hBuffer);
195 buf = LocalLock(hed->hBuffer);
196 }
197 else
198 {
199 buf = NULL;
200 bufsize = 0;
201
202 if(ScrollPos + First == 0)
203 {
204 /* draw address */
205 _stprintf(addr, _T("%04X"), 0);
206 TextOut(hDC, hed->LeftMargin, First * hed->LineHeight, addr, 4);
207 }
208 }
209
210 if(buf)
211 {
212 end = buf + bufsize;
213 dy = First * hed->LineHeight;
214 linestart = (ScrollPos + First) * hed->ColumnsPerLine;
215 current = buf + linestart;
216 Last = min(hed->nLines - ScrollPos, Last);
217
218 while(First <= Last && current < end)
219 {
220 DWORD dh;
221
222 dx = hed->LeftMargin;
223
224 /* draw address */
225 _stprintf(addr, _T("%04lX"), linestart);
226 TextOut(hDC, dx, dy, addr, 4);
227
228 dx += ((4 + hed->AddressSpacing) * hed->CharWidth);
229 dh = (3 * hed->CharWidth);
230
231 rct.left = dx;
232 rct.top = dy;
233 rct.right = rct.left + dh;
234 rct.bottom = dy + hed->LineHeight;
235
236 /* draw hex map */
237 dx += (hed->CharWidth / 2);
238 line = current;
239 for(x = 0; x < hed->ColumnsPerLine && current < end; x++)
240 {
241 rct.left += dh;
242 rct.right += dh;
243
244 _stprintf(hex, _T("%02X"), *(current++));
245 ExtTextOut(hDC, dx, dy, ETO_OPAQUE, &rct, hex, 2, NULL);
246 dx += dh;
247 }
248
249 /* draw ascii map */
250 dx = ((4 + hed->AddressSpacing + hed->SplitSpacing + (hed->ColumnsPerLine * 3)) * hed->CharWidth);
251 current = line;
252 for(x = 0; x < hed->ColumnsPerLine && current < end; x++)
253 {
254 _stprintf(hex, _T("%C"), *(current++));
255 hex[0] = ((hex[0] & _T('\x007f')) >= _T(' ') ? hex[0] : _T('.'));
256 TextOut(hDC, dx, dy, hex, 1);
257 dx += hed->CharWidth;
258 }
259
260 dy += hed->LineHeight;
261 linestart += hed->ColumnsPerLine;
262 First++;
263 }
264 }
265
266 LocalUnlock(hed->hBuffer);
267 }
268
269 static DWORD
270 HEXEDIT_HitRegionTest(PHEXEDIT_DATA hed, POINTS pt)
271 {
272 int d;
273
274 if(pt.x <= hed->LeftMargin)
275 {
276 return HEHT_LEFTMARGIN;
277 }
278
279 pt.x -= hed->LeftMargin;
280 d = (4 * hed->CharWidth);
281 if(pt.x <= d)
282 {
283 return HEHT_ADDRESS;
284 }
285
286 pt.x -= d;
287 d = (hed->AddressSpacing * hed->CharWidth);
288 if(pt.x <= d)
289 {
290 return HEHT_ADDRESSSPACING;
291 }
292
293 pt.x -= d;
294 d = (3 * hed->ColumnsPerLine * hed->CharWidth);
295 if(pt.x <= d)
296 {
297 return HEHT_HEXDUMP;
298 }
299
300 pt.x -= d;
301 d = (hed->SplitSpacing * hed->CharWidth);
302 if(pt.x <= d)
303 {
304 return HEHT_HEXDUMPSPACING;
305 }
306
307 pt.x -= d;
308 d = (hed->ColumnsPerLine * hed->CharWidth);
309 if(pt.x <= d)
310 {
311 return HEHT_ASCIIDUMP;
312 }
313
314 return HEHT_RIGHTMARGIN;
315 }
316
317 static DWORD
318 HEXEDIT_IndexFromPoint(PHEXEDIT_DATA hed, POINTS pt, DWORD Hit, POINT *EditPos, BOOL *EditField)
319 {
320 SCROLLINFO si;
321 DWORD Index, bufsize;
322
323 si.cbSize = sizeof(SCROLLINFO);
324 si.fMask = SIF_POS;
325 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
326
327 EditPos->x = 0;
328
329 if(hed->LineHeight > 0)
330 {
331 EditPos->y = min(si.nPos + (pt.y / hed->LineHeight), hed->nLines - 1);
332 }
333 else
334 {
335 EditPos->y = si.nPos;
336 }
337
338 switch(Hit)
339 {
340 case HEHT_LEFTMARGIN:
341 case HEHT_ADDRESS:
342 case HEHT_ADDRESSSPACING:
343 case HEHT_HEXDUMP:
344 pt.x -= (SHORT) hed->LeftMargin + ((4 + hed->AddressSpacing) * hed->CharWidth);
345 *EditField = TRUE;
346 break;
347
348 default:
349 pt.x -= hed->LeftMargin + ((4 + hed->AddressSpacing + hed->SplitSpacing + (3 * hed->ColumnsPerLine)) * hed->CharWidth);
350 *EditField = FALSE;
351 break;
352 }
353
354 if(pt.x > 0)
355 {
356 INT BlockWidth = (*EditField ? hed->CharWidth * 3 : hed->CharWidth);
357 EditPos->x = min(hed->ColumnsPerLine, (pt.x + BlockWidth / 2) / BlockWidth);
358 }
359
360 bufsize = (hed->hBuffer ? (DWORD) LocalSize(hed->hBuffer) : 0);
361 Index = (EditPos->y * hed->ColumnsPerLine) + EditPos->x;
362 if(Index > bufsize)
363 {
364 INT tmp = bufsize % hed->ColumnsPerLine;
365 Index = bufsize;
366 EditPos->x = (tmp == 0 ? hed->ColumnsPerLine : tmp);
367 }
368 return Index;
369 }
370
371 /*** Control specific messages ************************************************/
372
373 static LRESULT
374 HEXEDIT_HEM_LOADBUFFER(PHEXEDIT_DATA hed, PVOID Buffer, DWORD Size)
375 {
376 if(Buffer != NULL && Size > 0)
377 {
378 LPVOID buf;
379
380 if(hed->MaxBuffer > 0 && Size > hed->MaxBuffer)
381 {
382 Size = hed->MaxBuffer;
383 }
384
385 if(hed->hBuffer)
386 {
387 if(Size > 0)
388 {
389 if(LocalSize(hed->hBuffer) != Size)
390 {
391 hed->hBuffer = LocalReAlloc(hed->hBuffer, Size, LMEM_MOVEABLE | LMEM_ZEROINIT);
392 }
393 }
394 else
395 {
396 hed->hBuffer = LocalFree(hed->hBuffer);
397 hed->Index = 0;
398 HEXEDIT_Update(hed);
399
400 return 0;
401 }
402 }
403 else if(Size > 0)
404 {
405 hed->hBuffer = LocalAlloc(LHND, Size);
406 }
407
408 if(Size > 0)
409 {
410 buf = LocalLock(hed->hBuffer);
411 if(buf)
412 {
413 memcpy(buf, Buffer, Size);
414 }
415 else
416 Size = 0;
417 LocalUnlock(hed->hBuffer);
418 }
419
420 hed->Index = 0;
421 HEXEDIT_Update(hed);
422 return Size;
423 }
424 else if(hed->hBuffer)
425 {
426 hed->Index = 0;
427 hed->hBuffer = LocalFree(hed->hBuffer);
428 HEXEDIT_Update(hed);
429 }
430
431 return 0;
432 }
433
434 static LRESULT
435 HEXEDIT_HEM_COPYBUFFER(PHEXEDIT_DATA hed, PVOID Buffer, DWORD Size)
436 {
437 size_t nCpy;
438
439 if(!hed->hBuffer)
440 {
441 return 0;
442 }
443
444 if(Buffer != NULL && Size > 0)
445 {
446 nCpy = min(Size, LocalSize(hed->hBuffer));
447 if(nCpy > 0)
448 {
449 PVOID buf;
450
451 buf = LocalLock(hed->hBuffer);
452 if(buf)
453 {
454 memcpy(Buffer, buf, nCpy);
455 }
456 else
457 nCpy = 0;
458 LocalUnlock(hed->hBuffer);
459 }
460 return nCpy;
461 }
462
463 return (LRESULT)LocalSize(hed->hBuffer);
464 }
465
466 static LRESULT
467 HEXEDIT_HEM_SETMAXBUFFERSIZE(PHEXEDIT_DATA hed, DWORD nMaxSize)
468 {
469 hed->MaxBuffer = nMaxSize;
470 if (hed->MaxBuffer == 0)
471 {
472 hed->hBuffer = LocalFree(hed->hBuffer);
473 return 0;
474 }
475 if (hed->hBuffer)
476 hed->hBuffer = LocalReAlloc(hed->hBuffer, hed->MaxBuffer, LMEM_MOVEABLE);
477 else
478 hed->hBuffer = LocalAlloc(LMEM_MOVEABLE, hed->MaxBuffer);
479 HEXEDIT_Update(hed);
480 return 0;
481 }
482
483 /*** Message Proc *************************************************************/
484
485 static LRESULT
486 HEXEDIT_WM_NCCREATE(HWND hWnd, CREATESTRUCT *cs)
487 {
488 PHEXEDIT_DATA hed;
489
490 if(!(hed = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HEXEDIT_DATA))))
491 {
492 return FALSE;
493 }
494
495 hed->hWndSelf = hWnd;
496 hed->hWndParent = cs->hwndParent;
497 hed->style = cs->style;
498
499 hed->ColumnsPerLine = 8;
500 hed->LeftMargin = 2;
501 hed->AddressSpacing = 2;
502 hed->SplitSpacing = 2;
503 hed->EditingField = TRUE; /* in hexdump field */
504 hed->InMid = FALSE;
505
506 SetWindowLongPtr(hWnd, 0, (DWORD_PTR)hed);
507 HEXEDIT_Update(hed);
508
509 return TRUE;
510 }
511
512 static LRESULT
513 HEXEDIT_WM_NCDESTROY(PHEXEDIT_DATA hed)
514 {
515 if(hed->hBuffer)
516 {
517 //while(LocalUnlock(hed->hBuffer));
518 LocalFree(hed->hBuffer);
519 }
520
521 if(hed->hFont)
522 {
523 DeleteObject(hed->hFont);
524 }
525
526 SetWindowLongPtr(hed->hWndSelf, 0, (DWORD_PTR)0);
527 HeapFree(GetProcessHeap(), 0, hed);
528
529 return 0;
530 }
531
532 static LRESULT
533 HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed)
534 {
535 UNREFERENCED_PARAMETER(hed);
536 return 1;
537 }
538
539 static LRESULT
540 HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed)
541 {
542 CreateCaret(hed->hWndSelf, 0, 1, hed->LineHeight);
543 HEXEDIT_MoveCaret(hed, FALSE);
544 ShowCaret(hed->hWndSelf);
545 return 0;
546 }
547
548 static LRESULT
549 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed)
550 {
551 UNREFERENCED_PARAMETER(hed);
552 DestroyCaret();
553 return 0;
554 }
555
556 static LRESULT
557 HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed, WORD ThumbPosition, WORD SbCmd)
558 {
559 int ScrollY;
560 SCROLLINFO si;
561
562 UNREFERENCED_PARAMETER(ThumbPosition);
563
564 ZeroMemory(&si, sizeof(SCROLLINFO));
565 si.cbSize = sizeof(SCROLLINFO);
566 si.fMask = SIF_ALL;
567 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
568
569 ScrollY = si.nPos;
570 switch(SbCmd)
571 {
572 case SB_TOP:
573 si.nPos = si.nMin;
574 break;
575
576 case SB_BOTTOM:
577 si.nPos = si.nMax;
578 break;
579
580 case SB_LINEUP:
581 si.nPos--;
582 break;
583
584 case SB_LINEDOWN:
585 si.nPos++;
586 break;
587
588 case SB_PAGEUP:
589 si.nPos -= si.nPage;
590 break;
591
592 case SB_PAGEDOWN:
593 si.nPos += si.nPage;
594 break;
595
596 case SB_THUMBTRACK:
597 si.nPos = si.nTrackPos;
598 break;
599 }
600
601 si.fMask = SIF_POS;
602 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
603 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
604
605 if(si.nPos != ScrollY)
606 {
607 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
608 UpdateWindow(hed->hWndSelf);
609 }
610
611 return 0;
612 }
613
614 static LRESULT
615 HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed, HFONT hFont, BOOL bRedraw)
616 {
617 HDC hDC;
618 TEXTMETRIC tm;
619 HFONT hOldFont = 0;
620
621 if(hFont == 0)
622 {
623 hFont = HEXEDIT_GetFixedFont();
624 }
625
626 hed->hFont = hFont;
627 hDC = GetDC(hed->hWndSelf);
628 if(hFont)
629 {
630 hOldFont = SelectObject(hDC, hFont);
631 }
632 GetTextMetrics(hDC, &tm);
633 hed->LineHeight = tm.tmHeight;
634 hed->CharWidth = tm.tmAveCharWidth;
635 if(hOldFont)
636 {
637 SelectObject(hDC, hOldFont);
638 }
639 ReleaseDC(hed->hWndSelf, hDC);
640
641 if(bRedraw)
642 {
643 InvalidateRect(hed->hWndSelf, NULL, TRUE);
644 }
645
646 return 0;
647 }
648
649 static LRESULT
650 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed)
651 {
652 return (LRESULT)hed->hFont;
653 }
654
655 static LRESULT
656 HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed)
657 {
658 PAINTSTRUCT ps;
659 SCROLLINFO si;
660 RECT rc;
661 HBITMAP hbmp, hbmpold;
662 INT nLines, nFirst;
663 HFONT hOldFont;
664 HDC hTempDC;
665 DWORD height;
666
667 if(GetUpdateRect(hed->hWndSelf, &rc, FALSE) && (hed->LineHeight > 0))
668 {
669 ZeroMemory(&si, sizeof(SCROLLINFO));
670 si.cbSize = sizeof(SCROLLINFO);
671 si.fMask = SIF_POS;
672 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
673
674 height = (rc.bottom - rc.top);
675 nLines = height / hed->LineHeight;
676 if((height % hed->LineHeight) > 0)
677 {
678 nLines++;
679 }
680 if(nLines > hed->nLines - si.nPos)
681 {
682 nLines = hed->nLines - si.nPos;
683 }
684 nFirst = rc.top / hed->LineHeight;
685
686 BeginPaint(hed->hWndSelf, &ps);
687 if(!(hTempDC = CreateCompatibleDC(ps.hdc)))
688 {
689 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
690 goto epaint;
691 }
692 if(!(hbmp = CreateCompatibleBitmap(hTempDC, ps.rcPaint.right, ps.rcPaint.bottom)))
693 {
694 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
695 DeleteDC(hTempDC);
696 goto epaint;
697 }
698 hbmpold = SelectObject(hTempDC, hbmp);
699 hOldFont = SelectObject(hTempDC, hed->hFont);
700 HEXEDIT_PaintLines(hed, hTempDC, si.nPos, nFirst, nFirst + nLines, &ps.rcPaint);
701 BitBlt(ps.hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hTempDC, rc.left, rc.top, SRCCOPY);
702 SelectObject(hTempDC, hOldFont);
703 SelectObject(hTempDC, hbmpold);
704
705 DeleteObject(hbmp);
706 DeleteDC(hTempDC);
707
708 epaint:
709 EndPaint(hed->hWndSelf, &ps);
710 }
711
712 return 0;
713 }
714
715 static LRESULT
716 HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed, int cyMoveLines, WORD ButtonsDown, LPPOINTS MousePos)
717 {
718 SCROLLINFO si;
719 int ScrollY;
720
721 UNREFERENCED_PARAMETER(ButtonsDown);
722 UNREFERENCED_PARAMETER(MousePos);
723
724 SetFocus(hed->hWndSelf);
725
726 si.cbSize = sizeof(SCROLLINFO);
727 si.fMask = SIF_ALL;
728 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
729
730 ScrollY = si.nPos;
731
732 si.fMask = SIF_POS;
733 si.nPos += cyMoveLines;
734 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
735
736 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
737 if(si.nPos != ScrollY)
738 {
739 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
740 UpdateWindow(hed->hWndSelf);
741 }
742
743 return 0;
744 }
745
746 static LRESULT
747 HEXEDIT_WM_GETDLGCODE(LPMSG Msg)
748 {
749 UNREFERENCED_PARAMETER(Msg);
750 return DLGC_WANTARROWS | DLGC_WANTCHARS;
751 }
752
753 static LRESULT
754 HEXEDIT_WM_LBUTTONDOWN(PHEXEDIT_DATA hed, INT Buttons, POINTS Pt)
755 {
756 BOOL NewField;
757 POINT EditPos;
758 DWORD Hit = HEXEDIT_HitRegionTest(hed, Pt);
759
760 UNREFERENCED_PARAMETER(Buttons);
761 SetFocus(hed->hWndSelf);
762
763 hed->Index = HEXEDIT_IndexFromPoint(hed, Pt, Hit, &EditPos, &NewField);
764 hed->EditingField = NewField;
765 hed->CaretCol = EditPos.x;
766 hed->CaretLine = EditPos.y;
767 hed->InMid = FALSE;
768
769 HEXEDIT_MoveCaret(hed, TRUE);
770
771 return 0;
772 }
773
774 static BOOL
775 HEXEDIT_WM_KEYDOWN(PHEXEDIT_DATA hed, INT VkCode)
776 {
777 size_t bufsize;
778 PBYTE buf;
779 if(GetKeyState(VK_MENU) & 0x8000)
780 {
781 return FALSE;
782 }
783
784 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0);
785
786 switch(VkCode)
787 {
788 case VK_DELETE:
789 if (hed->InMid && hed->EditingField)
790 {
791 buf = (PBYTE) LocalLock(hed->hBuffer);
792 if (buf)
793 {
794 MoveMemory(buf + hed->Index, buf + hed->Index + 1,
795 bufsize - hed->Index - 1);
796 LocalUnlock(hed->hBuffer);
797 }
798 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1);
799 hed->InMid = FALSE;
800 }
801 else if (hed->Index < bufsize)
802 {
803 buf = (PBYTE) LocalLock(hed->hBuffer);
804 if (buf)
805 {
806 MoveMemory(buf + hed->Index, buf + hed->Index + 1,
807 bufsize - hed->Index - 1);
808 LocalUnlock(hed->hBuffer);
809 }
810 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1);
811 }
812 InvalidateRect(hed->hWndSelf, NULL, TRUE);
813 HEXEDIT_MoveCaret(hed, TRUE);
814 break;
815
816 case VK_BACK:
817 if (hed->InMid && hed->EditingField)
818 {
819 buf = (PBYTE) LocalLock(hed->hBuffer);
820 if (buf)
821 {
822 MoveMemory(buf + hed->Index, buf + hed->Index + 1,
823 bufsize - hed->Index - 1);
824 LocalUnlock(hed->hBuffer);
825 }
826 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1);
827 hed->InMid = FALSE;
828 }
829 else if (hed->Index > 0)
830 {
831 buf = (PBYTE) LocalLock(hed->hBuffer);
832 if (buf)
833 {
834 MoveMemory(buf + hed->Index - 1, buf + hed->Index,
835 bufsize - hed->Index);
836 LocalUnlock(hed->hBuffer);
837 }
838 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize - 1);
839 hed->Index--;
840 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
841 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
842 hed->InMid = FALSE;
843 }
844 InvalidateRect(hed->hWndSelf, NULL, TRUE);
845 HEXEDIT_MoveCaret(hed, TRUE);
846 break;
847
848 case VK_LEFT:
849 if (hed->Index > 0)
850 {
851 hed->Index--;
852 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
853 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
854 hed->InMid = FALSE;
855 HEXEDIT_MoveCaret(hed, TRUE);
856 }
857 break;
858
859 case VK_RIGHT:
860 if (hed->Index < (INT)bufsize)
861 {
862 hed->Index++;
863 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
864 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
865 hed->InMid = FALSE;
866 HEXEDIT_MoveCaret(hed, TRUE);
867 }
868 break;
869
870 case VK_UP:
871 if (hed->Index >= hed->ColumnsPerLine)
872 {
873 hed->Index -= hed->ColumnsPerLine;
874 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
875 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
876 hed->InMid = FALSE;
877 HEXEDIT_MoveCaret(hed, TRUE);
878 }
879 break;
880
881 case VK_DOWN:
882 if (hed->Index + hed->ColumnsPerLine <= (INT) bufsize)
883 {
884 hed->Index += hed->ColumnsPerLine;
885 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
886 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
887 }
888 else
889 {
890 hed->Index = bufsize;
891 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
892 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
893 }
894 hed->InMid = FALSE;
895 HEXEDIT_MoveCaret(hed, TRUE);
896 break;
897 }
898
899 return FALSE;
900 }
901
902 static BOOL
903 HEXEDIT_WM_CHAR(PHEXEDIT_DATA hed, WCHAR ch)
904 {
905 size_t bufsize;
906 PBYTE buf;
907
908 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0);
909 if (!hed->EditingField)
910 {
911 if (0x20 <= ch && ch < 0x7F)
912 {
913 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize + 1);
914 buf = (PBYTE) LocalLock(hed->hBuffer);
915 if (buf)
916 {
917 MoveMemory(buf + hed->Index + 1, buf + hed->Index,
918 bufsize - hed->Index);
919 buf[hed->Index] = ch;
920 LocalUnlock(hed->hBuffer);
921 }
922 hed->Index++;
923 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
924 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
925 InvalidateRect(hed->hWndSelf, NULL, TRUE);
926 HEXEDIT_MoveCaret(hed, TRUE);
927 return FALSE;
928 }
929 }
930 else
931 {
932 if (('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') ||
933 ('a' <= ch && ch <= 'f'))
934 {
935 if (hed->InMid)
936 {
937 buf = (PBYTE) LocalLock(hed->hBuffer);
938 if (buf)
939 {
940 if ('0' <= ch && ch <= '9')
941 buf[hed->Index] |= ch - '0';
942 else if ('A' <= ch && ch <= 'F')
943 buf[hed->Index] |= ch + 10 - 'A';
944 else if ('a' <= ch && ch <= 'f')
945 buf[hed->Index] |= ch + 10 - 'a';
946 LocalUnlock(hed->hBuffer);
947 }
948 hed->InMid = FALSE;
949 hed->Index++;
950 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
951 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
952 InvalidateRect(hed->hWndSelf, NULL, TRUE);
953 HEXEDIT_MoveCaret(hed, TRUE);
954 }
955 else
956 {
957 HexEdit_SetMaxBufferSize(hed->hWndSelf, bufsize + 1);
958 buf = (PBYTE) LocalLock(hed->hBuffer);
959 if (buf)
960 {
961 MoveMemory(buf + hed->Index + 1, buf + hed->Index,
962 bufsize - hed->Index);
963 if ('0' <= ch && ch <= '9')
964 buf[hed->Index] = (ch - '0') << 4;
965 else if ('A' <= ch && ch <= 'F')
966 buf[hed->Index] = (ch + 10 - 'A') << 4;
967 else if ('a' <= ch && ch <= 'f')
968 buf[hed->Index] = (ch + 10 - 'a') << 4;
969 LocalUnlock(hed->hBuffer);
970 }
971 hed->InMid = TRUE;
972 hed->CaretCol = hed->Index % hed->ColumnsPerLine;
973 hed->CaretLine = hed->Index / hed->ColumnsPerLine;
974 InvalidateRect(hed->hWndSelf, NULL, TRUE);
975 HEXEDIT_MoveCaret(hed, TRUE);
976 }
977 return FALSE;
978 }
979 }
980 return TRUE;
981 }
982
983 static LRESULT
984 HEXEDIT_WM_SIZE(PHEXEDIT_DATA hed, DWORD sType, WORD NewWidth, WORD NewHeight)
985 {
986 UNREFERENCED_PARAMETER(sType);
987 UNREFERENCED_PARAMETER(NewHeight);
988 UNREFERENCED_PARAMETER(NewWidth);
989 HEXEDIT_Update(hed);
990 return 0;
991 }
992
993 INT_PTR CALLBACK
994 HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
995 {
996 PHEXEDIT_DATA hed;
997 POINTS p;
998
999 hed = (PHEXEDIT_DATA)(LONG_PTR)GetWindowLongPtr(hWnd, (DWORD_PTR)0);
1000 switch(uMsg)
1001 {
1002 case WM_ERASEBKGND:
1003 return TRUE;
1004
1005 case WM_PAINT:
1006 return HEXEDIT_WM_PAINT(hed);
1007
1008 case WM_KEYDOWN:
1009 return HEXEDIT_WM_KEYDOWN(hed, (INT)wParam);
1010
1011 case WM_CHAR:
1012 return HEXEDIT_WM_CHAR(hed, (WCHAR)wParam);
1013
1014 case WM_VSCROLL:
1015 return HEXEDIT_WM_VSCROLL(hed, HIWORD(wParam), LOWORD(wParam));
1016
1017 case WM_SIZE:
1018 return HEXEDIT_WM_SIZE(hed, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
1019
1020 case WM_LBUTTONDOWN:
1021 {
1022 p.x = LOWORD(lParam);
1023 p.y = HIWORD(lParam);
1024 return HEXEDIT_WM_LBUTTONDOWN(hed, (INT)wParam, p);
1025 }
1026
1027 case WM_MOUSEWHEEL:
1028 {
1029 UINT nScrollLines = 3;
1030 int delta = 0;
1031
1032 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
1033 delta -= (SHORT)HIWORD(wParam);
1034 if(abs(delta) >= WHEEL_DELTA && nScrollLines != 0)
1035 {
1036 p.x = LOWORD(lParam);
1037 p.y = HIWORD(lParam);
1038 return HEXEDIT_WM_MOUSEWHEEL(hed, nScrollLines * (delta / WHEEL_DELTA), LOWORD(wParam), &p);
1039 }
1040 break;
1041 }
1042
1043 case HEM_LOADBUFFER:
1044 return HEXEDIT_HEM_LOADBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
1045
1046 case HEM_COPYBUFFER:
1047 return HEXEDIT_HEM_COPYBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
1048
1049 case HEM_SETMAXBUFFERSIZE:
1050 return HEXEDIT_HEM_SETMAXBUFFERSIZE(hed, (DWORD)lParam);
1051
1052 case WM_SETFOCUS:
1053 return HEXEDIT_WM_SETFOCUS(hed);
1054
1055 case WM_KILLFOCUS:
1056 return HEXEDIT_WM_KILLFOCUS(hed);
1057
1058 case WM_GETDLGCODE:
1059 return HEXEDIT_WM_GETDLGCODE((LPMSG)lParam);
1060
1061 case WM_SETFONT:
1062 return HEXEDIT_WM_SETFONT(hed, (HFONT)wParam, (BOOL)LOWORD(lParam));
1063
1064 case WM_GETFONT:
1065 return HEXEDIT_WM_GETFONT(hed);
1066
1067 case WM_CREATE:
1068 return HEXEDIT_WM_CREATE(hed);
1069
1070 case WM_NCCREATE:
1071 if(!hed)
1072 {
1073 return HEXEDIT_WM_NCCREATE(hWnd, (CREATESTRUCT*)lParam);
1074 }
1075 break;
1076
1077 case WM_NCDESTROY:
1078 if(hed)
1079 {
1080 return HEXEDIT_WM_NCDESTROY(hed);
1081 }
1082 break;
1083 }
1084
1085 return CallWindowProc(DefWindowProc, hWnd, uMsg, wParam, lParam);
1086 }
1087