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