- Get autochk, calc, cmd, devmgr, expand, format, gettype, hostname, lsass, msconfig...
[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 #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 STDCALL
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 STDCALL
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 = GetWindowLong(hed->hWndSelf, GWL_STYLE);
130
131 bufsize = (hed->hBuffer ? 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 UINT 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 -= 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 ? 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 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 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 return 1;
530 }
531
532 static LRESULT
533 HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed)
534 {
535 CreateCaret(hed->hWndSelf, 0, 1, hed->LineHeight);
536 HEXEDIT_MoveCaret(hed, FALSE);
537 ShowCaret(hed->hWndSelf);
538 return 0;
539 }
540
541 static LRESULT
542 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed)
543 {
544 DestroyCaret();
545 return 0;
546 }
547
548 static LRESULT
549 HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed, WORD ThumbPosition, WORD SbCmd)
550 {
551 int ScrollY;
552 SCROLLINFO si;
553
554 ZeroMemory(&si, sizeof(SCROLLINFO));
555 si.cbSize = sizeof(SCROLLINFO);
556 si.fMask = SIF_ALL;
557 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
558
559 ScrollY = si.nPos;
560 switch(SbCmd)
561 {
562 case SB_TOP:
563 si.nPos = si.nMin;
564 break;
565
566 case SB_BOTTOM:
567 si.nPos = si.nMax;
568 break;
569
570 case SB_LINEUP:
571 si.nPos--;
572 break;
573
574 case SB_LINEDOWN:
575 si.nPos++;
576 break;
577
578 case SB_PAGEUP:
579 si.nPos -= si.nPage;
580 break;
581
582 case SB_PAGEDOWN:
583 si.nPos += si.nPage;
584 break;
585
586 case SB_THUMBTRACK:
587 si.nPos = si.nTrackPos;
588 break;
589 }
590
591 si.fMask = SIF_POS;
592 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
593 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
594
595 if(si.nPos != ScrollY)
596 {
597 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
598 UpdateWindow(hed->hWndSelf);
599 }
600
601 return 0;
602 }
603
604 static LRESULT
605 HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed, HFONT hFont, BOOL bRedraw)
606 {
607 HDC hDC;
608 TEXTMETRIC tm;
609 HFONT hOldFont = 0;
610
611 if(hFont == 0)
612 {
613 hFont = HEXEDIT_GetFixedFont();
614 }
615
616 hed->hFont = hFont;
617 hDC = GetDC(hed->hWndSelf);
618 if(hFont)
619 {
620 hOldFont = SelectObject(hDC, hFont);
621 }
622 GetTextMetrics(hDC, &tm);
623 hed->LineHeight = tm.tmHeight;
624 hed->CharWidth = tm.tmAveCharWidth;
625 if(hOldFont)
626 {
627 SelectObject(hDC, hOldFont);
628 }
629 ReleaseDC(hed->hWndSelf, hDC);
630
631 if(bRedraw)
632 {
633 InvalidateRect(hed->hWndSelf, NULL, TRUE);
634 }
635
636 return 0;
637 }
638
639 static LRESULT
640 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed)
641 {
642 return (LRESULT)hed->hFont;
643 }
644
645 static LRESULT
646 HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed)
647 {
648 PAINTSTRUCT ps;
649 SCROLLINFO si;
650 RECT rc;
651 HBITMAP hbmp, hbmpold;
652 INT nLines, nFirst;
653 HFONT hOldFont;
654 HDC hTempDC;
655 DWORD height;
656
657 if(GetUpdateRect(hed->hWndSelf, &rc, FALSE) && (hed->LineHeight > 0))
658 {
659 ZeroMemory(&si, sizeof(SCROLLINFO));
660 si.cbSize = sizeof(SCROLLINFO);
661 si.fMask = SIF_POS;
662 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
663
664 height = (rc.bottom - rc.top);
665 nLines = height / hed->LineHeight;
666 if((height % hed->LineHeight) > 0)
667 {
668 nLines++;
669 }
670 if(nLines > hed->nLines - si.nPos)
671 {
672 nLines = hed->nLines - si.nPos;
673 }
674 nFirst = rc.top / hed->LineHeight;
675
676 BeginPaint(hed->hWndSelf, &ps);
677 if(!(hTempDC = CreateCompatibleDC(ps.hdc)))
678 {
679 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
680 goto epaint;
681 }
682 if(!(hbmp = CreateCompatibleBitmap(hTempDC, ps.rcPaint.right, ps.rcPaint.bottom)))
683 {
684 FillRect(ps.hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1));
685 DeleteDC(hTempDC);
686 goto epaint;
687 }
688 hbmpold = SelectObject(hTempDC, hbmp);
689 hOldFont = SelectObject(hTempDC, hed->hFont);
690 HEXEDIT_PaintLines(hed, hTempDC, si.nPos, nFirst, nFirst + nLines, &ps.rcPaint);
691 BitBlt(ps.hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hTempDC, rc.left, rc.top, SRCCOPY);
692 SelectObject(hTempDC, hOldFont);
693 SelectObject(hTempDC, hbmpold);
694
695 DeleteObject(hbmp);
696 DeleteDC(hTempDC);
697
698 epaint:
699 EndPaint(hed->hWndSelf, &ps);
700 }
701
702 return 0;
703 }
704
705 static LRESULT
706 HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed, int cyMoveLines, WORD ButtonsDown, LPPOINTS MousePos)
707 {
708 SCROLLINFO si;
709 int ScrollY;
710
711 SetFocus(hed->hWndSelf);
712
713 si.cbSize = sizeof(SCROLLINFO);
714 si.fMask = SIF_ALL;
715 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
716
717 ScrollY = si.nPos;
718
719 si.fMask = SIF_POS;
720 si.nPos += cyMoveLines;
721 SetScrollInfo(hed->hWndSelf, SB_VERT, &si, TRUE);
722
723 GetScrollInfo(hed->hWndSelf, SB_VERT, &si);
724 if(si.nPos != ScrollY)
725 {
726 ScrollWindow(hed->hWndSelf, 0, (ScrollY - si.nPos) * hed->LineHeight, NULL, NULL);
727 UpdateWindow(hed->hWndSelf);
728 }
729
730 return 0;
731 }
732
733 static LRESULT
734 HEXEDIT_WM_GETDLGCODE(LPMSG Msg)
735 {
736 return DLGC_WANTARROWS | DLGC_WANTCHARS;
737 }
738
739 static LRESULT
740 HEXEDIT_WM_LBUTTONDOWN(PHEXEDIT_DATA hed, INT Buttons, POINTS Pt)
741 {
742 BOOL NewField;
743 POINT EditPos;
744 DWORD Hit = HEXEDIT_HitRegionTest(hed, Pt);
745
746 SetFocus(hed->hWndSelf);
747
748 hed->Position = HEXEDIT_PositionFromPoint(hed, Pt, Hit, &EditPos, &NewField);
749 hed->EditingField = NewField;
750 hed->CaretCol = EditPos.x;
751 hed->CaretLine = EditPos.y;
752
753 HEXEDIT_MoveCaret(hed, TRUE);
754
755 return 0;
756 }
757
758 static BOOL
759 HEXEDIT_WM_KEYDOWN(PHEXEDIT_DATA hed, INT VkCode)
760 {
761 DWORD bufsize;
762 BOOL shift, control;
763
764 if(GetKeyState(VK_MENU) & 0x8000)
765 {
766 return FALSE;
767 }
768
769 shift = GetKeyState(VK_SHIFT) & 0x8000;
770 control = GetKeyState(VK_CONTROL) & 0x8000;
771
772 bufsize = (hed->hBuffer ? LocalSize(hed->hBuffer) : 0);
773
774 switch(VkCode)
775 {
776 case VK_LEFT:
777 if(hed->Position > 0)
778 {
779 if(--hed->CaretCol < 0)
780 {
781 hed->CaretLine--;
782 hed->CaretCol = hed->ColumnsPerLine;
783 }
784 else
785 hed->Position--;
786 }
787 HEXEDIT_MoveCaret(hed, TRUE);
788 break;
789
790 case VK_RIGHT:
791 if(hed->Position < (INT)bufsize)
792 {
793 if(++hed->CaretCol > hed->ColumnsPerLine)
794 {
795 hed->CaretCol = 0;
796 hed->CaretLine++;
797 }
798 else
799 hed->Position++;
800 }
801 HEXEDIT_MoveCaret(hed, TRUE);
802 break;
803
804 case VK_UP:
805 if(hed->Position > 0)
806 {
807 if(hed->CaretLine <= 0)
808 {
809 hed->CaretCol = 0;
810 hed->Position = 0;
811 }
812 else
813 {
814 hed->CaretLine--;
815 hed->Position -= hed->ColumnsPerLine;
816 }
817 }
818 HEXEDIT_MoveCaret(hed, TRUE);
819 break;
820
821 case VK_DOWN:
822 if(hed->Position <= (INT)bufsize)
823 {
824 if(hed->CaretLine < hed->nLines - 1)
825 {
826 hed->Position += hed->ColumnsPerLine;
827 hed->CaretLine++;
828 if(hed->Position > (INT)bufsize)
829 {
830 hed->Position = bufsize;
831 hed->CaretLine = (hed->nLines > 0 ? hed->nLines - 1 : 0);
832 hed->CaretCol = bufsize % hed->ColumnsPerLine;
833 }
834 }
835 else
836 {
837 INT tmp = bufsize % hed->ColumnsPerLine;
838 hed->Position = bufsize;
839 hed->CaretCol = (tmp == 0 ? hed->ColumnsPerLine : tmp);
840 }
841 }
842 HEXEDIT_MoveCaret(hed, TRUE);
843 break;
844 }
845
846 return FALSE;
847 }
848
849 static LRESULT
850 HEXEDIT_WM_SIZE(PHEXEDIT_DATA hed, DWORD sType, WORD NewWidth, WORD NewHeight)
851 {
852 HEXEDIT_Update(hed);
853 return 0;
854 }
855
856 INT_PTR CALLBACK
857 HexEditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
858 {
859 PHEXEDIT_DATA hed;
860
861 hed = (PHEXEDIT_DATA)(LONG_PTR)GetWindowLongPtr(hWnd, (DWORD_PTR)0);
862 switch(uMsg)
863 {
864 case WM_ERASEBKGND:
865 return TRUE;
866
867 case WM_PAINT:
868 return HEXEDIT_WM_PAINT(hed);
869
870 case WM_KEYDOWN:
871 return HEXEDIT_WM_KEYDOWN(hed, (INT)wParam);
872
873 case WM_VSCROLL:
874 return HEXEDIT_WM_VSCROLL(hed, HIWORD(wParam), LOWORD(wParam));
875
876 case WM_SIZE:
877 return HEXEDIT_WM_SIZE(hed, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
878
879 case WM_LBUTTONDOWN:
880 return HEXEDIT_WM_LBUTTONDOWN(hed, (INT)wParam, MAKEPOINTS(lParam));
881
882 case WM_MOUSEWHEEL:
883 {
884 UINT nScrollLines = 3;
885 int delta = 0;
886
887 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
888 delta -= (SHORT)HIWORD(wParam);
889 if(abs(delta) >= WHEEL_DELTA && nScrollLines != 0)
890 {
891 return HEXEDIT_WM_MOUSEWHEEL(hed, nScrollLines * (delta / WHEEL_DELTA), LOWORD(wParam), &MAKEPOINTS(lParam));
892 }
893 break;
894 }
895
896 case HEM_LOADBUFFER:
897 return HEXEDIT_HEM_LOADBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
898
899 case HEM_COPYBUFFER:
900 return HEXEDIT_HEM_COPYBUFFER(hed, (PVOID)wParam, (DWORD)lParam);
901
902 case HEM_SETMAXBUFFERSIZE:
903 return HEXEDIT_HEM_SETMAXBUFFERSIZE(hed, (DWORD)lParam);
904
905 case WM_SETFOCUS:
906 return HEXEDIT_WM_SETFOCUS(hed);
907
908 case WM_KILLFOCUS:
909 return HEXEDIT_WM_KILLFOCUS(hed);
910
911 case WM_GETDLGCODE:
912 return HEXEDIT_WM_GETDLGCODE((LPMSG)lParam);
913
914 case WM_SETFONT:
915 return HEXEDIT_WM_SETFONT(hed, (HFONT)wParam, (BOOL)LOWORD(lParam));
916
917 case WM_GETFONT:
918 return HEXEDIT_WM_GETFONT(hed);
919
920 case WM_CREATE:
921 return HEXEDIT_WM_CREATE(hed);
922
923 case WM_NCCREATE:
924 if(!hed)
925 {
926 return HEXEDIT_WM_NCCREATE(hWnd, (CREATESTRUCT*)lParam);
927 }
928 break;
929
930 case WM_NCDESTROY:
931 if(hed)
932 {
933 return HEXEDIT_WM_NCDESTROY(hed);
934 }
935 break;
936 }
937
938 return CallWindowProc(DefWindowProc, hWnd, uMsg, wParam, lParam);
939 }
940