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