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