hexedit.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /*
  2. * Hex Edit control
  3. *
  4. * Copyright 2005 Robert Shearman
  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 St, Fifth Floor, Boston, MA 02110-1301, USA
  19. *
  20. * TODO:
  21. * - Selection support
  22. * - Cut, copy and paste
  23. * - Mouse support
  24. */
  25. #include <stdarg.h>
  26. #include <string.h>
  27. #include <assert.h>
  28. #include "windef.h"
  29. #include "winbase.h"
  30. #include "wingdi.h"
  31. #include "winuser.h"
  32. #include "winnls.h"
  33. #include "commctrl.h"
  34. #include "wine/heap.h"
  35. #include "main.h"
  36. /* spaces dividing hex and ASCII */
  37. #define DIV_SPACES 4
  38. typedef struct tagHEXEDIT_INFO
  39. {
  40. HWND hwndSelf;
  41. HFONT hFont;
  42. BOOL bFocus : 1;
  43. BOOL bFocusHex : 1; /* TRUE if focus is on hex, FALSE if focus on ASCII */
  44. BOOL bInsert : 1; /* insert mode if TRUE, overwrite mode if FALSE */
  45. INT nHeight; /* height of text */
  46. INT nCaretPos; /* caret pos in nibbles */
  47. BYTE *pData;
  48. INT cbData;
  49. INT nBytesPerLine; /* bytes of hex to display per line of the control */
  50. INT nScrollPos; /* first visible line */
  51. } HEXEDIT_INFO;
  52. const WCHAR szHexEditClass[] = {'H','e','x','E','d','i','t',0};
  53. static inline LRESULT HexEdit_SetFont (HEXEDIT_INFO *infoPtr, HFONT hFont, BOOL redraw);
  54. static inline BYTE hexchar_to_byte(WCHAR ch)
  55. {
  56. if (ch >= '0' && ch <= '9')
  57. return ch - '0';
  58. else if (ch >= 'a' && ch <= 'f')
  59. return ch - 'a' + 10;
  60. else if (ch >= 'A' && ch <= 'F')
  61. return ch - 'A' + 10;
  62. else
  63. return -1;
  64. }
  65. static LPWSTR HexEdit_GetLineText(int offset, BYTE *pData, LONG cbData, LONG pad)
  66. {
  67. static const WCHAR percent_04xW[] = {'%','0','4','X',' ',' ',0};
  68. static const WCHAR percent_02xW[] = {'%','0','2','X',' ',0};
  69. WCHAR *lpszLine = heap_xalloc((6 + cbData * 3 + pad * 3 + DIV_SPACES + cbData + 1) * sizeof(WCHAR));
  70. LONG i;
  71. wsprintfW(lpszLine, percent_04xW, offset);
  72. for (i = 0; i < cbData; i++)
  73. wsprintfW(lpszLine + 6 + i*3, percent_02xW, pData[offset + i]);
  74. for (i = 0; i < pad * 3; i++)
  75. lpszLine[6 + cbData * 3 + i] = ' ';
  76. for (i = 0; i < DIV_SPACES; i++)
  77. lpszLine[6 + cbData * 3 + pad * 3 + i] = ' ';
  78. /* attempt an ASCII representation if the characters are printable,
  79. * otherwise display a '.' */
  80. for (i = 0; i < cbData; i++)
  81. {
  82. /* (C1_ALPHA|C1_BLANK|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER) */
  83. if (iswprint(pData[offset + i]))
  84. lpszLine[6 + cbData * 3 + pad * 3 + DIV_SPACES + i] = pData[offset + i];
  85. else
  86. lpszLine[6 + cbData * 3 + pad * 3 + DIV_SPACES + i] = '.';
  87. }
  88. lpszLine[6 + cbData * 3 + pad * 3 + DIV_SPACES + cbData] = 0;
  89. return lpszLine;
  90. }
  91. static void
  92. HexEdit_Paint(HEXEDIT_INFO *infoPtr)
  93. {
  94. PAINTSTRUCT ps;
  95. HDC hdc = BeginPaint(infoPtr->hwndSelf, &ps);
  96. INT nXStart, nYStart;
  97. COLORREF clrOldText;
  98. HFONT hOldFont;
  99. INT iMode;
  100. LONG lByteOffset = infoPtr->nScrollPos * infoPtr->nBytesPerLine;
  101. int i;
  102. /* Make a gap from the frame */
  103. nXStart = GetSystemMetrics(SM_CXBORDER);
  104. nYStart = GetSystemMetrics(SM_CYBORDER);
  105. if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)
  106. clrOldText = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
  107. else
  108. clrOldText = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  109. iMode = SetBkMode(hdc, TRANSPARENT);
  110. hOldFont = SelectObject(hdc, infoPtr->hFont);
  111. for (i = lByteOffset; i < infoPtr->cbData; i += infoPtr->nBytesPerLine)
  112. {
  113. LPWSTR lpszLine;
  114. LONG nLineLen = min(infoPtr->cbData - i, infoPtr->nBytesPerLine);
  115. lpszLine = HexEdit_GetLineText(i, infoPtr->pData, nLineLen, infoPtr->nBytesPerLine - nLineLen);
  116. /* FIXME: draw hex <-> ASCII mapping highlighted? */
  117. TextOutW(hdc, nXStart, nYStart, lpszLine, lstrlenW(lpszLine));
  118. nYStart += infoPtr->nHeight;
  119. heap_free(lpszLine);
  120. }
  121. SelectObject(hdc, hOldFont);
  122. SetBkMode(hdc, iMode);
  123. SetTextColor(hdc, clrOldText);
  124. EndPaint(infoPtr->hwndSelf, &ps);
  125. }
  126. static void
  127. HexEdit_UpdateCaret(HEXEDIT_INFO *infoPtr)
  128. {
  129. HDC hdc;
  130. HFONT hOldFont;
  131. SIZE size;
  132. INT nCaretBytePos = infoPtr->nCaretPos/2;
  133. INT nByteLinePos = nCaretBytePos % infoPtr->nBytesPerLine;
  134. INT nLine = nCaretBytePos / infoPtr->nBytesPerLine;
  135. LONG nLineLen = min(infoPtr->cbData - nLine * infoPtr->nBytesPerLine, infoPtr->nBytesPerLine);
  136. LPWSTR lpszLine = HexEdit_GetLineText(nLine * infoPtr->nBytesPerLine, infoPtr->pData, nLineLen, infoPtr->nBytesPerLine - nLineLen);
  137. INT nCharOffset;
  138. /* calculate offset of character caret is on in the line */
  139. if (infoPtr->bFocusHex)
  140. nCharOffset = 6 + nByteLinePos*3 + infoPtr->nCaretPos % 2;
  141. else
  142. nCharOffset = 6 + infoPtr->nBytesPerLine*3 + DIV_SPACES + nByteLinePos;
  143. hdc = GetDC(infoPtr->hwndSelf);
  144. hOldFont = SelectObject(hdc, infoPtr->hFont);
  145. GetTextExtentPoint32W(hdc, lpszLine, nCharOffset, &size);
  146. SelectObject(hdc, hOldFont);
  147. ReleaseDC(infoPtr->hwndSelf, hdc);
  148. if (!nLineLen) size.cx = 0;
  149. heap_free(lpszLine);
  150. SetCaretPos(
  151. GetSystemMetrics(SM_CXBORDER) + size.cx,
  152. GetSystemMetrics(SM_CYBORDER) + (nLine - infoPtr->nScrollPos) * infoPtr->nHeight);
  153. }
  154. static void
  155. HexEdit_UpdateScrollbars(HEXEDIT_INFO *infoPtr)
  156. {
  157. RECT rcClient;
  158. INT nLines = infoPtr->cbData / infoPtr->nBytesPerLine;
  159. INT nVisibleLines;
  160. SCROLLINFO si;
  161. GetClientRect(infoPtr->hwndSelf, &rcClient);
  162. InflateRect(&rcClient, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
  163. nVisibleLines = (rcClient.bottom - rcClient.top) / infoPtr->nHeight;
  164. si.cbSize = sizeof(si);
  165. si.fMask = SIF_RANGE | SIF_PAGE;
  166. si.nMin = 0;
  167. si.nMax = max(nLines - nVisibleLines, nLines);
  168. si.nPage = nVisibleLines;
  169. SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si, TRUE);
  170. }
  171. static void
  172. HexEdit_EnsureVisible(HEXEDIT_INFO *infoPtr, INT nCaretPos)
  173. {
  174. INT nLine = nCaretPos / (2 * infoPtr->nBytesPerLine);
  175. SCROLLINFO si;
  176. si.cbSize = sizeof(si);
  177. si.fMask = SIF_POS | SIF_PAGE;
  178. GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si);
  179. if (nLine < si.nPos)
  180. si.nPos = nLine;
  181. else if (nLine >= si.nPos + si.nPage)
  182. si.nPos = nLine - si.nPage + 1;
  183. else
  184. return;
  185. si.fMask = SIF_POS;
  186. SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si, FALSE);
  187. SendMessageW(infoPtr->hwndSelf, WM_VSCROLL, MAKELONG(SB_THUMBPOSITION, 0), 0);
  188. }
  189. static LRESULT
  190. HexEdit_SetData(HEXEDIT_INFO *infoPtr, INT cbData, const BYTE *pData)
  191. {
  192. heap_free(infoPtr->pData);
  193. infoPtr->cbData = 0;
  194. infoPtr->pData = heap_xalloc(cbData);
  195. memcpy(infoPtr->pData, pData, cbData);
  196. infoPtr->cbData = cbData;
  197. infoPtr->nCaretPos = 0;
  198. HexEdit_UpdateScrollbars(infoPtr);
  199. HexEdit_UpdateCaret(infoPtr);
  200. InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
  201. return TRUE;
  202. }
  203. static LRESULT
  204. HexEdit_GetData(HEXEDIT_INFO *infoPtr, INT cbData, BYTE *pData)
  205. {
  206. if (pData)
  207. memcpy(pData, infoPtr->pData, min(cbData, infoPtr->cbData));
  208. return infoPtr->cbData;
  209. }
  210. static inline LRESULT
  211. HexEdit_Char (HEXEDIT_INFO *infoPtr, WCHAR ch)
  212. {
  213. INT nCaretBytePos = infoPtr->nCaretPos/2;
  214. assert(nCaretBytePos >= 0);
  215. /* backspace is special */
  216. if (ch == '\b')
  217. {
  218. if (infoPtr->nCaretPos == 0)
  219. return 0;
  220. /* if at end of byte then delete the whole byte */
  221. if (infoPtr->bFocusHex && (infoPtr->nCaretPos % 2 == 0))
  222. {
  223. memmove(infoPtr->pData + nCaretBytePos - 1,
  224. infoPtr->pData + nCaretBytePos,
  225. infoPtr->cbData - nCaretBytePos);
  226. infoPtr->cbData--;
  227. infoPtr->nCaretPos -= 2; /* backtrack two nibble */
  228. }
  229. else /* blank upper nibble */
  230. {
  231. infoPtr->pData[nCaretBytePos] &= 0x0f;
  232. infoPtr->nCaretPos--; /* backtrack one nibble */
  233. }
  234. }
  235. else
  236. {
  237. if (infoPtr->bFocusHex && hexchar_to_byte(ch) == (BYTE)-1)
  238. {
  239. MessageBeep(MB_ICONWARNING);
  240. return 0;
  241. }
  242. if ((infoPtr->bInsert && (infoPtr->nCaretPos % 2 == 0)) || (nCaretBytePos >= infoPtr->cbData))
  243. {
  244. /* make room for another byte */
  245. infoPtr->cbData++;
  246. infoPtr->pData = heap_xrealloc(infoPtr->pData, infoPtr->cbData + 1);
  247. /* move everything after caret up one byte */
  248. memmove(infoPtr->pData + nCaretBytePos + 1,
  249. infoPtr->pData + nCaretBytePos,
  250. infoPtr->cbData - nCaretBytePos);
  251. /* zero new byte */
  252. infoPtr->pData[nCaretBytePos] = 0x0;
  253. }
  254. /* overwrite a byte */
  255. assert(nCaretBytePos < infoPtr->cbData);
  256. if (infoPtr->bFocusHex)
  257. {
  258. BYTE orig_byte = infoPtr->pData[nCaretBytePos];
  259. BYTE digit = hexchar_to_byte(ch);
  260. if (infoPtr->nCaretPos % 2) /* set low nibble */
  261. infoPtr->pData[nCaretBytePos] = (orig_byte & 0xf0) | digit;
  262. else /* set high nibble */
  263. infoPtr->pData[nCaretBytePos] = (orig_byte & 0x0f) | digit << 4;
  264. infoPtr->nCaretPos++; /* advance one nibble */
  265. }
  266. else
  267. {
  268. infoPtr->pData[nCaretBytePos] = (BYTE)ch;
  269. infoPtr->nCaretPos += 2; /* advance two nibbles */
  270. }
  271. }
  272. HexEdit_UpdateScrollbars(infoPtr);
  273. InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
  274. HexEdit_UpdateCaret(infoPtr);
  275. HexEdit_EnsureVisible(infoPtr, infoPtr->nCaretPos);
  276. return 0;
  277. }
  278. static inline LRESULT
  279. HexEdit_Destroy (HEXEDIT_INFO *infoPtr)
  280. {
  281. HWND hwnd = infoPtr->hwndSelf;
  282. heap_free(infoPtr->pData);
  283. /* free info data */
  284. heap_free(infoPtr);
  285. SetWindowLongPtrW(hwnd, 0, 0);
  286. return 0;
  287. }
  288. static inline LRESULT
  289. HexEdit_GetFont (HEXEDIT_INFO *infoPtr)
  290. {
  291. return (LRESULT)infoPtr->hFont;
  292. }
  293. static inline LRESULT
  294. HexEdit_KeyDown (HEXEDIT_INFO *infoPtr, DWORD key, DWORD flags)
  295. {
  296. INT nInc = (infoPtr->bFocusHex) ? 1 : 2;
  297. SCROLLINFO si;
  298. switch (key)
  299. {
  300. case VK_LEFT:
  301. infoPtr->nCaretPos -= nInc;
  302. if (infoPtr->nCaretPos < 0)
  303. infoPtr->nCaretPos = 0;
  304. break;
  305. case VK_RIGHT:
  306. infoPtr->nCaretPos += nInc;
  307. if (infoPtr->nCaretPos > infoPtr->cbData*2)
  308. infoPtr->nCaretPos = infoPtr->cbData*2;
  309. break;
  310. case VK_UP:
  311. if ((infoPtr->nCaretPos - infoPtr->nBytesPerLine*2) >= 0)
  312. infoPtr->nCaretPos -= infoPtr->nBytesPerLine*2;
  313. break;
  314. case VK_DOWN:
  315. if ((infoPtr->nCaretPos + infoPtr->nBytesPerLine*2) <= infoPtr->cbData*2)
  316. infoPtr->nCaretPos += infoPtr->nBytesPerLine*2;
  317. break;
  318. case VK_HOME:
  319. infoPtr->nCaretPos = 0;
  320. break;
  321. case VK_END:
  322. infoPtr->nCaretPos = infoPtr->cbData*2;
  323. break;
  324. case VK_PRIOR: /* page up */
  325. si.cbSize = sizeof(si);
  326. si.fMask = SIF_PAGE;
  327. GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si);
  328. if ((infoPtr->nCaretPos - (INT)si.nPage*infoPtr->nBytesPerLine*2) >= 0)
  329. infoPtr->nCaretPos -= si.nPage*infoPtr->nBytesPerLine*2;
  330. else
  331. infoPtr->nCaretPos = 0;
  332. break;
  333. case VK_NEXT: /* page down */
  334. si.cbSize = sizeof(si);
  335. si.fMask = SIF_PAGE;
  336. GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si);
  337. if ((infoPtr->nCaretPos + (INT)si.nPage*infoPtr->nBytesPerLine*2) <= infoPtr->cbData*2)
  338. infoPtr->nCaretPos += si.nPage*infoPtr->nBytesPerLine*2;
  339. else
  340. infoPtr->nCaretPos = infoPtr->cbData*2;
  341. break;
  342. default:
  343. return 0;
  344. }
  345. HexEdit_UpdateCaret(infoPtr);
  346. HexEdit_EnsureVisible(infoPtr, infoPtr->nCaretPos);
  347. return 0;
  348. }
  349. static inline LRESULT
  350. HexEdit_KillFocus (HEXEDIT_INFO *infoPtr, HWND receiveFocus)
  351. {
  352. infoPtr->bFocus = FALSE;
  353. DestroyCaret();
  354. return 0;
  355. }
  356. static inline LRESULT
  357. HexEdit_LButtonDown (HEXEDIT_INFO *infoPtr)
  358. {
  359. SetFocus(infoPtr->hwndSelf);
  360. /* FIXME: hittest and set caret */
  361. return 0;
  362. }
  363. static inline LRESULT HexEdit_NCCreate (HWND hwnd, LPCREATESTRUCTW lpcs)
  364. {
  365. HEXEDIT_INFO *infoPtr;
  366. SetWindowLongW(hwnd, GWL_EXSTYLE,
  367. lpcs->dwExStyle | WS_EX_CLIENTEDGE);
  368. /* allocate memory for info structure */
  369. infoPtr = heap_xalloc(sizeof(HEXEDIT_INFO));
  370. memset(infoPtr, 0, sizeof(HEXEDIT_INFO));
  371. SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
  372. /* initialize info structure */
  373. infoPtr->nCaretPos = 0;
  374. infoPtr->hwndSelf = hwnd;
  375. infoPtr->nBytesPerLine = 2;
  376. infoPtr->bFocusHex = TRUE;
  377. infoPtr->bInsert = TRUE;
  378. return DefWindowProcW(infoPtr->hwndSelf, WM_NCCREATE, 0, (LPARAM)lpcs);
  379. }
  380. static inline LRESULT
  381. HexEdit_SetFocus (HEXEDIT_INFO *infoPtr, HWND lostFocus)
  382. {
  383. infoPtr->bFocus = TRUE;
  384. CreateCaret(infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight);
  385. HexEdit_UpdateCaret(infoPtr);
  386. ShowCaret(infoPtr->hwndSelf);
  387. return 0;
  388. }
  389. static inline LRESULT
  390. HexEdit_SetFont (HEXEDIT_INFO *infoPtr, HFONT hFont, BOOL redraw)
  391. {
  392. TEXTMETRICW tm;
  393. HDC hdc;
  394. HFONT hOldFont = NULL;
  395. LONG i;
  396. RECT rcClient;
  397. infoPtr->hFont = hFont;
  398. hdc = GetDC(infoPtr->hwndSelf);
  399. if (infoPtr->hFont)
  400. hOldFont = SelectObject(hdc, infoPtr->hFont);
  401. GetTextMetricsW(hdc, &tm);
  402. infoPtr->nHeight = tm.tmHeight + tm.tmExternalLeading;
  403. GetClientRect(infoPtr->hwndSelf, &rcClient);
  404. for (i = 0; ; i++)
  405. {
  406. BYTE *pData = heap_xalloc(i);
  407. WCHAR *lpszLine;
  408. SIZE size;
  409. memset(pData, 0, i);
  410. lpszLine = HexEdit_GetLineText(0, pData, i, 0);
  411. GetTextExtentPoint32W(hdc, lpszLine, lstrlenW(lpszLine), &size);
  412. heap_free(lpszLine);
  413. heap_free(pData);
  414. if (size.cx > (rcClient.right - rcClient.left))
  415. {
  416. infoPtr->nBytesPerLine = i - 1;
  417. break;
  418. }
  419. }
  420. HexEdit_UpdateScrollbars(infoPtr);
  421. if (infoPtr->hFont)
  422. SelectObject(hdc, hOldFont);
  423. ReleaseDC (infoPtr->hwndSelf, hdc);
  424. if (redraw)
  425. InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
  426. return 0;
  427. }
  428. static inline LRESULT
  429. HexEdit_VScroll (HEXEDIT_INFO *infoPtr, INT action)
  430. {
  431. SCROLLINFO si;
  432. /* get all scroll bar info */
  433. si.cbSize = sizeof(si);
  434. si.fMask = SIF_ALL;
  435. GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si);
  436. switch (LOWORD(action))
  437. {
  438. case SB_TOP: /* user pressed the home key */
  439. si.nPos = si.nMin;
  440. break;
  441. case SB_BOTTOM: /* user pressed the end key */
  442. si.nPos = si.nMax;
  443. break;
  444. case SB_LINEUP: /* user clicked the up arrow */
  445. si.nPos -= 1;
  446. break;
  447. case SB_LINEDOWN: /* user clicked the down arrow */
  448. si.nPos += 1;
  449. break;
  450. case SB_PAGEUP: /* user clicked the scroll bar above the scroll thumb */
  451. si.nPos -= si.nPage;
  452. break;
  453. case SB_PAGEDOWN: /* user clicked the scroll bar below the scroll thumb */
  454. si.nPos += si.nPage;
  455. break;
  456. case SB_THUMBTRACK: /* user dragged the scroll thumb */
  457. si.nPos = si.nTrackPos;
  458. break;
  459. default:
  460. break;
  461. }
  462. /* set the position and then retrieve it to let the system handle the
  463. * cases where the position is out of range */
  464. si.fMask = SIF_POS;
  465. SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si, TRUE);
  466. GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si);
  467. if (si.nPos != infoPtr->nScrollPos)
  468. {
  469. ScrollWindow(infoPtr->hwndSelf, 0, infoPtr->nHeight * (infoPtr->nScrollPos - si.nPos), NULL, NULL);
  470. infoPtr->nScrollPos = si.nPos;
  471. UpdateWindow(infoPtr->hwndSelf);
  472. /* need to update caret position since it depends on the scroll position */
  473. HexEdit_UpdateCaret(infoPtr);
  474. }
  475. return 0;
  476. }
  477. static LRESULT WINAPI
  478. HexEdit_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  479. {
  480. HEXEDIT_INFO *infoPtr = (HEXEDIT_INFO *)GetWindowLongPtrW(hwnd, 0);
  481. if (!infoPtr && (uMsg != WM_NCCREATE))
  482. return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  483. switch (uMsg)
  484. {
  485. case HEM_SETDATA:
  486. return HexEdit_SetData (infoPtr, (INT)wParam, (const BYTE *)lParam);
  487. case HEM_GETDATA:
  488. return HexEdit_GetData (infoPtr, (INT)wParam, (BYTE *)lParam);
  489. case WM_CHAR:
  490. return HexEdit_Char (infoPtr, (WCHAR)wParam);
  491. case WM_DESTROY:
  492. return HexEdit_Destroy (infoPtr);
  493. case WM_GETDLGCODE:
  494. return DLGC_WANTCHARS | DLGC_WANTARROWS;
  495. case WM_GETFONT:
  496. return HexEdit_GetFont (infoPtr);
  497. case WM_KEYDOWN:
  498. return HexEdit_KeyDown (infoPtr, wParam, lParam);
  499. case WM_KILLFOCUS:
  500. return HexEdit_KillFocus (infoPtr, (HWND)wParam);
  501. case WM_LBUTTONDOWN:
  502. return HexEdit_LButtonDown (infoPtr);
  503. case WM_NCCREATE:
  504. return HexEdit_NCCreate (hwnd, (LPCREATESTRUCTW)lParam);
  505. case WM_PAINT:
  506. HexEdit_Paint(infoPtr);
  507. return 0;
  508. case WM_SETFOCUS:
  509. return HexEdit_SetFocus (infoPtr, (HWND)wParam);
  510. case WM_SETFONT:
  511. return HexEdit_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam));
  512. case WM_VSCROLL:
  513. return HexEdit_VScroll (infoPtr, (INT)wParam);
  514. default:
  515. return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  516. }
  517. return 0;
  518. }
  519. void HexEdit_Register(void)
  520. {
  521. WNDCLASSW wndClass;
  522. ZeroMemory(&wndClass, sizeof(WNDCLASSW));
  523. wndClass.style = 0;
  524. wndClass.lpfnWndProc = HexEdit_WindowProc;
  525. wndClass.cbClsExtra = 0;
  526. wndClass.cbWndExtra = sizeof(HEXEDIT_INFO *);
  527. wndClass.hCursor = LoadCursorW(0, (const WCHAR *)IDC_IBEAM);
  528. wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  529. wndClass.lpszClassName = szHexEditClass;
  530. RegisterClassW(&wndClass);
  531. }