4 * Copyright (C) 2004 Thomas Weidenmueller <w3seek@reactos.com>
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.
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.
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
21 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
50 } HEXEDIT_DATA
, *PHEXEDIT_DATA
;
53 #define HEHT_LEFTMARGIN (0x1)
54 #define HEHT_ADDRESS (0x2)
55 #define HEHT_ADDRESSSPACING (0x3)
56 #define HEHT_HEXDUMP (0x4)
57 #define HEHT_HEXDUMPSPACING (0x5)
58 #define HEHT_ASCIIDUMP (0x6)
59 #define HEHT_RIGHTMARGIN (0x7)
61 LRESULT WINAPI
HexEditWndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
65 RegisterHexEditorClass(HINSTANCE hInstance
)
69 ZeroMemory(&WndClass
, sizeof(WNDCLASSEX
));
70 WndClass
.cbSize
= sizeof(WNDCLASSEX
);
71 WndClass
.style
= CS_DBLCLKS
;
72 WndClass
.lpfnWndProc
= (WNDPROC
)HexEditWndProc
;
73 WndClass
.cbWndExtra
= sizeof(PHEXEDIT_DATA
);
74 WndClass
.hInstance
= hInstance
;
75 WndClass
.hCursor
= LoadCursor(0, IDC_IBEAM
);
76 WndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
77 WndClass
.lpszClassName
= HEX_EDIT_CLASS_NAME
;
79 return RegisterClassEx(&WndClass
);
84 UnregisterHexEditorClass(HINSTANCE hInstance
)
86 return UnregisterClass(HEX_EDIT_CLASS_NAME
, hInstance
);
89 /*** Helper functions *********************************************************/
92 HEXEDIT_MoveCaret(PHEXEDIT_DATA hed
, INT Line
, INT Column
, BOOL HexDump
)
96 si
.cbSize
= sizeof(SCROLLINFO
);
98 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
103 SetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
, TRUE
);
104 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
105 InvalidateRect(hed
->hWndSelf
, NULL
, TRUE
);
107 else if((Line
- si
.nPos
) > hed
->nVisibleLines
)
109 si
.nPos
+= (Line
- si
.nPos
);
110 SetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
, TRUE
);
111 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
112 InvalidateRect(hed
->hWndSelf
, NULL
, TRUE
);
116 SetCaretPos(hed
->LeftMargin
+ ((4 + hed
->AddressSpacing
) * hed
->CharWidth
) - 2, (Line
- si
.nPos
) * hed
->LineHeight
);
118 SetCaretPos(hed
->LeftMargin
+ ((4 + hed
->AddressSpacing
+ hed
->SplitSpacing
+ (3 * hed
->ColumnsPerLine
)) * hed
->CharWidth
) - 2, (Line
- si
.nPos
) * hed
->LineHeight
);
122 HEXEDIT_Update(PHEXEDIT_DATA hed
)
127 GetClientRect(hed
->hWndSelf
, &rcClient
);
128 hed
->style
= GetWindowLong(hed
->hWndSelf
, GWL_STYLE
);
130 hed
->nLines
= max((hed
->hBuffer
? LocalSize(hed
->hBuffer
) / hed
->ColumnsPerLine
: 1), 1);
132 if(hed
->LineHeight
> 0)
134 hed
->nVisibleLines
= rcClient
.bottom
/ hed
->LineHeight
;
135 if(rcClient
.bottom
% hed
->LineHeight
)
137 hed
->nVisibleLines
++;
141 hed
->nVisibleLines
= 0;
143 /* update scrollbar */
144 si
.cbSize
= sizeof(SCROLLINFO
);
145 si
.fMask
= SIF_RANGE
| SIF_PAGE
;
147 si
.nMax
= hed
->nLines
;
148 if(hed
->LineHeight
> 0)
149 si
.nPage
= rcClient
.bottom
/ hed
->LineHeight
;
152 SetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
, TRUE
);
154 if(hed
->style
& WS_VISIBLE
)
156 InvalidateRect(hed
->hWndSelf
, NULL
, TRUE
);
161 HEXEDIT_GetFixedFont(VOID
)
164 GetObject(GetStockObject(ANSI_FIXED_FONT
), sizeof(LOGFONT
), &lf
);
165 return CreateFontIndirect(&lf
);
169 HEXEDIT_PaintLines(PHEXEDIT_DATA hed
, HDC hDC
, DWORD ScrollPos
, DWORD First
, DWORD Last
, RECT
*rc
)
171 DWORD x
, dx
, dy
, linestart
;
172 PBYTE buf
, current
, end
, line
;
174 TCHAR hex
[3], addr
[17];
179 bufsize
= LocalSize(hed
->hBuffer
);
180 buf
= LocalLock(hed
->hBuffer
);
188 FillRect(hDC
, rc
, (HBRUSH
)(COLOR_WINDOW
+ 1));
192 dy
= First
* hed
->LineHeight
;
193 linestart
= (ScrollPos
+ First
) * hed
->ColumnsPerLine
;
194 current
= buf
+ linestart
;
195 Last
= min(hed
->nLines
- ScrollPos
, Last
);
197 while(First
<= Last
&& current
< end
)
201 dx
= hed
->LeftMargin
;
204 _stprintf(addr
, _T("%04X"), linestart
);
205 TextOut(hDC
, dx
, dy
, addr
, 4);
207 dx
+= ((4 + hed
->AddressSpacing
) * hed
->CharWidth
);
208 dh
= (3 * hed
->CharWidth
);
212 rct
.right
= rct
.left
+ dh
;
213 rct
.bottom
= dy
+ hed
->LineHeight
;
216 dx
+= (hed
->CharWidth
/ 2);
218 for(x
= 0; x
< hed
->ColumnsPerLine
&& current
< end
; x
++)
223 _stprintf(hex
, _T("%02X"), *(current
++));
224 ExtTextOut(hDC
, dx
, dy
, ETO_OPAQUE
, &rct
, hex
, 2, NULL
);
229 dx
= ((4 + hed
->AddressSpacing
+ hed
->SplitSpacing
+ (hed
->ColumnsPerLine
* 3)) * hed
->CharWidth
);
231 for(x
= 0; x
< hed
->ColumnsPerLine
&& current
< end
; x
++)
233 _stprintf(hex
, _T("%C"), *(current
++));
234 hex
[0] = ((hex
[0] & _T('\x007f')) >= _T(' ') ? hex
[0] : _T('.'));
235 TextOut(hDC
, dx
, dy
, hex
, 1);
236 dx
+= hed
->CharWidth
;
239 dy
+= hed
->LineHeight
;
240 linestart
+= hed
->ColumnsPerLine
;
245 LocalUnlock(hed
->hBuffer
);
249 HEXEDIT_HitRegionTest(PHEXEDIT_DATA hed
, POINTS pt
, POINTS
*ptClient
)
254 wi
.cbSize
= sizeof(WINDOWINFO
);
255 GetWindowInfo(hed
->hWndSelf
, &wi
);
257 x
= pt
.x
- wi
.rcClient
.left
;
261 ptClient
->y
= pt
.y
- wi
.rcClient
.top
;
264 if(x
<= hed
->LeftMargin
)
266 return HEHT_LEFTMARGIN
;
269 x
-= hed
->LeftMargin
;
270 d
= (4 * hed
->CharWidth
);
277 d
= (hed
->AddressSpacing
* hed
->CharWidth
);
280 return HEHT_ADDRESSSPACING
;
284 d
= (3 * hed
->ColumnsPerLine
* hed
->CharWidth
);
291 d
= (hed
->SplitSpacing
* hed
->CharWidth
);
294 return HEHT_HEXDUMPSPACING
;
298 d
= (hed
->ColumnsPerLine
* hed
->CharWidth
);
301 return HEHT_ASCIIDUMP
;
304 return HEHT_RIGHTMARGIN
;
308 HEXEDIT_PositionFromPoint(PHEXEDIT_DATA hed
, POINTS pt
, DWORD
*Hit
)
314 *Hit
= HEXEDIT_HitRegionTest(hed
, pt
, &ptClient
);
316 si
.cbSize
= sizeof(SCROLLINFO
);
318 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
320 if(hed
->LineHeight
> 0)
322 Line
= min(si
.nPos
+ (ptClient
.y
/ hed
->LineHeight
), hed
->nLines
);
329 case HEHT_LEFTMARGIN
:
331 case HEHT_ADDRESSSPACING
:
332 return Line
* hed
->ColumnsPerLine
;
340 case HEHT_RIGHTMARGIN
:
341 return (Line
+ 1) * hed
->ColumnsPerLine
;
345 /*** Control specific messages ************************************************/
348 HEXEDIT_HEM_LOADBUFFER(PHEXEDIT_DATA hed
, PVOID Buffer
, DWORD Size
)
350 if(Buffer
!= NULL
&& Size
> 0)
354 if(hed
->MaxBuffer
> 0 && Size
> hed
->MaxBuffer
)
356 Size
= hed
->MaxBuffer
;
363 if(LocalSize(hed
->hBuffer
) != Size
)
365 hed
->hBuffer
= LocalReAlloc(hed
->hBuffer
, Size
, LMEM_MOVEABLE
| LMEM_ZEROINIT
);
370 hed
->hBuffer
= LocalFree(hed
->hBuffer
);
379 hed
->hBuffer
= LocalAlloc(LHND
, Size
);
384 buf
= LocalLock(hed
->hBuffer
);
387 memcpy(buf
, Buffer
, Size
);
391 LocalUnlock(hed
->hBuffer
);
398 else if(hed
->hBuffer
)
401 hed
->hBuffer
= LocalFree(hed
->hBuffer
);
409 HEXEDIT_HEM_COPYBUFFER(PHEXEDIT_DATA hed
, PVOID Buffer
, DWORD Size
)
418 if(Buffer
!= NULL
&& Size
> 0)
420 nCpy
= min(Size
, LocalSize(hed
->hBuffer
));
425 buf
= LocalLock(hed
->hBuffer
);
428 memcpy(Buffer
, buf
, nCpy
);
432 LocalUnlock(hed
->hBuffer
);
437 return (LRESULT
)LocalSize(hed
->hBuffer
);
441 HEXEDIT_HEM_SETMAXBUFFERSIZE(PHEXEDIT_DATA hed
, DWORD nMaxSize
)
443 hed
->MaxBuffer
= nMaxSize
;
444 if(hed
->MaxBuffer
> 0 && hed
->hBuffer
&& LocalSize(hed
->hBuffer
) > hed
->MaxBuffer
)
446 /* truncate the buffer */
447 hed
->hBuffer
= LocalReAlloc(hed
->hBuffer
, hed
->MaxBuffer
, LMEM_MOVEABLE
);
452 /*** Message Proc *************************************************************/
455 HEXEDIT_WM_NCCREATE(HWND hWnd
, CREATESTRUCT
*cs
)
459 if(!(hed
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HEXEDIT_DATA
))))
464 hed
->hWndSelf
= hWnd
;
465 hed
->hWndParent
= cs
->hwndParent
;
466 hed
->style
= cs
->style
;
468 hed
->ColumnsPerLine
= 8;
470 hed
->AddressSpacing
= 2;
471 hed
->SplitSpacing
= 2;
472 hed
->EditingField
= TRUE
; /* in hexdump field */
474 SetWindowLong(hWnd
, 0, (LONG
)hed
);
480 HEXEDIT_WM_NCDESTROY(PHEXEDIT_DATA hed
)
484 while(LocalUnlock(hed
->hBuffer
));
485 LocalFree(hed
->hBuffer
);
488 SetWindowLong(hed
->hWndSelf
, 0, 0);
489 HeapFree(GetProcessHeap(), 0, hed
);
495 HEXEDIT_WM_CREATE(PHEXEDIT_DATA hed
)
501 HEXEDIT_WM_SETFOCUS(PHEXEDIT_DATA hed
)
503 CreateCaret(hed
->hWndSelf
, 0, 1, hed
->LineHeight
);
504 HEXEDIT_MoveCaret(hed
, hed
->CaretLine
, hed
->CaretCol
, hed
->EditingField
);
505 ShowCaret(hed
->hWndSelf
);
510 HEXEDIT_WM_KILLFOCUS(PHEXEDIT_DATA hed
)
517 HEXEDIT_WM_VSCROLL(PHEXEDIT_DATA hed
, WORD ThumbPosition
, WORD SbCmd
)
522 ZeroMemory(&si
, sizeof(SCROLLINFO
));
523 si
.cbSize
= sizeof(SCROLLINFO
);
525 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
555 si
.nPos
= si
.nTrackPos
;
560 SetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
, TRUE
);
561 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
563 if(si
.nPos
!= ScrollY
)
565 ScrollWindow(hed
->hWndSelf
, 0, (ScrollY
- si
.nPos
) * hed
->LineHeight
, NULL
, NULL
);
566 UpdateWindow(hed
->hWndSelf
);
573 HEXEDIT_WM_SETFONT(PHEXEDIT_DATA hed
, HFONT hFont
, BOOL bRedraw
)
581 hFont
= HEXEDIT_GetFixedFont();
585 hDC
= GetDC(hed
->hWndSelf
);
588 hOldFont
= SelectObject(hDC
, hFont
);
590 GetTextMetrics(hDC
, &tm
);
591 hed
->LineHeight
= tm
.tmHeight
;
592 hed
->CharWidth
= tm
.tmAveCharWidth
;
595 SelectObject(hDC
, hOldFont
);
597 ReleaseDC(hed
->hWndSelf
, hDC
);
601 InvalidateRect(hed
->hWndSelf
, NULL
, TRUE
);
608 HEXEDIT_WM_GETFONT(PHEXEDIT_DATA hed
)
610 return (LRESULT
)hed
->hFont
;
614 HEXEDIT_WM_PAINT(PHEXEDIT_DATA hed
)
619 HBITMAP hbmp
, hbmpold
;
620 DWORD nLines
, nFirst
;
625 if(GetUpdateRect(hed
->hWndSelf
, &rc
, FALSE
) && (hed
->LineHeight
> 0))
627 ZeroMemory(&si
, sizeof(SCROLLINFO
));
628 si
.cbSize
= sizeof(SCROLLINFO
);
630 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
632 height
= (rc
.bottom
- rc
.top
);
633 nLines
= height
/ hed
->LineHeight
;
634 if((height
% hed
->LineHeight
) > 0)
638 if(nLines
> hed
->nLines
- si
.nPos
)
640 nLines
= hed
->nLines
- si
.nPos
;
642 nFirst
= rc
.top
/ hed
->LineHeight
;
644 BeginPaint(hed
->hWndSelf
, &ps
);
645 if(!(hTempDC
= CreateCompatibleDC(ps
.hdc
)))
647 FillRect(ps
.hdc
, &rc
, (HBRUSH
)(COLOR_WINDOW
+ 1));
650 if(!(hbmp
= CreateCompatibleBitmap(hTempDC
, ps
.rcPaint
.right
, ps
.rcPaint
.bottom
)))
652 FillRect(ps
.hdc
, &rc
, (HBRUSH
)(COLOR_WINDOW
+ 1));
656 hbmpold
= SelectObject(hTempDC
, hbmp
);
657 hOldFont
= SelectObject(hTempDC
, hed
->hFont
);
658 HEXEDIT_PaintLines(hed
, hTempDC
, si
.nPos
, nFirst
, nFirst
+ nLines
, &ps
.rcPaint
);
659 BitBlt(ps
.hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, hTempDC
, rc
.left
, rc
.top
, SRCCOPY
);
660 SelectObject(hTempDC
, hOldFont
);
661 SelectObject(hTempDC
, hbmpold
);
667 EndPaint(hed
->hWndSelf
, &ps
);
674 HEXEDIT_WM_MOUSEWHEEL(PHEXEDIT_DATA hed
, int cyMoveLines
, WORD ButtonsDown
, LPPOINTS MousePos
)
679 SetFocus(hed
->hWndSelf
);
681 si
.cbSize
= sizeof(SCROLLINFO
);
683 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
688 si
.nPos
+= cyMoveLines
;
689 SetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
, TRUE
);
691 GetScrollInfo(hed
->hWndSelf
, SB_VERT
, &si
);
692 if(si
.nPos
!= ScrollY
)
694 ScrollWindow(hed
->hWndSelf
, 0, (ScrollY
- si
.nPos
) * hed
->LineHeight
, NULL
, NULL
);
695 UpdateWindow(hed
->hWndSelf
);
702 HEXEDIT_WM_SETCURSOR(PHEXEDIT_DATA hed
)
707 Pos
= GetMessagePos();
708 pt
= MAKEPOINTS(Pos
);
709 Hit
= HEXEDIT_HitRegionTest(hed
, pt
, NULL
);
714 case HEHT_HEXDUMPSPACING
:
716 SetCursor(LoadCursor(0, MAKEINTRESOURCE(IDC_IBEAM
)));
720 SetCursor(LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW
)));
727 HEXEDIT_WM_KEYDOWN(PHEXEDIT_DATA hed
, INT VkCode
)
730 BOOL shift
, control
, handled
;
732 if(GetKeyState(VK_MENU
) & 0x8000)
737 shift
= GetKeyState(VK_SHIFT
) & 0x8000;
738 control
= GetKeyState(VK_CONTROL
) & 0x8000;
740 bufsize
= (hed
->hBuffer
? LocalSize(hed
->hBuffer
) : 0);
745 case VK_LEFT
:MessageBox(0, L
"", L
"", 0);
746 if(hed
->Position
> 0)
748 if(--hed
->CaretCol
< 0)
751 hed
->CaretCol
= hed
->ColumnsPerLine
;
756 HEXEDIT_MoveCaret(hed
, hed
->CaretLine
, hed
->CaretCol
, hed
->EditingField
);
762 if(hed
->Position
< bufsize
)
764 if(++hed
->CaretCol
> hed
->ColumnsPerLine
)
772 HEXEDIT_MoveCaret(hed
, hed
->CaretLine
, hed
->CaretCol
, hed
->EditingField
);
783 HexEditWndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
787 hed
= (PHEXEDIT_DATA
)GetWindowLong(hWnd
, 0);
794 return HEXEDIT_WM_PAINT(hed
);
797 return HEXEDIT_WM_SETCURSOR(hed
);
800 return HEXEDIT_WM_KEYDOWN(hed
, (INT
)wParam
);
803 return HEXEDIT_WM_VSCROLL(hed
, HIWORD(wParam
), LOWORD(wParam
));
806 return HEXEDIT_WM_MOUSEWHEEL(hed
, ((SHORT
)(wParam
>> 16) < 0 ? 3 : -3), LOWORD(wParam
), &MAKEPOINTS(lParam
));
809 return HEXEDIT_HEM_LOADBUFFER(hed
, (PVOID
)wParam
, (DWORD
)lParam
);
812 return HEXEDIT_HEM_COPYBUFFER(hed
, (PVOID
)wParam
, (DWORD
)lParam
);
814 case HEM_SETMAXBUFFERSIZE
:
815 return HEXEDIT_HEM_SETMAXBUFFERSIZE(hed
, (DWORD
)lParam
);
818 return HEXEDIT_WM_SETFOCUS(hed
);
821 return HEXEDIT_WM_KILLFOCUS(hed
);
824 return HEXEDIT_WM_SETFONT(hed
, (HFONT
)wParam
, (BOOL
)LOWORD(lParam
));
827 return HEXEDIT_WM_GETFONT(hed
);
830 return HEXEDIT_WM_CREATE(hed
);
835 return HEXEDIT_WM_NCCREATE(hWnd
, (CREATESTRUCT
*)lParam
);
842 return HEXEDIT_WM_NCDESTROY(hed
);
847 return CallWindowProc(DefWindowProc
, hWnd
, uMsg
, wParam
, lParam
);