- Add neutral English resources.
authorRobert Shearman <rob@codeweavers.com>
Thu, 14 Apr 2005 11:30:31 +0000 (11:30 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Thu, 14 Apr 2005 11:30:31 +0000 (11:30 +0000)
- Add a control for editing binary data.
- Add a binary value editor dialog.

programs/regedit/En.rc
programs/regedit/Makefile.in
programs/regedit/edit.c
programs/regedit/hexedit.c [new file with mode: 0644]
programs/regedit/main.c
programs/regedit/main.h
programs/regedit/resource.h

index 813daceaee00ff23999fcec13250f967f4b93a6f..7165e450295cfe87735da1e23aede76114dd4a93 100644 (file)
  * 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
  */
index 7d54c28ad52a5e9cb6021d76d75c44c92c534d1c..0d5449ea6a7af176ee958c21977acadecbb212c1 100644 (file)
@@ -14,6 +14,7 @@ C_SRCS = \
        childwnd.c \
        edit.c \
        framewnd.c \
+       hexedit.c \
        listview.c \
        main.c \
        regedit.c \
index 01305e8b03c48582127a5f4090863d50f737052f..396fec96434625b2de49e2a77ba3ce03bb61d236 100644 (file)
@@ -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)&params);
     } else {
         error(hwnd, IDS_UNSUPPORTED_TYPE, type);
     }
diff --git a/programs/regedit/hexedit.c b/programs/regedit/hexedit.c
new file mode 100644 (file)
index 0000000..9cbf85c
--- /dev/null
@@ -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 <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#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);
+}
index 97f38a316988e2a2cdb3fae2e3135fe2cc289a77..93752793eef23cbb545fd2f91c993cab7b0d05d1 100644 (file)
@@ -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();
index fc6837310c8356edd818b161f14c17d249a5abd9..24719ea28befb8f2834efe74e90ee63c9a428f5d 100644 (file)
 
 #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__ */
index af6f6563e4f28ff24ccb8a3718413bc740270858..d22b4238e06f95bfa0eaba8e155f433c3e4bfb19 100644 (file)
 #define IDD_EDIT_STRING                        2000
 #define IDC_VALUE_NAME                 2001
 #define IDC_VALUE_DATA                 2002
+#define IDD_EDIT_BINARY                        2003
 
 #define IDC_STATIC                      -1