09ddc5b6f01f602fc047cb639b0e2b1dc1ff568c
[reactos.git] / 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 Position;
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 } HEXEDIT_DATA, *PHEXEDIT_DATA;
47
48 /* hit test codes */
49 #define HEHT_LEFTMARGIN (0x1)
50 #define HEHT_ADDRESS (0x2)
51 #define HEHT_ADDRESSSPACING (0x3)
52 #define HEHT_HEXDUMP (0x4)
53 #define HEHT_HEXDUMPSPACING (0x5)
54 #define HEHT_ASCIIDUMP (0x6)
55 #define HEHT_RIGHTMARGIN (0x7)
56
57 INT_PTR CALLBACK HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
58
59 ATOM
60 WINAPI
61 RegisterHexEditorClass(HINSTANCE hInstance)
62 {
63 WNDCLASSEX WndClass;
64
65 ZeroMemory(&WndClass, sizeof(WNDCLASSEX));
66 WndClass.cbSize = sizeof(WNDCLASSEX);
67 WndClass.style = CS_DBLCLKS;
68 WndClass.lpfnWndProc = (WNDPROC)HexEditWndProc;
69 WndClass.cbWndExtra = sizeof(PHEXEDIT_DATA);
70 WndClass.hInstance = hInstance;
71 WndClass.hCursor = LoadCursor(0, IDC_IBEAM);
72 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
73 WndClass.lpszClassName = HEX_EDIT_CLASS_NAME;
74
75 return RegisterClassEx(&WndClass);
76 }
77
78 BOOL
79 WINAPI
80 UnregisterHexEditorClass(HINSTANCE hInstance)
81 {
82 return UnregisterClass(HEX_EDIT_CLASS_NAME, hInstance);
83 }
84
85 /*** Helper functions *********************************************************/
86
87 static VOID
88 HEXEDIT_MoveCaret(PHEXEDIT_DATA hed, BOOL Scroll)
89 {
90 SCROLLINFO si;
91
92 si.cbSize = sizeof(SCROLLINFO);
93 si.fMask = SIF_POS;
94 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
95
96 if(Scroll)
97 {
98 if(si.nPos > hed->CaretLine)
99 {
100 si.nPos = hed->CaretLine;
101 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
102 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
103 InvalidateRect(hed->hWndSelf, NULL, TRUE);
104 }
105 else if(hed->CaretLine >= (hed->nVisibleLinesComplete + si.nPos))
106 {
107 si.nPos = hed->CaretLine - hed->nVisibleLinesComplete + 1;
108 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
109 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
110 InvalidateRect(hed->hWndSelf, NULL, TRUE);
111 }
112 }
113
114 if(hed->EditingField)
115 SetCaretPos(hed->LeftMargin + ((4 + hed->AddressSpacing + (3 * hed->CaretCol)) * hed->CharWidth) - 1, (hed->CaretLine - si.nPos) * hed->LineHeight);
116 else
117 SetCaretPos(hed->LeftMargin + ((4 + hed->AddressSpacing + hed->SplitSpacing + (3 * hed->ColumnsPerLine) + hed->CaretCol) * hed->CharWidth) - 2, (hed->CaretLine - si.nPos) * hed->LineHeight);
118 }
119
120 static VOID
121 HEXEDIT_Update(PHEXEDIT_DATA hed)
122 {
123 SCROLLINFO si;
124 RECT rcClient;
125 BOOL SbVisible;
126 INT bufsize, cvislines;
127
128 GetClientRect(hed->hWndSelf, &rcClient);
129 hed->style = GetWindowLongPtr(hed->hWndSelf, GWL_STYLE);
130
131 bufsize = (hed->hBuffer ? (INT) LocalSize(hed->hBuffer) : 0);
132 hed->nLines = max(bufsize / hed->ColumnsPerLine, 1);
133 if(bufsize > hed->ColumnsPerLine && (bufsize % hed->ColumnsPerLine) > 0)
134 {
135 hed->nLines++;
136 }
137
138 if(hed->LineHeight > 0)
139 {
140 hed->nVisibleLinesComplete = cvislines = rcClient.bottom / hed->LineHeight;
141 hed->nVisibleLines = hed->nVisibleLinesComplete;
142 if(rcClient.bottom % hed->LineHeight)
143 {
144 hed->nVisibleLines++;
145 }
146 }
147 else
148 {
149 hed->nVisibleLines = cvislines = 0;
150 }
151
152 SbVisible = bufsize > 0 && cvislines < hed->nLines;
153 ShowScrollBar(hed->hWndSelf, SB_VERT, SbVisible);
154
155 /* update scrollbar */
156 si.cbSize = sizeof(SCROLLINFO);
157 si.fMask = SIF_RANGE | SIF_PAGE;
158 si.nMin = 0;
159 si.nMax = ((bufsize > 0) ? hed->nLines - 1 : 0);
160 si.nPage = ((hed->LineHeight > 0) ? rcClient.bottom / hed->LineHeight : 0);
161 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
162
163 if(IsWindowVisible(hed->hWndSelf) && SbVisible != hed->SbVisible)
164 {
165 InvalidateRect(hed->hWndSelf, NULL, TRUE);
166 }
167
168 hed->SbVisible = SbVisible;
169 }
170
171 static HFONT
172 HEXEDIT_GetFixedFont(VOID)
173 {
174 LOGFONT lf;
175 GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT), &lf);
176 return CreateFontIndirect(&lf);
177 }
178
179 static VOID
180 HEXEDIT_PaintLines(PHEXEDIT_DATA hed, HDC hDC, DWORD ScrollPos, DWORD First, DWORD Last, RECT *rc)
181 {
182 DWORD dx, dy, linestart;
183 INT x;
184 PBYTE buf, current, end, line;
185 size_t bufsize;
186 TCHAR hex[3], addr[17];
187 RECT rct;
188
189 FillRect(hDC, rc, (HBRUSH)(COLOR_WINDOW + 1));
190
191 if(hed->hBuffer)
192 {
193 bufsize = LocalSize(hed->hBuffer);
194 buf = LocalLock(hed->hBuffer);
195 }
196 else
197 {
198 buf = NULL;
199 bufsize = 0;
200
201 if(ScrollPos + First == 0)
202 {
203 /* draw address */
204 _stprintf(addr, _T("%04X"), 0);
205 TextOut(hDC, hed->LeftMargin, First * hed->LineHeight, addr, 4);
206 }
207 }
208
209 if(buf)
210 {
211 end = buf + bufsize;
212 dy = First * hed->LineHeight;
213 linestart = (ScrollPos + First) * hed->ColumnsPerLine;
214 current = buf + linestart;
215 Last = min(hed->nLines - ScrollPos, Last);
216
217 while(First <= Last && current < end)
218 {
219 DWORD dh;
220
221 dx = hed->LeftMargin;
222
223 /* draw address */
224 _stprintf(addr, _T("%04lX"), linestart);
225 TextOut(hDC, dx, dy, addr, 4);
226
227 dx += ((4 + hed->AddressSpacing) * hed->CharWidth);
228 dh = (3 * hed->CharWidth);
229
230 rct.left = dx;
231 rct.top = dy;
232 rct.right = rct.left + dh;
233 rct.bottom = dy + hed->LineHeight;
234
235 /* draw hex map */
236 dx += (hed->CharWidth / 2);
237 line = current;
238 for(x = 0; x < hed->ColumnsPerLine && current < end; x++)
239 {
240 rct.left += dh;
241 rct.right += dh;
242
243 _stprintf(hex, _T("%02X"), *(current++));
244 ExtTextOut(hDC, dx, dy, ETO_OPAQUE, &rct, hex, 2, NULL);
245 dx += dh;
246 }
247
248 /* draw ascii map */
249 dx = ((4 + hed->AddressSpacing + hed->SplitSpacing + (hed->ColumnsPerLine * 3)) * hed->CharWidth);
250 current = line;
251 for(x = 0; x < hed->ColumnsPerLine && current < end; x++)
252 {
253 _stprintf(hex, _T("%C"), *(current++));
254 hex[0] = ((hex[0] & _T('\x007f')) >= _T(' ') ? hex[0] : _T('.'));
255 TextOut(hDC, dx, dy, hex, 1);
256 dx += hed->CharWidth;
257 }
258
259 dy += hed->LineHeight;
260 linestart += hed->ColumnsPerLine;
261 First++;
262 }
263 }
264
265 LocalUnlock(hed->hBuffer);
266 }
267
268 static DWORD
269 HEXEDIT_HitRegionTest(PHEXEDIT_DATA hed, POINTS pt)
270 {
271 int d;
272
273 if(pt.x <= hed->LeftMargin)
274 {
275 return HEHT_LEFTMARGIN;
276 }
277
278 pt.x -= hed->LeftMargin;
279 d = (4 * hed->CharWidth);
280 if(pt.x <= d)
281 {
282 return HEHT_ADDRESS;
283 }
284
285 pt.x -= d;
286 d = (hed->AddressSpacing * hed->CharWidth);
287 if(pt.x <= d)
288 {
289 return HEHT_ADDRESSSPACING;
290 }
291
292 pt.x -= d;
293 d = (3 * hed->ColumnsPerLine * hed->CharWidth);
294 if(pt.x <= d)
295 {
296 return HEHT_HEXDUMP;
297 }
298
299 pt.x -= d;
300 d = (hed->SplitSpacing * hed->CharWidth);
301 if(pt.x <= d)
302 {
303 return HEHT_HEXDUMPSPACING;
304 }
305
306 pt.x -= d;
307 d = (hed->ColumnsPerLine * hed->CharWidth);
308 if(pt.x <= d)
309 {
310 return HEHT_ASCIIDUMP;
311 }
312
313 return HEHT_RIGHTMARGIN;
314 }
315
316 static DWORD
317 HEXEDIT_PositionFromPoint(PHEXEDIT_DATA hed, POINTS pt, DWORD Hit, POINT *EditPos, BOOL *EditField)
318 {
319 SCROLLINFO si;
320 DWORD Pos, bufsize;
321
322 si.cbSize = sizeof(SCROLLINFO);
323 si.fMask = SIF_POS;
324 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
325
326 EditPos->x = 0;
327
328 if(hed->LineHeight > 0)
329 {
330 EditPos->y = min(si.nPos + (pt.y / hed->LineHeight), hed->nLines - 1);
331 }
332 else
333 {
334 EditPos->y = si.nPos;
335 }
336
337 switch(Hit)
338 {
339 case HEHT_LEFTMARGIN:
340 case HEHT_ADDRESS:
341 case HEHT_ADDRESSSPACING:
342 case HEHT_HEXDUMP:
343 pt.x -= (SHORT) hed->LeftMargin + ((4 + hed->AddressSpacing) * hed->CharWidth);
344 *EditField = TRUE;
345 break;
346
347 default:
348 pt.x -= hed->LeftMargin + ((4 + hed->AddressSpacing + hed->SplitSpacing + (3 * hed->ColumnsPerLine)) * hed->CharWidth);
349 *EditField = FALSE;
350 break;
351 }
352
353 if(pt.x > 0)
354 {
355 INT BlockWidth = (*EditField ? hed->CharWidth * 3 : hed->CharWidth);
356 EditPos->x = min(hed->ColumnsPerLine, pt.x / BlockWidth);
357 }
358
359 bufsize = (hed->hBuffer ? (DWORD) LocalSize(hed->hBuffer) : 0);
360 Pos = (EditPos->y * hed->ColumnsPerLine) + EditPos->x;
361 if(Pos > bufsize)
362 {
363 INT tmp = bufsize % hed->ColumnsPerLine;
364 Pos = bufsize;
365 EditPos->x = (tmp == 0 ? hed->ColumnsPerLine : tmp);
366 }
367 return Pos;
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 size_t 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 return 0;
476 }
477
478 /*** Message Proc *************************************************************/
479
480 static LRESULT
481 HEXEDIT_WM_NCCREATE(HWND hWnd, CREATESTRUCT *cs)
482 {
483 PHEXEDIT_DATA hed;
484
485 if(!(hed = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HEXEDIT_DATA))))
486 {
487 return FALSE;
488 }
489
490 hed->hWndSelf = hWnd;
491 hed->hWndParent = cs->hwndParent;
492 hed->style = cs->style;
493
494 hed->ColumnsPerLine = 8;
495 hed->LeftMargin = 2;
496 hed->AddressSpacing = 2;
497 hed->SplitSpacing = 2;
498 hed->EditingField = TRUE; /* in hexdump field */
499
500 SetWindowLongPtr(hWnd, 0, (DWORD_PTR)hed);
501 HEXEDIT_Update(hed);
502
503 return TRUE;
504 }
505
506 static LRESULT
507 HEXEDIT_WM_NCDESTROY(PHEXEDIT_DATA hed)
508 {
509 if(hed->hBuffer)
510 {
511 //while(LocalUnlock(hed->hBuffer));
512 LocalFree(hed->hBuffer);
513 }
514
515 if(hed->hFont)
516 {
517 DeleteObject(hed->hFont);
518 }
519
520 SetWindowLongPtr(hed->hWndSelf, 0, (DWORD_PTR)0);
521 HeapFree(GetProcessHeap(), 0, hed);
522
523 return 0;
524 }
525
526 static LRESULT
527 HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed)
528 {
529 UNREFERENCED_PARAMETER(hed);
530 return 1;
531 }
532
533 static LRESULT
534 HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed)
535 {
536 CreateCaret(hed->hWndSelf, 0, 1, hed->LineHeight);
537 HEXEDIT_MoveCaret(hed, FALSE);
538 ShowCaret(hed->hWndSelf);
539 return 0;
540 }
541
542 static LRESULT
543 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed)
544 {
545 UNREFERENCED_PARAMETER(hed);
546 DestroyCaret();
547 return 0;
548 }
549
550 static LRESULT
551 HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed, WORD ThumbPosition, WORD SbCmd)
552 {
553 int ScrollY;
554 SCROLLINFO si;
555
556 UNREFERENCED_PARAMETER(ThumbPosition);
557
558 ZeroMemory(&si, sizeof(SCROLLINFO));
559 si.cbSize = sizeof(SCROLLINFO);
560 si.fMask = SIF_ALL;
561 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
562
563 ScrollY = si.nPos;
564 switch(SbCmd)
565 {
566 case SB_TOP:
567 si.nPos = si.nMin;
568 break;
569
570 case SB_BOTTOM:
571 si.nPos = si.nMax;
572 break;
573
574 case SB_LINEUP:
575 si.nPos--;
576 break;
577
578 case SB_LINEDOWN:
579 si.nPos++;
580 break;
581
582 case SB_PAGEUP:
583 si.nPos -= si.nPage;
584 break;
585
586 case SB_PAGEDOWN:
587 si.nPos += si.nPage;
588 break;
589
590 case SB_THUMBTRACK:
591 si.nPos = si.nTrackPos;
592 break;
593 }
594
595 si.fMask = SIF_POS;
596 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
597 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
598
599 if(si.nPos != ScrollY)
600 {
601 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
602 UpdateWindow(hed->hWndSelf);
603 }
604
605 return 0;
606 }
607
608 static LRESULT
609 HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed, HFONT hFont, BOOL bRedraw)
610 {
611 HDC hDC;
612 TEXTMETRIC tm;
613 HFONT hOldFont = 0;
614
615 if(hFont == 0)
616 {
617 hFont = HEXEDIT_GetFixedFont();
618 }
619
620 hed->hFont = hFont;
621 hDC = GetDC(hed->hWndSelf);
622 if(hFont)
623 {
624 hOldFont = SelectObject(hDC, hFont);
625 }
626 GetTextMetrics(hDC, &tm);
627 hed->LineHeight = tm.tmHeight;
628 hed->CharWidth = tm.tmAveCharWidth;
629 if(hOldFont)
630 {
631 SelectObject(hDC, hOldFont);
632 }
633 ReleaseDC(hed->hWndSelf, hDC);
634
635 if(bRedraw)
636 {
637 InvalidateRect(hed->hWndSelf, NULL, TRUE);
638 }
639
640 return 0;
641 }
642
643 static LRESULT
644 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed)
645 {
646 return (LRESULT)hed->hFont;
647 }
648
649 static LRESULT
650 HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed)
651 {
652 PAINTSTRUCT ps;
653 SCROLLINFO si;
654 RECT rc;
655 HBITMAP hbmp, hbmpold;
656 INT nLines, nFirst;
657 HFONT hOldFont;
658 HDC hTempDC;
659 DWORD height;
660
661 if(GetUpdateRect(hed->hWndSelf, &rc, FALSE) && (hed->LineHeight > 0))
662 {
663 ZeroMemory(&si, sizeof(SCROLLINFO));
664 si.cbSize = sizeof(SCROLLINFO);
665 si.fMask = SIF_POS;
666 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
667
668 height = (rc.bottom - rc.top);
669 nLines = height / hed->LineHeight;
670 if((height % hed->LineHeight) > 0)
671 {
672 nLines++;
673 }
674 if(nLines > hed->nLines - si.nPos)
675 {
676 nLines = hed->nLines - si.nPos;
677 }
678 nFirst = rc.top / hed->LineHeight;
679
680 BeginPaint(hed->hWndSelf, &ps);
681 if(!(hTempDC = CreateCompatibleDC(ps.hdc)))
682 {
683 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
684 goto epaint;
685 }
686 if(!(hbmp = CreateCompatibleBitmap(hTempDC, ps.rcPaint.right, ps.rcPaint.bottom)))
687 {
688 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
689 DeleteDC(hTempDC);
690 goto epaint;
691 }
692 hbmpold = SelectObject(hTempDC, hbmp);
693 hOldFont = SelectObject(hTempDC, hed->hFont);
694 HEXEDIT_PaintLines(hed, hTempDC, si.nPos, nFirst, nFirst + nLines, &ps.rcPaint);
695 BitBlt(ps.hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hTempDC, rc.left, rc.top, SRCCOPY);
696 SelectObject(hTempDC, hOldFont);
697 SelectObject(hTempDC, hbmpold);
698
699 DeleteObject(hbmp);
700 DeleteDC(hTempDC);
701
702 epaint:
703 EndPaint(hed->hWndSelf, &ps);
704 }
705
706 return 0;
707 }
708
709 static LRESULT
710 HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed, int cyMoveLines, WORD ButtonsDown, LPPOINTS MousePos)
711 {
712 SCROLLINFO si;
713 int ScrollY;
714
715 UNREFERENCED_PARAMETER(ButtonsDown);
716 UNREFERENCED_PARAMETER(MousePos);
717
718 SetFocus(hed->hWndSelf);
719
720 si.cbSize = sizeof(SCROLLINFO);
721 si.fMask = SIF_ALL;
722 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
723
724 ScrollY = si.nPos;
725
726 si.fMask = SIF_POS;
727 si.nPos += cyMoveLines;
728 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
729
730 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
731 if(si.nPos != ScrollY)
732 {
733 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
734 UpdateWindow(hed->hWndSelf);
735 }
736
737 return 0;
738 }
739
740 static LRESULT
741 HEXEDIT_WM_GETDLGCODE(LPMSG Msg)
742 {
743 UNREFERENCED_PARAMETER(Msg);
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 UNREFERENCED_PARAMETER(Buttons);
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 size_t 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 = (INT) bufsize;
840 hed->CaretLine = (hed->nLines > 0 ? hed->nLines - 1 : 0);
841 hed->CaretCol = (INT) bufsize % hed->ColumnsPerLine;
842 }
843 }
844 else
845 {
846 INT tmp = (INT) bufsize % hed->ColumnsPerLine;
847 hed->Position = (INT) 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 UNREFERENCED_PARAMETER(sType);
862 UNREFERENCED_PARAMETER(NewHeight);
863 UNREFERENCED_PARAMETER(NewWidth);
864 HEXEDIT_Update(hed);
865 return 0;
866 }
867
868 INT_PTR CALLBACK
869 HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
870 {
871 PHEXEDIT_DATA hed;
872 POINTS p;
873
874 hed = (PHEXEDIT_DATA)(LONG_PTR)GetWindowLongPtr(hWnd, (DWORD_PTR)0);
875 switch(uMsg)
876 {
877 case WM_ERASEBKGND:
878 return TRUE;
879
880 case WM_PAINT:
881 return HEXEDIT_WM_PAINT(hed);
882
883 case WM_KEYDOWN:
884 return HEXEDIT_WM_KEYDOWN(hed, (INT)wParam);
885
886 case WM_VSCROLL:
887 return HEXEDIT_WM_VSCROLL(hed, HIWORD(wParam), LOWORD(wParam));
888
889 case WM_SIZE:
890 return HEXEDIT_WM_SIZE(hed, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
891
892 case WM_LBUTTONDOWN:
893 {
894 p.x = LOWORD(lParam);
895 p.y = HIWORD(lParam);
896 return HEXEDIT_WM_LBUTTONDOWN(hed, (INT)wParam, p);
897 }
898
899 case WM_MOUSEWHEEL:
900 {
901 UINT nScrollLines = 3;
902 int delta = 0;
903
904 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
905 delta -= (SHORT)HIWORD(wParam);
906 if(abs(delta) >= WHEEL_DELTA && nScrollLines != 0)
907 {
908 p.x = LOWORD(lParam);
909 p.y = HIWORD(lParam);
910 return HEXEDIT_WM_MOUSEWHEEL(hed, nScrollLines * (delta / WHEEL_DELTA), LOWORD(wParam), &p);
911 }
912 break;
913 }
914
915 case HEM_LOADBUFFER:
916 return HEXEDIT_HEM_LOADBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
917
918 case HEM_COPYBUFFER:
919 return HEXEDIT_HEM_COPYBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
920
921 case HEM_SETMAXBUFFERSIZE:
922 return HEXEDIT_HEM_SETMAXBUFFERSIZE(hed, (DWORD)lParam);
923
924 case WM_SETFOCUS:
925 return HEXEDIT_WM_SETFOCUS(hed);
926
927 case WM_KILLFOCUS:
928 return HEXEDIT_WM_KILLFOCUS(hed);
929
930 case WM_GETDLGCODE:
931 return HEXEDIT_WM_GETDLGCODE((LPMSG)lParam);
932
933 case WM_SETFONT:
934 return HEXEDIT_WM_SETFONT(hed, (HFONT)wParam, (BOOL)LOWORD(lParam));
935
936 case WM_GETFONT:
937 return HEXEDIT_WM_GETFONT(hed);
938
939 case WM_CREATE:
940 return HEXEDIT_WM_CREATE(hed);
941
942 case WM_NCCREATE:
943 if(!hed)
944 {
945 return HEXEDIT_WM_NCCREATE(hWnd, (CREATESTRUCT*)lParam);
946 }
947 break;
948
949 case WM_NCDESTROY:
950 if(hed)
951 {
952 return HEXEDIT_WM_NCDESTROY(hed);
953 }
954 break;
955 }
956
957 return CallWindowProc(DefWindowProc, hWnd, uMsg, wParam, lParam);
958 }
959