some little fixes
[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 LRESULT WINAPI 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, POINTS *ptClient)
275 {
276 WINDOWINFO wi;
277 int d, x;
278
279 wi.cbSize = sizeof(WINDOWINFO);
280 GetWindowInfo(hed->hWndSelf, &wi);
281
282 x = pt.x - wi.rcClient.left;
283 if(ptClient)
284 {
285 ptClient->x = x;
286 ptClient->y = pt.y - wi.rcClient.top;
287 }
288
289 if(x <= hed->LeftMargin)
290 {
291 return HEHT_LEFTMARGIN;
292 }
293
294 x -= hed->LeftMargin;
295 d = (4 * hed->CharWidth);
296 if(x <= d)
297 {
298 return HEHT_ADDRESS;
299 }
300
301 x -= d;
302 d = (hed->AddressSpacing * hed->CharWidth);
303 if(x <= d)
304 {
305 return HEHT_ADDRESSSPACING;
306 }
307
308 x -= d;
309 d = (3 * hed->ColumnsPerLine * hed->CharWidth);
310 if(x <= d)
311 {
312 return HEHT_HEXDUMP;
313 }
314
315 x -= d;
316 d = (hed->SplitSpacing * hed->CharWidth);
317 if(x <= d)
318 {
319 return HEHT_HEXDUMPSPACING;
320 }
321
322 x -= d;
323 d = (hed->ColumnsPerLine * hed->CharWidth);
324 if(x <= d)
325 {
326 return HEHT_ASCIIDUMP;
327 }
328
329 return HEHT_RIGHTMARGIN;
330 }
331
332 static DWORD
333 HEXEDIT_PositionFromPoint(PHEXEDIT_DATA hed, POINTS pt, DWORD *Hit)
334 {
335 SCROLLINFO si;
336 POINTS ptClient;
337 DWORD Line;
338
339 *Hit = HEXEDIT_HitRegionTest(hed, pt, &ptClient);
340
341 si.cbSize = sizeof(SCROLLINFO);
342 si.fMask = SIF_POS;
343 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
344
345 if(hed->LineHeight > 0)
346 {
347 Line = min(si.nPos + (ptClient.y / hed->LineHeight), hed->nLines);
348 }
349 else
350 return 0;
351
352 switch(*Hit)
353 {
354 case HEHT_LEFTMARGIN:
355 case HEHT_ADDRESS:
356 case HEHT_ADDRESSSPACING:
357 return Line * hed->ColumnsPerLine;
358
359 case HEHT_HEXDUMP:
360 return 0;
361
362 case HEHT_ASCIIDUMP:
363 return 0;
364
365 case HEHT_RIGHTMARGIN:
366 return (Line + 1) * hed->ColumnsPerLine;
367 }
368 }
369
370 /*** Control specific messages ************************************************/
371
372 static LRESULT
373 HEXEDIT_HEM_LOADBUFFER(PHEXEDIT_DATA hed, PVOID Buffer, DWORD Size)
374 {
375 if(Buffer != NULL && Size > 0)
376 {
377 LPVOID buf;
378
379 if(hed->MaxBuffer > 0 && Size > hed->MaxBuffer)
380 {
381 Size = hed->MaxBuffer;
382 }
383
384 if(hed->hBuffer)
385 {
386 if(Size > 0)
387 {
388 if(LocalSize(hed->hBuffer) != Size)
389 {
390 hed->hBuffer = LocalReAlloc(hed->hBuffer, Size, LMEM_MOVEABLE | LMEM_ZEROINIT);
391 }
392 }
393 else
394 {
395 hed->hBuffer = LocalFree(hed->hBuffer);
396 hed->Position = 0;
397 HEXEDIT_Update(hed);
398
399 return 0;
400 }
401 }
402 else if(Size > 0)
403 {
404 hed->hBuffer = LocalAlloc(LHND, Size);
405 }
406
407 if(Size > 0)
408 {
409 buf = LocalLock(hed->hBuffer);
410 if(buf)
411 {
412 memcpy(buf, Buffer, Size);
413 }
414 else
415 Size = 0;
416 LocalUnlock(hed->hBuffer);
417 }
418
419 hed->Position = 0;
420 HEXEDIT_Update(hed);
421 return Size;
422 }
423 else if(hed->hBuffer)
424 {
425 hed->Position = 0;
426 hed->hBuffer = LocalFree(hed->hBuffer);
427 HEXEDIT_Update(hed);
428 }
429
430 return 0;
431 }
432
433 static LRESULT
434 HEXEDIT_HEM_COPYBUFFER(PHEXEDIT_DATA hed, PVOID Buffer, DWORD Size)
435 {
436 DWORD nCpy;
437
438 if(!hed->hBuffer)
439 {
440 return 0;
441 }
442
443 if(Buffer != NULL && Size > 0)
444 {
445 nCpy = min(Size, LocalSize(hed->hBuffer));
446 if(nCpy > 0)
447 {
448 PVOID buf;
449
450 buf = LocalLock(hed->hBuffer);
451 if(buf)
452 {
453 memcpy(Buffer, buf, nCpy);
454 }
455 else
456 nCpy = 0;
457 LocalUnlock(hed->hBuffer);
458 }
459 return nCpy;
460 }
461
462 return (LRESULT)LocalSize(hed->hBuffer);
463 }
464
465 static LRESULT
466 HEXEDIT_HEM_SETMAXBUFFERSIZE(PHEXEDIT_DATA hed, DWORD nMaxSize)
467 {
468 hed->MaxBuffer = nMaxSize;
469 if(hed->MaxBuffer > 0 && hed->hBuffer && LocalSize(hed->hBuffer) > hed->MaxBuffer)
470 {
471 /* truncate the buffer */
472 hed->hBuffer = LocalReAlloc(hed->hBuffer, hed->MaxBuffer, LMEM_MOVEABLE);
473 HEXEDIT_Update(hed);
474 }
475 }
476
477 /*** Message Proc *************************************************************/
478
479 static LRESULT
480 HEXEDIT_WM_NCCREATE(HWND hWnd, CREATESTRUCT *cs)
481 {
482 PHEXEDIT_DATA hed;
483
484 if(!(hed = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HEXEDIT_DATA))))
485 {
486 return FALSE;
487 }
488
489 hed->hWndSelf = hWnd;
490 hed->hWndParent = cs->hwndParent;
491 hed->style = cs->style;
492
493 hed->ColumnsPerLine = 8;
494 hed->LeftMargin = 2;
495 hed->AddressSpacing = 2;
496 hed->SplitSpacing = 2;
497 hed->EditingField = TRUE; /* in hexdump field */
498
499 SetWindowLong(hWnd, 0, (LONG)hed);
500 HEXEDIT_Update(hed);
501
502 return TRUE;
503 }
504
505 static LRESULT
506 HEXEDIT_WM_NCDESTROY(PHEXEDIT_DATA hed)
507 {
508 if(hed->hBuffer)
509 {
510 while(LocalUnlock(hed->hBuffer));
511 LocalFree(hed->hBuffer);
512 }
513
514 if(hed->hFont)
515 {
516 DeleteObject(hed->hFont);
517 }
518
519 SetWindowLong(hed->hWndSelf, 0, 0);
520 HeapFree(GetProcessHeap(), 0, hed);
521
522 return 0;
523 }
524
525 static LRESULT
526 HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed)
527 {
528 return 1;
529 }
530
531 static LRESULT
532 HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed)
533 {
534 CreateCaret(hed->hWndSelf, 0, 1, hed->LineHeight);
535 HEXEDIT_MoveCaret(hed, FALSE);
536 ShowCaret(hed->hWndSelf);
537 return 0;
538 }
539
540 static LRESULT
541 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed)
542 {
543 DestroyCaret();
544 return 0;
545 }
546
547 static LRESULT
548 HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed, WORD ThumbPosition, WORD SbCmd)
549 {
550 int ScrollY;
551 SCROLLINFO si;
552
553 ZeroMemory(&si, sizeof(SCROLLINFO));
554 si.cbSize = sizeof(SCROLLINFO);
555 si.fMask = SIF_ALL;
556 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
557
558 ScrollY = si.nPos;
559 switch(SbCmd)
560 {
561 case SB_TOP:
562 si.nPos = si.nMin;
563 break;
564
565 case SB_BOTTOM:
566 si.nPos = si.nMax;
567 break;
568
569 case SB_LINEUP:
570 si.nPos--;
571 break;
572
573 case SB_LINEDOWN:
574 si.nPos++;
575 break;
576
577 case SB_PAGEUP:
578 si.nPos -= si.nPage;
579 break;
580
581 case SB_PAGEDOWN:
582 si.nPos += si.nPage;
583 break;
584
585 case SB_THUMBTRACK:
586 si.nPos = si.nTrackPos;
587 break;
588 }
589
590 si.fMask = SIF_POS;
591 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
592 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
593
594 if(si.nPos != ScrollY)
595 {
596 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
597 UpdateWindow(hed->hWndSelf);
598 }
599
600 return 0;
601 }
602
603 static LRESULT
604 HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed, HFONT hFont, BOOL bRedraw)
605 {
606 HDC hDC;
607 TEXTMETRIC tm;
608 HFONT hOldFont = 0;
609
610 if(hFont == 0)
611 {
612 hFont = HEXEDIT_GetFixedFont();
613 }
614
615 hed->hFont = hFont;
616 hDC = GetDC(hed->hWndSelf);
617 if(hFont)
618 {
619 hOldFont = SelectObject(hDC, hFont);
620 }
621 GetTextMetrics(hDC, &tm);
622 hed->LineHeight = tm.tmHeight;
623 hed->CharWidth = tm.tmAveCharWidth;
624 if(hOldFont)
625 {
626 SelectObject(hDC, hOldFont);
627 }
628 ReleaseDC(hed->hWndSelf, hDC);
629
630 if(bRedraw)
631 {
632 InvalidateRect(hed->hWndSelf, NULL, TRUE);
633 }
634
635 return 0;
636 }
637
638 static LRESULT
639 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed)
640 {
641 return (LRESULT)hed->hFont;
642 }
643
644 static LRESULT
645 HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed)
646 {
647 PAINTSTRUCT ps;
648 SCROLLINFO si;
649 RECT rc;
650 HBITMAP hbmp, hbmpold;
651 DWORD nLines, nFirst;
652 HFONT hOldFont;
653 HDC hTempDC;
654 DWORD height;
655
656 if(GetUpdateRect(hed->hWndSelf, &rc, FALSE) && (hed->LineHeight > 0))
657 {
658 ZeroMemory(&si, sizeof(SCROLLINFO));
659 si.cbSize = sizeof(SCROLLINFO);
660 si.fMask = SIF_POS;
661 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
662
663 height = (rc.bottom - rc.top);
664 nLines = height / hed->LineHeight;
665 if((height % hed->LineHeight) > 0)
666 {
667 nLines++;
668 }
669 if(nLines > hed->nLines - si.nPos)
670 {
671 nLines = hed->nLines - si.nPos;
672 }
673 nFirst = rc.top / hed->LineHeight;
674
675 BeginPaint(hed->hWndSelf, &ps);
676 if(!(hTempDC = CreateCompatibleDC(ps.hdc)))
677 {
678 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
679 goto epaint;
680 }
681 if(!(hbmp = CreateCompatibleBitmap(hTempDC, ps.rcPaint.right, ps.rcPaint.bottom)))
682 {
683 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
684 DeleteDC(hTempDC);
685 goto epaint;
686 }
687 hbmpold = SelectObject(hTempDC, hbmp);
688 hOldFont = SelectObject(hTempDC, hed->hFont);
689 HEXEDIT_PaintLines(hed, hTempDC, si.nPos, nFirst, nFirst + nLines, &ps.rcPaint);
690 BitBlt(ps.hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hTempDC, rc.left, rc.top, SRCCOPY);
691 SelectObject(hTempDC, hOldFont);
692 SelectObject(hTempDC, hbmpold);
693
694 DeleteObject(hbmp);
695 DeleteDC(hTempDC);
696
697 epaint:
698 EndPaint(hed->hWndSelf, &ps);
699 }
700
701 return 0;
702 }
703
704 static LRESULT
705 HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed, int cyMoveLines, WORD ButtonsDown, LPPOINTS MousePos)
706 {
707 SCROLLINFO si;
708 int ScrollY;
709
710 SetFocus(hed->hWndSelf);
711
712 si.cbSize = sizeof(SCROLLINFO);
713 si.fMask = SIF_ALL;
714 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
715
716 ScrollY = si.nPos;
717
718 si.fMask = SIF_POS;
719 si.nPos += cyMoveLines;
720 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
721
722 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
723 if(si.nPos != ScrollY)
724 {
725 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
726 UpdateWindow(hed->hWndSelf);
727 }
728
729 return 0;
730 }
731
732 static LRESULT
733 HEXEDIT_WM_GETDLGCODE(LPMSG Msg)
734 {
735 return DLGC_WANTARROWS | DLGC_WANTCHARS;
736 }
737
738 static BOOL
739 HEXEDIT_WM_KEYDOWN(PHEXEDIT_DATA hed, INT VkCode)
740 {
741 DWORD bufsize;
742 BOOL shift, control;
743
744 if(GetKeyState(VK_MENU) & 0x8000)
745 {
746 return FALSE;
747 }
748
749 shift = GetKeyState(VK_SHIFT) & 0x8000;
750 control = GetKeyState(VK_CONTROL) & 0x8000;
751
752 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0);
753
754 switch(VkCode)
755 {
756 case VK_LEFT:
757 if(hed->Position > 0)
758 {
759 if(--hed->CaretCol < 0)
760 {
761 hed->CaretLine--;
762 hed->CaretCol = hed->ColumnsPerLine;
763 }
764 else
765 hed->Position--;
766 }
767 HEXEDIT_MoveCaret(hed, TRUE);
768 break;
769
770 case VK_RIGHT:
771 if(hed->Position < bufsize)
772 {
773 if(++hed->CaretCol > hed->ColumnsPerLine)
774 {
775 hed->CaretCol = 0;
776 hed->CaretLine++;
777 }
778 else
779 hed->Position++;
780 }
781 HEXEDIT_MoveCaret(hed, TRUE);
782 break;
783
784 case VK_UP:
785 if(hed->Position > 0)
786 {
787 if(hed->CaretLine <= 0)
788 {
789 hed->CaretCol = 0;
790 hed->Position = 0;
791 }
792 else
793 {
794 hed->CaretLine--;
795 hed->Position -= hed->ColumnsPerLine;
796 }
797 }
798 HEXEDIT_MoveCaret(hed, TRUE);
799 break;
800
801 case VK_DOWN:
802 if(hed->Position <= bufsize)
803 {
804 if(hed->CaretLine < hed->nLines - 1)
805 {
806 hed->Position += hed->ColumnsPerLine;
807 hed->CaretLine++;
808 if(hed->Position > bufsize)
809 {
810 hed->Position = bufsize;
811 hed->CaretLine = (hed->nLines > 0 ? hed->nLines - 1 : 0);
812 hed->CaretCol = bufsize % hed->ColumnsPerLine;
813 }
814 }
815 else
816 {
817 INT tmp = bufsize % hed->ColumnsPerLine;
818 hed->Position = bufsize;
819 hed->CaretCol = (tmp == 0 ? hed->ColumnsPerLine : tmp);
820 }
821 }
822 HEXEDIT_MoveCaret(hed, TRUE);
823 break;
824 }
825
826 return FALSE;
827 }
828
829 static LRESULT
830 HEXEDIT_WM_SIZE(PHEXEDIT_DATA hed, DWORD sType, WORD NewWidth, WORD NewHeight)
831 {
832 HEXEDIT_Update(hed);
833 return 0;
834 }
835
836 LRESULT
837 WINAPI
838 HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
839 {
840 PHEXEDIT_DATA hed;
841
842 hed = (PHEXEDIT_DATA)GetWindowLong(hWnd, 0);
843 switch(uMsg)
844 {
845 case WM_ERASEBKGND:
846 return TRUE;
847
848 case WM_PAINT:
849 return HEXEDIT_WM_PAINT(hed);
850
851 case WM_KEYDOWN:
852 return HEXEDIT_WM_KEYDOWN(hed, (INT)wParam);
853
854 case WM_VSCROLL:
855 return HEXEDIT_WM_VSCROLL(hed, HIWORD(wParam), LOWORD(wParam));
856
857 case WM_SIZE:
858 return HEXEDIT_WM_SIZE(hed, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
859
860 case WM_MOUSEWHEEL:
861 {
862 UINT nScrollLines = 3;
863 int delta = 0;
864
865 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
866 delta -= (SHORT)HIWORD(wParam);
867 if(abs(delta) >= WHEEL_DELTA && nScrollLines != 0)
868 {
869 return HEXEDIT_WM_MOUSEWHEEL(hed, nScrollLines * (delta / WHEEL_DELTA), LOWORD(wParam), &MAKEPOINTS(lParam));
870 }
871 break;
872 }
873
874 case HEM_LOADBUFFER:
875 return HEXEDIT_HEM_LOADBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
876
877 case HEM_COPYBUFFER:
878 return HEXEDIT_HEM_COPYBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
879
880 case HEM_SETMAXBUFFERSIZE:
881 return HEXEDIT_HEM_SETMAXBUFFERSIZE(hed, (DWORD)lParam);
882
883 case WM_SETFOCUS:
884 return HEXEDIT_WM_SETFOCUS(hed);
885
886 case WM_KILLFOCUS:
887 return HEXEDIT_WM_KILLFOCUS(hed);
888
889 case WM_GETDLGCODE:
890 return HEXEDIT_WM_GETDLGCODE((LPMSG)lParam);
891
892 case WM_SETFONT:
893 return HEXEDIT_WM_SETFONT(hed, (HFONT)wParam, (BOOL)LOWORD(lParam));
894
895 case WM_GETFONT:
896 return HEXEDIT_WM_GETFONT(hed);
897
898 case WM_CREATE:
899 return HEXEDIT_WM_CREATE(hed);
900
901 case WM_NCCREATE:
902 if(!hed)
903 {
904 return HEXEDIT_WM_NCCREATE(hWnd, (CREATESTRUCT*)lParam);
905 }
906 break;
907
908 case WM_NCDESTROY:
909 if(hed)
910 {
911 return HEXEDIT_WM_NCDESTROY(hed);
912 }
913 break;
914 }
915
916 return CallWindowProc(DefWindowProc, hWnd, uMsg, wParam, lParam);
917 }
918