From 828aff306c58fe51822519ca73c962437e732b30 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Thu, 14 Apr 2005 11:30:31 +0000 Subject: [PATCH] - Add neutral English resources. - Add a control for editing binary data. - Add a binary value editor dialog. --- programs/regedit/En.rc | 87 ++++- programs/regedit/Makefile.in | 1 + programs/regedit/edit.c | 67 +++- programs/regedit/hexedit.c | 700 +++++++++++++++++++++++++++++++++++ programs/regedit/main.c | 3 + programs/regedit/main.h | 9 + programs/regedit/resource.h | 1 + 7 files changed, 865 insertions(+), 3 deletions(-) create mode 100644 programs/regedit/hexedit.c diff --git a/programs/regedit/En.rc b/programs/regedit/En.rc index 813daceaee..7165e45029 100644 --- a/programs/regedit/En.rc +++ b/programs/regedit/En.rc @@ -18,6 +18,76 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* English Neutral Resources */ + +LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL + +STRINGTABLE DISCARDABLE +BEGIN + ID_FAVORITES_ADDTOFAVORITES "Adds keys to the favourites list" + ID_FAVORITES_REMOVEFAVORITE "Removes keys from the favourites list" +END + +IDR_REGEDIT_MENU MENU DISCARDABLE +BEGIN + POPUP "&Registry" + BEGIN + MENUITEM "&Import Registry File...", ID_REGISTRY_IMPORTREGISTRYFILE + MENUITEM "&Export Registry File...", ID_REGISTRY_EXPORTREGISTRYFILE + MENUITEM SEPARATOR + MENUITEM "&Connect Network Registry...", ID_REGISTRY_CONNECTNETWORKREGISTRY, GRAYED + MENUITEM "&Disconnect Network Registry...", ID_REGISTRY_DISCONNECTNETWORKREGISTRY, GRAYED + MENUITEM SEPARATOR + MENUITEM "&Print\tCtrl+P", ID_REGISTRY_PRINT, GRAYED + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_REGISTRY_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Modify", ID_EDIT_MODIFY + MENUITEM SEPARATOR + POPUP "&New" + BEGIN + MENUITEM "&Key", ID_EDIT_NEW_KEY + MENUITEM SEPARATOR + MENUITEM "&String Value", ID_EDIT_NEW_STRINGVALUE + MENUITEM "&Binary Value", ID_EDIT_NEW_BINARYVALUE + MENUITEM "&DWORD Value", ID_EDIT_NEW_DWORDVALUE + END + MENUITEM SEPARATOR + MENUITEM "&Delete\tDel", ID_EDIT_DELETE + MENUITEM "&Rename\tF2", ID_EDIT_RENAME + MENUITEM SEPARATOR + MENUITEM "&Copy Key Name", ID_EDIT_COPYKEYNAME + MENUITEM SEPARATOR + MENUITEM "&Find\tCtrl+F", ID_EDIT_FIND, GRAYED + MENUITEM "Find Ne&xt\tF3", ID_EDIT_FINDNEXT, GRAYED + END + POPUP "&View" + BEGIN + MENUITEM "Status &Bar", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "Sp&lit", ID_VIEW_SPLIT + MENUITEM SEPARATOR + MENUITEM "&Refresh\tF5", ID_VIEW_REFRESH + END + POPUP "&Favourites" + BEGIN + MENUITEM "&Add to Favourites", ID_FAVORITES_ADDTOFAVORITES + , GRAYED + MENUITEM "&Remove Favourite", ID_FAVORITES_REMOVEFAVORITE + , GRAYED + END + POPUP "&Help" + BEGIN + MENUITEM "&Help Topics\tF1", ID_HELP_HELPTOPICS + MENUITEM SEPARATOR + MENUITEM "&About Registry Editor", ID_HELP_ABOUT + END +END + +/* US English Resources */ + LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US /* @@ -130,7 +200,7 @@ END */ IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +STYLE DS_MODALFRAME | DS_NOIDLEMSG | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "MS Shell Dlg" BEGIN @@ -155,7 +225,7 @@ BEGIN END IDD_EDIT_DWORD DIALOG DISCARDABLE 22, 17, 210, 100 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +STYLE DS_MODALFRAME | DS_NOIDLEMSG | WS_CAPTION | WS_SYSMENU CAPTION "Edit DWORD" FONT 8, "MS Shell Dlg" BEGIN @@ -170,6 +240,19 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,175,80,30,11,WS_GROUP END +IDD_EDIT_BINARY DIALOG DISCARDABLE 22, 17, 210, 100 +STYLE DS_MODALFRAME | DS_NOIDLEMSG | WS_CAPTION | WS_SYSMENU +CAPTION "Edit Binary" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Value name:",IDC_STATIC,5,5,119,8 + EDITTEXT IDC_VALUE_NAME,5,15,200,12, WS_BORDER | WS_TABSTOP | WS_DISABLED + LTEXT "Value data:",IDC_STATIC,5,30,90,8 + CONTROL "",IDC_VALUE_DATA,"HexEdit",WS_TABSTOP,4,40,200,40 + DEFPUSHBUTTON "OK",IDOK,140,80,30,11,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,175,80,30,11,WS_GROUP +END + /* * String Table */ diff --git a/programs/regedit/Makefile.in b/programs/regedit/Makefile.in index 7d54c28ad5..0d5449ea6a 100644 --- a/programs/regedit/Makefile.in +++ b/programs/regedit/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ childwnd.c \ edit.c \ framewnd.c \ + hexedit.c \ listview.c \ main.c \ regedit.c \ diff --git a/programs/regedit/edit.c b/programs/regedit/edit.c index 01305e8b03..396fec9643 100644 --- a/programs/regedit/edit.c +++ b/programs/regedit/edit.c @@ -38,6 +38,14 @@ static const TCHAR* editValueName; static TCHAR* stringValueData; static BOOL isDecimal; +struct edit_params +{ + HKEY hKey; + LPCTSTR lpszValueName; + void *pData; + LONG cbData; +}; + INT vmessagebox(HWND hwnd, INT buttons, INT titleId, INT resId, va_list ap) { TCHAR title[256]; @@ -142,6 +150,54 @@ INT_PTR CALLBACK modify_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM l return FALSE; } +static INT_PTR CALLBACK bin_modify_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + struct edit_params *params; + LPBYTE pData; + LONG cbData; + LONG lRet; + + switch(uMsg) { + case WM_INITDIALOG: + params = (struct edit_params *)lParam; + SetWindowLongPtr(hwndDlg, DWLP_USER, (ULONG_PTR)params); + if (params->lpszValueName) + SetDlgItemText(hwndDlg, IDC_VALUE_NAME, params->lpszValueName); + else + SetDlgItemText(hwndDlg, IDC_VALUE_NAME, g_pszDefaultValueName); + SendDlgItemMessage(hwndDlg, IDC_VALUE_DATA, HEM_SETDATA, (WPARAM)params->cbData, (LPARAM)params->pData); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + params = (struct edit_params *)GetWindowLongPtr(hwndDlg, DWLP_USER); + cbData = SendDlgItemMessage(hwndDlg, IDC_VALUE_DATA, HEM_GETDATA, 0, 0); + pData = HeapAlloc(GetProcessHeap(), 0, cbData); + + if (pData) + { + SendDlgItemMessage(hwndDlg, IDC_VALUE_DATA, HEM_GETDATA, (WPARAM)cbData, (LPARAM)pData); + lRet = RegSetValueEx(params->hKey, params->lpszValueName, 0, REG_BINARY, pData, cbData); + } + else + lRet = ERROR_OUTOFMEMORY; + + if (lRet == ERROR_SUCCESS) + EndDialog(hwndDlg, 1); + else + { + error_code_messagebox(hwndDlg, lRet); + EndDialog(hwndDlg, 0); + } + return TRUE; + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + return FALSE; +} + static BOOL check_value(HWND hwnd, HKEY hKey, LPCTSTR valueName) { LONG lRet = RegQueryValueEx(hKey, valueName ? valueName : _T(""), 0, NULL, 0, NULL); @@ -231,6 +287,7 @@ BOOL ModifyValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPCTSTR valueName) DWORD type; LONG lRet; HKEY hKey; + LONG len; lRet = RegOpenKeyEx(hKeyRoot, keyPath, 0, KEY_READ | KEY_SET_VALUE, &hKey); if (lRet != ERROR_SUCCESS) { @@ -239,7 +296,7 @@ BOOL ModifyValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPCTSTR valueName) } editValueName = valueName ? valueName : g_pszDefaultValueName; - if(!(stringValueData = read_value(hwnd, hKey, valueName, &type, 0))) goto done; + if(!(stringValueData = read_value(hwnd, hKey, valueName, &type, &len))) goto done; if ( (type == REG_SZ) || (type == REG_EXPAND_SZ) ) { if (DialogBox(0, MAKEINTRESOURCE(IDD_EDIT_STRING), hwnd, modify_dlgproc) == IDOK) { @@ -257,6 +314,14 @@ BOOL ModifyValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPCTSTR valueName) else error_code_messagebox(hwnd, lRet); } } + } else if ( type == REG_BINARY ) { + struct edit_params params; + params.hKey = hKey; + params.lpszValueName = valueName; + params.pData = stringValueData; + params.cbData = len; + result = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_EDIT_BINARY), hwnd, + bin_modify_dlgproc, (LPARAM)¶ms); } else { error(hwnd, IDS_UNSUPPORTED_TYPE, type); } diff --git a/programs/regedit/hexedit.c b/programs/regedit/hexedit.c new file mode 100644 index 0000000000..9cbf85c7b4 --- /dev/null +++ b/programs/regedit/hexedit.c @@ -0,0 +1,700 @@ +/* + * Hex Edit control + * + * Copyright 2005 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - Selection support + * - Cut, copy and paste + * - Mouse support + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" + +#include "main.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(regedit); + +/* spaces dividing hex and ASCII */ +#define DIV_SPACES 4 + +typedef struct tagHEXEDIT_INFO +{ + HWND hwndSelf; + HFONT hFont; + BOOL bFocus : 1; + BOOL bFocusHex : 1; /* TRUE if focus is on hex, FALSE if focus on ASCII */ + BOOL bInsert : 1; /* insert mode if TRUE, overwrite mode if FALSE */ + INT nHeight; /* height of text */ + INT nCaretPos; /* caret pos in nibbles */ + BYTE *pData; + INT cbData; + INT nBytesPerLine; /* bytes of hex to display per line of the control */ + INT nScrollPos; /* first visible line */ +} HEXEDIT_INFO; + +static inline LRESULT HexEdit_SetFont (HEXEDIT_INFO *infoPtr, HFONT hFont, BOOL redraw); + +static inline BYTE hexchar_to_byte(TCHAR ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static LPTSTR HexEdit_GetLineText(BYTE *pData, LONG cbData, LONG pad) +{ + LPTSTR lpszLine = HeapAlloc(GetProcessHeap(), 0, + (cbData * 3 + pad * 3 + DIV_SPACES + cbData + 1) * sizeof(TCHAR)); + LONG i; + + if (!lpszLine) + return NULL; + + for (i = 0; i < cbData; i++) + wsprintf(lpszLine + i*3, TEXT("%02X "), pData[i]); + for (i = 0; i < pad * 3; i++) + lpszLine[cbData * 3 + i] = ' '; + + for (i = 0; i < DIV_SPACES; i++) + lpszLine[cbData * 3 + pad * 3 + i] = ' '; + + /* attempt an ASCII representation if the characters are printable, + * otherwise display a '.' */ + for (i = 0; i < cbData; i++) + { + /* (C1_ALPHA|C1_BLANK|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER) */ + if (isprint(pData[i])) + lpszLine[cbData * 3 + pad * 3 + DIV_SPACES + i] = pData[i]; + else + lpszLine[cbData * 3 + pad * 3 + DIV_SPACES + i] = '.'; + } + lpszLine[cbData * 3 + pad * 3 + DIV_SPACES + cbData] = 0; + return lpszLine; +} + +static void +HexEdit_Paint(HEXEDIT_INFO *infoPtr) +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(infoPtr->hwndSelf, &ps); + INT nXStart, nYStart; + COLORREF clrOldText; + HFONT hOldFont; + BYTE *pData; + INT iMode; + LONG lByteOffset = infoPtr->nScrollPos * infoPtr->nBytesPerLine; + + /* Make a gap from the frame */ + nXStart = GetSystemMetrics(SM_CXBORDER); + nYStart = GetSystemMetrics(SM_CYBORDER); + + if (GetWindowLong(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) + clrOldText = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + else + clrOldText = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + + iMode = SetBkMode(hdc, TRANSPARENT); + hOldFont = SelectObject(hdc, infoPtr->hFont); + + for (pData = infoPtr->pData + lByteOffset; pData < infoPtr->pData + infoPtr->cbData; pData += infoPtr->nBytesPerLine) + { + LPTSTR lpszLine; + LONG nLineLen = min((LONG)((infoPtr->pData + infoPtr->cbData) - pData), + infoPtr->nBytesPerLine); + + lpszLine = HexEdit_GetLineText(pData, nLineLen, infoPtr->nBytesPerLine - nLineLen); + + /* FIXME: draw hex <-> ASCII mapping highlighted? */ + TextOut(hdc, nXStart, nYStart, lpszLine, infoPtr->nBytesPerLine * 3 + DIV_SPACES + nLineLen); + + nYStart += infoPtr->nHeight; + HeapFree(GetProcessHeap(), 0, lpszLine); + } + + SelectObject(hdc, hOldFont); + SetBkMode(hdc, iMode); + SetTextColor(hdc, clrOldText); + + EndPaint(infoPtr->hwndSelf, &ps); +} + +static void +HexEdit_UpdateCaret(HEXEDIT_INFO *infoPtr) +{ + HDC hdc; + HFONT hOldFont; + SIZE size; + INT nCaretBytePos = infoPtr->nCaretPos/2; + INT nByteLinePos = nCaretBytePos % infoPtr->nBytesPerLine; + INT nLine = nCaretBytePos / infoPtr->nBytesPerLine; + LONG nLineLen = min(infoPtr->cbData - nLine * infoPtr->nBytesPerLine, infoPtr->nBytesPerLine); + LPTSTR lpszLine = HexEdit_GetLineText(infoPtr->pData + nLine * infoPtr->nBytesPerLine, nLineLen, infoPtr->nBytesPerLine - nLineLen); + INT nCharOffset; + + /* calculate offset of character caret is on in the line */ + if (infoPtr->bFocusHex) + nCharOffset = nByteLinePos*3 + infoPtr->nCaretPos % 2; + else + nCharOffset = infoPtr->nBytesPerLine*3 + DIV_SPACES + nByteLinePos; + + hdc = GetDC(infoPtr->hwndSelf); + hOldFont = SelectObject(hdc, infoPtr->hFont); + + GetTextExtentPoint32(hdc, lpszLine, nCharOffset, &size); + + SelectObject(hdc, hOldFont); + ReleaseDC(infoPtr->hwndSelf, hdc); + + if (!nLineLen) size.cx = 0; + + HeapFree(GetProcessHeap(), 0, lpszLine); + + SetCaretPos( + GetSystemMetrics(SM_CXBORDER) + size.cx, + GetSystemMetrics(SM_CYBORDER) + (nLine - infoPtr->nScrollPos) * infoPtr->nHeight); +} + +static void +HexEdit_UpdateScrollbars(HEXEDIT_INFO *infoPtr) +{ + RECT rcClient; + INT nLines = infoPtr->cbData / infoPtr->nBytesPerLine; + INT nVisibleLines; + SCROLLINFO si; + + GetClientRect(infoPtr->hwndSelf, &rcClient); + InflateRect(&rcClient, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER)); + + nVisibleLines = (rcClient.bottom - rcClient.top) / infoPtr->nHeight; + si.cbSize = sizeof(si); + si.fMask = SIF_RANGE | SIF_PAGE; + si.nMin = 0; + si.nMax = max(nLines - nVisibleLines, nLines); + si.nPage = nVisibleLines; + SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si, TRUE); +} + +static void +HexEdit_EnsureVisible(HEXEDIT_INFO *infoPtr, INT nCaretPos) +{ + INT nLine = nCaretPos / (2 * infoPtr->nBytesPerLine); + SCROLLINFO si; + + si.cbSize = sizeof(si); + si.fMask = SIF_POS | SIF_PAGE; + GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si); + if (nLine < si.nPos) + si.nPos = nLine; + else if (nLine >= si.nPos + si.nPage) + si.nPos = nLine - si.nPage + 1; + else + return; + si.fMask = SIF_POS; + + SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si, FALSE); + SendMessage(infoPtr->hwndSelf, WM_VSCROLL, MAKELONG(SB_THUMBPOSITION, 0), 0); +} + + +static LRESULT +HexEdit_SetData(HEXEDIT_INFO *infoPtr, INT cbData, const BYTE *pData) +{ + HeapFree(GetProcessHeap(), 0, infoPtr->pData); + infoPtr->cbData = 0; + + infoPtr->pData = HeapAlloc(GetProcessHeap(), 0, cbData); + if (infoPtr->pData) + { + memcpy(infoPtr->pData, pData, cbData); + infoPtr->cbData = cbData; + + infoPtr->nCaretPos = 0; + HexEdit_UpdateScrollbars(infoPtr); + HexEdit_UpdateCaret(infoPtr); + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return TRUE; + } + return FALSE; +} + +static LRESULT +HexEdit_GetData(HEXEDIT_INFO *infoPtr, INT cbData, BYTE *pData) +{ + if (pData) + memcpy(pData, infoPtr->pData, min(cbData, infoPtr->cbData)); + return infoPtr->cbData; +} + +static inline LRESULT +HexEdit_Char (HEXEDIT_INFO *infoPtr, TCHAR ch) +{ + INT nCaretBytePos = infoPtr->nCaretPos/2; + + assert(nCaretBytePos >= 0); + + /* backspace is special */ + if (ch == '\b') + { + if (infoPtr->nCaretPos == 0) + return 0; + + /* if at end of byte then delete the whole byte */ + if (infoPtr->bFocusHex && (infoPtr->nCaretPos % 2 == 0)) + { + memmove(infoPtr->pData + nCaretBytePos - 1, + infoPtr->pData + nCaretBytePos, + infoPtr->cbData - nCaretBytePos); + infoPtr->cbData--; + infoPtr->nCaretPos -= 2; /* backtrack two nibble */ + } + else /* blank upper nibble */ + { + infoPtr->pData[nCaretBytePos] &= 0x0f; + infoPtr->nCaretPos--; /* backtrack one nibble */ + } + } + else + { + if (infoPtr->bFocusHex && hexchar_to_byte(ch) == (BYTE)-1) + { + MessageBeep(MB_ICONWARNING); + return 0; + } + + if ((infoPtr->bInsert && (infoPtr->nCaretPos % 2 == 0)) || (nCaretBytePos >= infoPtr->cbData)) + { + /* make room for another byte */ + infoPtr->cbData++; + infoPtr->pData = HeapReAlloc(GetProcessHeap(), 0, infoPtr->pData, infoPtr->cbData + 1); + if (!infoPtr->pData) return 0; + /* move everything after caret up one byte */ + memmove(infoPtr->pData + nCaretBytePos + 1, + infoPtr->pData + nCaretBytePos, + infoPtr->cbData - nCaretBytePos); + /* zero new byte */ + infoPtr->pData[nCaretBytePos] = 0x0; + } + + /* overwrite a byte */ + + assert(nCaretBytePos < infoPtr->cbData); + + if (infoPtr->bFocusHex) + { + BYTE orig_byte = infoPtr->pData[nCaretBytePos]; + BYTE digit = hexchar_to_byte(ch); + if (infoPtr->nCaretPos % 2) /* set low nibble */ + infoPtr->pData[nCaretBytePos] = (orig_byte & 0xf0) | digit; + else /* set high nibble */ + infoPtr->pData[nCaretBytePos] = (orig_byte & 0x0f) | digit << 4; + infoPtr->nCaretPos++; /* advance one nibble */ + } + else + { + infoPtr->pData[nCaretBytePos] = (BYTE)ch; + infoPtr->nCaretPos += 2; /* advance two nibbles */ + } + } + + HexEdit_UpdateScrollbars(infoPtr); + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + HexEdit_UpdateCaret(infoPtr); + HexEdit_EnsureVisible(infoPtr, infoPtr->nCaretPos); + return 0; +} + +static inline LRESULT +HexEdit_Create (HEXEDIT_INFO *infoPtr, LPCREATESTRUCT lpcs) +{ + HexEdit_SetFont(infoPtr, GetStockObject(SYSTEM_FONT), FALSE); + HexEdit_UpdateScrollbars(infoPtr); + + return 0; +} + + +static inline LRESULT +HexEdit_Destroy (HEXEDIT_INFO *infoPtr) +{ + HWND hwnd = infoPtr->hwndSelf; + HeapFree(GetProcessHeap(), 0, infoPtr->pData); + /* free info data */ + HeapFree(GetProcessHeap(), 0, infoPtr); + SetWindowLongPtr(hwnd, 0, 0); + return 0; +} + + +static inline LRESULT +HexEdit_EraseBackground (HEXEDIT_INFO *infoPtr, HDC hdc) +{ + HBRUSH hBrush, hSolidBrush = NULL; + RECT rc; + + if (GetWindowLong(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) + hBrush = hSolidBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + else + { + hBrush = (HBRUSH)SendMessage(GetParent(infoPtr->hwndSelf), WM_CTLCOLOREDIT, + (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); + if (!hBrush) + hBrush = hSolidBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); + } + + GetClientRect (infoPtr->hwndSelf, &rc); + + FillRect (hdc, &rc, hBrush); + + if (hSolidBrush) + DeleteObject(hSolidBrush); + + return -1; +} + + +static inline LRESULT +HexEdit_GetFont (HEXEDIT_INFO *infoPtr) +{ + return (LRESULT)infoPtr->hFont; +} + +static inline LRESULT +HexEdit_KeyDown (HEXEDIT_INFO *infoPtr, DWORD key, DWORD flags) +{ + INT nInc = (infoPtr->bFocusHex) ? 1 : 2; + SCROLLINFO si; + + switch (key) + { + case VK_LEFT: + infoPtr->nCaretPos -= nInc; + if (infoPtr->nCaretPos < 0) + infoPtr->nCaretPos = 0; + break; + case VK_RIGHT: + infoPtr->nCaretPos += nInc; + if (infoPtr->nCaretPos > infoPtr->cbData*2) + infoPtr->nCaretPos = infoPtr->cbData*2; + break; + case VK_UP: + if ((infoPtr->nCaretPos - infoPtr->nBytesPerLine*2) >= 0) + infoPtr->nCaretPos -= infoPtr->nBytesPerLine*2; + break; + case VK_DOWN: + if ((infoPtr->nCaretPos + infoPtr->nBytesPerLine*2) <= infoPtr->cbData*2) + infoPtr->nCaretPos += infoPtr->nBytesPerLine*2; + break; + case VK_HOME: + infoPtr->nCaretPos = 0; + break; + case VK_END: + infoPtr->nCaretPos = infoPtr->cbData*2; + break; + case VK_PRIOR: /* page up */ + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE; + GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si); + if ((infoPtr->nCaretPos - (INT)si.nPage*infoPtr->nBytesPerLine*2) >= 0) + infoPtr->nCaretPos -= si.nPage*infoPtr->nBytesPerLine*2; + else + infoPtr->nCaretPos = 0; + break; + case VK_NEXT: /* page down */ + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE; + GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si); + if ((infoPtr->nCaretPos + (INT)si.nPage*infoPtr->nBytesPerLine*2) <= infoPtr->cbData*2) + infoPtr->nCaretPos += si.nPage*infoPtr->nBytesPerLine*2; + else + infoPtr->nCaretPos = infoPtr->cbData*2; + break; + default: + return 0; + } + + HexEdit_UpdateCaret(infoPtr); + HexEdit_EnsureVisible(infoPtr, infoPtr->nCaretPos); + + return 0; +} + + +static inline LRESULT +HexEdit_KillFocus (HEXEDIT_INFO *infoPtr, HWND receiveFocus) +{ + infoPtr->bFocus = FALSE; + DestroyCaret(); + + return 0; +} + + +static inline LRESULT +HexEdit_LButtonDown (HEXEDIT_INFO *infoPtr) +{ + SetFocus(infoPtr->hwndSelf); + + /* FIXME: hittest and set caret */ + + return 0; +} + + +static inline LRESULT HexEdit_NCCreate (HWND hwnd, LPCREATESTRUCT lpcs) +{ + HEXEDIT_INFO *infoPtr; + SetWindowLong(hwnd, GWL_EXSTYLE, + lpcs->dwExStyle | WS_EX_CLIENTEDGE); + + /* allocate memory for info structure */ + infoPtr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HEXEDIT_INFO)); + SetWindowLongPtr(hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize info structure */ + infoPtr->nCaretPos = 0; + infoPtr->hwndSelf = hwnd; + infoPtr->nBytesPerLine = 2; + infoPtr->bFocusHex = TRUE; + infoPtr->bInsert = TRUE; + + return DefWindowProc(infoPtr->hwndSelf, WM_NCCREATE, 0, (LPARAM)lpcs); +} + +static inline LRESULT +HexEdit_SetFocus (HEXEDIT_INFO *infoPtr, HWND lostFocus) +{ + infoPtr->bFocus = TRUE; + + CreateCaret(infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight); + HexEdit_UpdateCaret(infoPtr); + ShowCaret(infoPtr->hwndSelf); + + return 0; +} + + +static inline LRESULT +HexEdit_SetFont (HEXEDIT_INFO *infoPtr, HFONT hFont, BOOL redraw) +{ + TEXTMETRIC tm; + HDC hdc; + HFONT hOldFont = NULL; + LONG i; + RECT rcClient; + + infoPtr->hFont = hFont; + + hdc = GetDC(infoPtr->hwndSelf); + if (infoPtr->hFont) + hOldFont = SelectObject(hdc, infoPtr->hFont); + + GetTextMetrics(hdc, &tm); + infoPtr->nHeight = tm.tmHeight + tm.tmExternalLeading; + + GetClientRect(infoPtr->hwndSelf, &rcClient); + + for (i = 0; ; i++) + { + BYTE *pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, i); + LPTSTR lpszLine = HexEdit_GetLineText(pData, i, 0); + SIZE size; + GetTextExtentPoint32(hdc, lpszLine, lstrlen(lpszLine), &size); + HeapFree(GetProcessHeap(), 0, lpszLine); + HeapFree(GetProcessHeap(), 0, pData); + if (size.cx > (rcClient.right - rcClient.left)) + { + infoPtr->nBytesPerLine = i - 1; + break; + } + } + + if (infoPtr->hFont) + SelectObject(hdc, hOldFont); + ReleaseDC (infoPtr->hwndSelf, hdc); + + if (redraw) + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + +static inline LRESULT +HexEdit_VScroll (HEXEDIT_INFO *infoPtr, INT action) +{ + SCROLLINFO si; + + /* get all scroll bar info */ + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si); + + switch (LOWORD(action)) + { + case SB_TOP: /* user pressed the home key */ + si.nPos = si.nMin; + break; + + case SB_BOTTOM: /* user pressed the end key */ + si.nPos = si.nMax; + break; + + case SB_LINEUP: /* user clicked the up arrow */ + si.nPos -= 1; + break; + + case SB_LINEDOWN: /* user clicked the down arrow */ + si.nPos += 1; + break; + + case SB_PAGEUP: /* user clicked the scroll bar above the scroll thumb */ + si.nPos -= si.nPage; + break; + + case SB_PAGEDOWN: /* user clicked the scroll bar below the scroll thumb */ + si.nPos += si.nPage; + break; + + case SB_THUMBTRACK: /* user dragged the scroll thumb */ + si.nPos = si.nTrackPos; + break; + + default: + break; + } + + /* set the position and then retrieve it to let the system handle the + * cases where the position is out of range */ + si.fMask = SIF_POS; + SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si, TRUE); + GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &si); + + if (si.nPos != infoPtr->nScrollPos) + { + ScrollWindow(infoPtr->hwndSelf, 0, infoPtr->nHeight * (infoPtr->nScrollPos - si.nPos), NULL, NULL); + infoPtr->nScrollPos = si.nPos; + UpdateWindow(infoPtr->hwndSelf); + + /* need to update caret position since it depends on the scroll position */ + HexEdit_UpdateCaret(infoPtr); + } + return 0; +} + + +static LRESULT WINAPI +HexEdit_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HEXEDIT_INFO *infoPtr = (HEXEDIT_INFO *)GetWindowLongPtr (hwnd, 0); + + if (!infoPtr && (uMsg != WM_NCCREATE)) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case HEM_SETDATA: + return HexEdit_SetData (infoPtr, (INT)wParam, (const BYTE *)lParam); + + case HEM_GETDATA: + return HexEdit_GetData (infoPtr, (INT)wParam, (BYTE *)lParam); + + case WM_CHAR: + return HexEdit_Char (infoPtr, (TCHAR)wParam); + + case WM_CREATE: + return HexEdit_Create (infoPtr, (LPCREATESTRUCT)lParam); + + case WM_DESTROY: + return HexEdit_Destroy (infoPtr); + + case WM_ERASEBKGND: + return HexEdit_EraseBackground (infoPtr, (HDC)wParam); + + case WM_GETDLGCODE: + return DLGC_WANTCHARS | DLGC_WANTARROWS; + + case WM_GETFONT: + return HexEdit_GetFont (infoPtr); + + case WM_KEYDOWN: + return HexEdit_KeyDown (infoPtr, wParam, lParam); + + case WM_KILLFOCUS: + return HexEdit_KillFocus (infoPtr, (HWND)wParam); + + case WM_LBUTTONDOWN: + return HexEdit_LButtonDown (infoPtr); + + case WM_NCCREATE: + return HexEdit_NCCreate (hwnd, (LPCREATESTRUCT)lParam); + + case WM_PAINT: + HexEdit_Paint(infoPtr); + return 0; + + case WM_SETFOCUS: + return HexEdit_SetFocus (infoPtr, (HWND)wParam); + + case WM_SETFONT: + return HexEdit_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); + + case WM_VSCROLL: + return HexEdit_VScroll (infoPtr, (INT)wParam); + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + return 0; +} + +void HexEdit_Register() +{ + WNDCLASS wndClass; + + ZeroMemory(&wndClass, sizeof(WNDCLASS)); + wndClass.style = 0; + wndClass.lpfnWndProc = HexEdit_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(HEXEDIT_INFO *); + wndClass.hCursor = NULL; + wndClass.hbrBackground = NULL; + wndClass.lpszClassName = HEXEDIT_CLASS; + + RegisterClass(&wndClass); +} + + +void HexEdit_Unregister() +{ + UnregisterClass(HEXEDIT_CLASS, NULL); +} diff --git a/programs/regedit/main.c b/programs/regedit/main.c index 97f38a3169..93752793ee 100644 --- a/programs/regedit/main.c +++ b/programs/regedit/main.c @@ -110,6 +110,9 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) /* Initialize the Windows Common Controls DLL */ InitCommonControls(); + /* register our hex editor control */ + HexEdit_Register(); + nClipboardFormat = RegisterClipboardFormat(strClipboardFormat); /* if (nClipboardFormat == 0) { DWORD dwError = GetLastError(); diff --git a/programs/regedit/main.h b/programs/regedit/main.h index fc6837310c..24719ea28b 100644 --- a/programs/regedit/main.h +++ b/programs/regedit/main.h @@ -39,6 +39,11 @@ #define WM_NOTIFY_REFLECT (WM_USER+1024) +/* HexEdit Class */ +#define HEXEDIT_CLASS TEXT("HexEdit") +#define HEM_SETDATA (WM_USER+0) +#define HEM_GETDATA (WM_USER+1) + extern HINSTANCE hInst; /******************************************************************************/ @@ -118,4 +123,8 @@ extern BOOL DeleteValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPCTSTR value extern BOOL RenameValue(HWND hwnd, HKEY hRootKey, LPCTSTR keyPath, LPCTSTR oldName, LPCTSTR newName); extern BOOL RenameKey(HWND hwnd, HKEY hRootKey, LPCTSTR keyPath, LPCTSTR newName); +/* hexedit.c */ +extern void HexEdit_Register(void); +extern void HexEdit_Unregister(void); + #endif /* __MAIN_H__ */ diff --git a/programs/regedit/resource.h b/programs/regedit/resource.h index af6f6563e4..d22b4238e0 100644 --- a/programs/regedit/resource.h +++ b/programs/regedit/resource.h @@ -124,5 +124,6 @@ #define IDD_EDIT_STRING 2000 #define IDC_VALUE_NAME 2001 #define IDC_VALUE_DATA 2002 +#define IDD_EDIT_BINARY 2003 #define IDC_STATIC -1 -- 2.32.0.93.g670b81a890