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