Hab nen nützlichen ShowMemory-Dialog geschrieben



  • Moin Leudde,
    manchmal stößt man beim Programmieren auf das Problem, dass man gerne wissen möchte, was so in einem bestimmten Speicherbereich steht. Ich habe nun etwas programmiert, das dieses Problem beseitigt. Wenn man die Header eingebunden hat, muss man nur noch

    ShowMemory(hwnd, addr1, addr2);
    

    schreiben, und es öffnet sich ein netter Dialog, in dem der Speicherblock von addr1 bis addr2 wie in nem Hex-Editor "visualisiert" ist. Was ihr dazu braucht, ist erstmal die Unit "DynDialogs" aus der FAQ. Weiterhin noch folgende Unit "Fonts":

    //   Headerdatei: Fonts.h
    //---------------------------------------------------------------------------
    #ifndef FontsH
    #define FontsH
    //---------------------------------------------------------------------------
    #include <windows.h>
    //---------------------------------------------------------------------------
    
    // Definitions of font formats used in SetFont()
    #define  FF_NORMAL     0
    #define  FF_BOLD       2
    #define  FF_ITALIC     4
    #define  FF_UNDERLINE  8
    #define  FF_STRIKEOUT  16
    //---------------------------------------------------------------------------
    
    HFONT  BuildFont(LPCTSTR lpszName, INT iSize, WORD wFontFormat);
    HFONT  SetFont(HWND hwnd, LPCTSTR lpszName, INT iSize, WORD wFontFormat);
    VOID   SetFont(HWND hwnd, HFONT hFont);
    //---------------------------------------------------------------------------
    #endif
    
    //  Die Implementierung: Fonts.cpp
    //---------------------------------------------------------------------------
    #include "Fonts.h"
    //---------------------------------------------------------------------------
    
    HFONT BuildFont(LPCTSTR lpszName, INT iSize, WORD wFontFormat)
    {
       BOOL   bBold, bIt, bUl, bStrikeout;
       INT    iWeight;
       HFONT  hFont;
    
       bBold       = wFontFormat & FF_BOLD;
       bIt         = wFontFormat & FF_ITALIC;
       bUl         = wFontFormat & FF_UNDERLINE;
       bStrikeout  = wFontFormat & FF_STRIKEOUT;
       iWeight     = bBold ? FW_BOLD : FW_NORMAL;
    
       hFont =  CreateFont(-MulDiv(iSize, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72),
                           0, 0, 0, iWeight, bIt, bUl, bStrikeout, ANSI_CHARSET,
                           OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
                           DEFAULT_PITCH, lpszName);
       return hFont;
    }
    //---------------------------------------------------------------------------
    
    HFONT SetFont(HWND hwnd, LPCTSTR lpszName, INT iSize, WORD wFontFormat)
    {
       HFONT hFont = BuildFont(lpszName, iSize, wFontFormat);
       SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont, 0);
       return hFont;
    }
    //---------------------------------------------------------------------------
    
    VOID SetFont(HWND hwnd, HFONT hFont)
    {
       SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont, 0);
    }
    //---------------------------------------------------------------------------
    

    So. Da für das Anzeigen eines ShowMemory-Dialoges einige Funktionen nötig sind, habe ich sie alle wiederum in eine neue Unit gepackt. Hier ist sie:

    //   Die Headerdatei: MemoryDialog.h
    //---------------------------------------------------------------------------
    #ifndef MemoryDialogH
    #define MemoryDialogH
    //---------------------------------------------------------------------------
    
    // Definitions of dialog control IDs
    #define  ID_GROUP          10
    #define  ID_STATIC_FROM    11
    #define  ID_STATIC_TO      12
    #define  ID_EDIT_FROM      13
    #define  ID_EDIT_TO        14
    #define  ID_BUTTON_SHOW    15
    #define  ID_BUTTON_SAVE    16
    #define  ID_EDIT_MEMORY    17
    //---------------------------------------------------------------------------
    
    LRESULT ShowMemory(HWND hwnd, BYTE* addr_from, BYTE* addr_to);
    BOOL    TestValues(DWORD dwFrom, DWORD dwTo);
    DWORD   HexToInt(unsigned char* buf, INT digits);
    VOID    DisplayMemory(HWND hDlg, DWORD dwFrom, DWORD dwTo);
    CHAR*   FillLines(DWORD dwFrom, DWORD dwTo);
    VOID    SaveToFile(HWND hDlg, DWORD dwFrom, DWORD dwTo);
    
    BOOL  CALLBACK  ShowMemDlgProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
    //---------------------------------------------------------------------------
    #endif
    
    //   Die Implementierung: MemoryDialog.cpp
    //---------------------------------------------------------------------------
    #include <windows.h>
    #include <stdio.h>
    #include "MemoryDialog.h"
    #include "DynDialogs.h"
    #include "Fonts.h"
    //---------------------------------------------------------------------------
    
    LRESULT ShowMemory(HWND hwnd, BYTE* addr_from, BYTE* addr_to)
    {
       LRESULT  ret;
       HGLOBAL  hgbl;
       LPWORD   lpw;
       DWORD    dwFrom, dwTo, style;
       CHAR     caption[256] = "";
       CHAR     str_from[10];
       CHAR     str_to[10];
    
       // Convert pointers to DWORD
       dwFrom = (DWORD)addr_from;
       dwTo   = (DWORD)addr_to;
    
       // Test if values are valid
       if( !TestValues(dwFrom, dwTo) )
       {
          ShowMessage(hwnd, "Addresses are not valid", "ERROR", SM_ERROR);
          return NULL;
       }
    
       // store addresses in strings and setup caption
       wsprintf(str_from, "%.8X", dwFrom);
       wsprintf(str_to, "%.8X", dwTo);
       wsprintf(caption, "Memory from %s to %s", str_from, str_to);
    
       // Allocate some memory for dialog data
       hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
       if(!hgbl)
          return NULL;
       LPVOID lpv = GlobalLock(hgbl);
    
       // Prepare the dialog box
       style = DS_SETFONT | DS_CENTER | DS_3DLOOK | DS_MODALFRAME | WS_SYSMENU | WS_CAPTION | WS_VISIBLE;
       lpw = InitDialog(lpv, caption, style, 8, "MS Sans Serif", 8, 0, 0, 386, 305);
    
       // GroupBox
       style = WS_CHILD | WS_VISIBLE | BS_GROUPBOX;
       lpw = CreateDlgControl(lpw, BUTTON_CLASS, ID_GROUP, "Options", style,
                              0, 0, 386, 60);
    
       // Static From
       style = WS_CHILD | WS_VISIBLE | SS_LEFT;
       lpw = CreateDlgControl(lpw, STATIC_CLASS, ID_STATIC_FROM, "First Byte Address", style,
                              6, 16, 80, 10);
    
       // Static To
       lpw = CreateDlgControl(lpw, STATIC_CLASS, ID_STATIC_TO, "Last Byte Address", style,
                              160, 16, 80, 10);
    
       // Edit From
       style = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP;
       lpw = CreateDlgControl(lpw, EDIT_CLASS, ID_EDIT_FROM, str_from, style,
                              68, 14, 80, 13);
    
       // Edit To
       lpw = CreateDlgControl(lpw, EDIT_CLASS, ID_EDIT_TO, str_to, style,
                              227, 14, 80, 13);
    
       // Button Show
       style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP;
       lpw = CreateDlgControl(lpw, BUTTON_CLASS, ID_BUTTON_SHOW, "Show", style,
                              329, 14, 51, 16);
    
       // Button Save
       lpw = CreateDlgControl(lpw, BUTTON_CLASS, ID_BUTTON_SAVE, "Save To File", style,
                              227, 37, 153, 16);
    
       // Edit Memory
       style = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP
               | ES_READONLY | ES_MULTILINE | ES_WANTRETURN;
       lpw = CreateDlgControl(lpw, EDIT_CLASS, ID_EDIT_MEMORY, "", style,
                              0, 61, 386, 244);
    
       GlobalUnlock(hgbl);
       DWORD data[2] = {(DWORD)addr_from, (DWORD)addr_to};
       ret = DialogBoxIndirectParam(NULL, (LPDLGTEMPLATE)hgbl, hwnd,
                                    (DLGPROC)ShowMemDlgProc, (LPARAM)(DWORD)data);
       GlobalFree(hgbl);
       return ret;
    }
    //---------------------------------------------------------------------------
    
    BOOL TestValues(DWORD dwFrom, DWORD dwTo)
    {
       if(dwFrom > dwTo)
          return FALSE;
    
       if(dwFrom == 0  ||  dwTo == 0)
          return FALSE;
    
       return TRUE;
    }
    //---------------------------------------------------------------------------
    
    DWORD HexToInt(unsigned char* buf, INT n)
    {
       INT retVal;
       INT i;
    
       UINT* digits = new UINT[n];
       n = n - 1;
    
       // Den String "übersetzen"
       for(i = 0; i <= n; i++)
       {
          if(buf[n-i] < 48  || (buf[n-i] > 57  &&  buf[n-i] < 65)  ||  buf[n-i] > 70)
             return 0;
          if(buf[n-i] >= 48  && buf[n-i] <= 57)
             digits[i] = buf[n-i] - 48;
          if(buf[n-i] >= 65  && buf[n-i] <= 70)
             digits[i] = buf[n-i] - 55;
       }
    
       retVal = digits[n];
       for(i = 1; i <= n; i++)
          retVal = digits[n-i] + 16 * retVal;
    
       delete[] digits;
       return (DWORD)retVal;
    }
    //---------------------------------------------------------------------------
    
    VOID DisplayMemory(HWND hDlg, DWORD dwFrom, DWORD dwTo)
    {
       CHAR* lines = FillLines(dwFrom, dwTo);
       if(lines)
       {
          SetDlgItemText(hDlg, ID_EDIT_MEMORY, lines);
          delete[] lines;
       }
    }
    //---------------------------------------------------------------------------
    
    CHAR* FillLines(DWORD dwFrom, DWORD dwTo)
    {
       // We need 61 characters per line:
       // 8 for address offset
       // 3 free ones (spaces)
       // 16 units of BYTE values with the following format:
       //       1 Space (' ')
       //       2 hex digits
       // 2 for a carriage return (i.e. "
    ")
       // Thus: 8 + 3 + 16 * 3 + 2  =  61
       DWORD row;
       DWORD rows = (dwTo - dwFrom) / 16 + 1;
       DWORD dwFromInRow, dwToInRow, addr;
       CHAR* ptr;
       CHAR* lines = new CHAR[rows * 61 + 1];
    
       for(row = 0; row < rows; row++)
       {
          // First position in row
          ptr = lines + row * 61;
    
          // Write address offset to beginning
          dwFromInRow = dwFrom + 16 * row;
          wsprintf(ptr, "%.8X   ", dwFromInRow);
    
          // Set pointer to right position
          ptr += 11;
    
          // Determine number of bytes in row
          dwToInRow = dwFromInRow + 16;
          dwToInRow = (dwTo < dwToInRow) ? (dwTo + 1) : dwToInRow;
    
          // Write the byte into the line
          for(addr = dwFromInRow; addr < dwToInRow; addr++)
          {
             // Writes "_XX" to ptr position
             wsprintf(ptr, " %.2X", *(BYTE*)addr);
             ptr += 3;
          }
    
          // A carriage return in every except the last line
          if(row < rows - 1)
          {
             *ptr       = '
    ';
             *(ptr + 1) = '
    ';
          }
       }
    
       // Terminate the whole string by NULL
       ptr = '';
       return lines;
    }
    //---------------------------------------------------------------------------
    
    VOID SaveToFile(HWND hDlg, DWORD dwFrom, DWORD dwTo)
    {
       DWORD rows = (dwTo - dwFrom) / 16 + 1;
       DWORD characters = rows * 61 + 1;   // Every row contains 61 characters
    
       OPENFILENAME ofn;
       CHAR lpszFileName[MAX_PATH];
       lpszFileName[0] = '';
    
       ofn.lStructSize       = sizeof(OPENFILENAME) ;
       ofn.hwndOwner         = hDlg;
       ofn.hInstance         = NULL;
       ofn.lpstrFilter       = TEXT("TXT-Files (*.txt)*.txt");
       ofn.lpstrCustomFilter = NULL;
       ofn.nMaxCustFilter    = 0;
       ofn.nFilterIndex      = 0;
       ofn.lpstrFile         = lpszFileName;
       ofn.nMaxFile          = MAX_PATH;
       ofn.lpstrFileTitle    = NULL;
       ofn.nMaxFileTitle     = 0;
       ofn.lpstrInitialDir   = NULL;
       ofn.lpstrTitle        = NULL;
       ofn.Flags             = OFN_HIDEREADONLY;
       ofn.nFileOffset       = 0;
       ofn.nFileExtension    = 0;
       ofn.lpstrDefExt       = TEXT("txt");
       ofn.lCustData         = 0L;
       ofn.lpfnHook          = NULL;
       ofn.lpTemplateName    = NULL;
    
       if( !GetSaveFileName(&ofn) )
          return;
    
       CHAR* buf = new CHAR[characters];
       GetDlgItemText(hDlg, ID_EDIT_MEMORY, buf, characters);
    
       FILE *file = fopen(lpszFileName, "wt");
       if(file)
          fwrite((void*)buf, 1, characters, file);
       fclose(file);
    
       delete[] buf;
    }
    //---------------------------------------------------------------------------
    
    BOOL CALLBACK ShowMemDlgProc(HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
    {
       static HFONT hDlgFont, hEditMemFont;
       static DWORD dwFrom, dwTo;
    
       switch(uiMsg)
       {
          case WM_INITDIALOG:
          {
             hEditMemFont = SetFont( GetDlgItem(hDlg, ID_EDIT_MEMORY), "Courier New",
                                     10, FF_NORMAL);
    
             DWORD* data = (DWORD*)lParam;
             dwFrom = data[0];
             dwTo   = data[1];
             DisplayMemory(hDlg, dwFrom, dwTo);
    
             SendMessage( hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)LoadIcon(NULL, IDI_APPLICATION) );
             SetFocus( GetDlgItem(hDlg, ID_BUTTON_SHOW) );
             return FALSE;
          }
    
          case WM_SETFONT:
             hDlgFont = (HFONT)wParam;  // store HFONT for deletion when closed
             return TRUE;
    
          case WM_CLOSE:
             EndDialog(hDlg, IDCANCEL);
             DeleteObject(hEditMemFont);
             DeleteObject(hDlgFont);
             return TRUE;
    
          case WM_COMMAND:
          {
             switch(LOWORD(wParam))  // which ID?
             {
                case ID_BUTTON_SHOW:
                {
                   char buf[256];
    
                   GetDlgItemText(hDlg, ID_EDIT_FROM, buf, 256);
                   if(strlen(buf) != 8)
                      ShowMessage(hDlg, "Please use 8 digits for an address", "ERROR", SM_ERROR);
                   dwFrom = HexToInt((unsigned char*)buf, 8);
    
                   GetDlgItemText(hDlg, ID_EDIT_TO, buf, 256);
                   if(strlen(buf) != 8)
                      ShowMessage(hDlg, "Please use 8 digits for an address", "ERROR", SM_ERROR);
                   dwTo   = HexToInt((unsigned char*)buf, 8);
    
                   if( !TestValues(dwFrom, dwTo) )
                   {
                      ShowMessage(hDlg, "Addresses are not valid", "ERROR", SM_ERROR);
                      return TRUE;
                   }
    
                   DisplayMemory(hDlg, dwFrom, dwTo);
                   return TRUE;
                }
    
                case ID_BUTTON_SAVE:
                   SaveToFile(hDlg, dwFrom, dwTo);
                   return TRUE;
             }
          }
       }
    
       return FALSE;
    }
    //---------------------------------------------------------------------------
    


  • Glaube zwar das das nicht wirklich jemand braucht, aber trotzdem danke. :p



  • Wie wäre es, wenn du das ganze in kompilierter Form als Download anbietest? 🙄



  • Das ist es ja gerade. Man kann das nicht kompilieren. Es ist ja keine EXE, sondern einfach nur eine Funktion. Es ist ja auch nur ein "Tool", um beim Programmieren eine Erleichterung zu haben. Ich hatte das mal für mich in VCL gemacht. Das ging natürlich viel schneller zu machen als die WinAPI-Version. Ich hatte das Ganze in ne Klasse gepackt, und diese hat mir echt schon oftmals geholfen. Es ist einfach praktisch!



  • er wollte das so, das es auch in delphi benutzbar ist



  • aber was soll das bringen? das kann man doch viel besser im debugger machen?!



  • Mir bringt es was. Und ich kann mir denken, dass es auch anderen hilft. Deshalb habe ich es gepostet. Ganz einfach.



  • stell das auf deine homepage. hab kein bock das aus den einzelnen dateien rauszukopieren.



  • Was ist "DynDialogs.h" und was hat ShowMessage dazu suchen? 😡

    und noch vieles mehr...



  • @<klar>: Dann brauchst du das Tool auch nicht wirklich!

    Original erstellt von <master>:
    Was ist "DynDialogs.h" und was hat ShowMessage dazu suchen? 😡

    Ich habe oben erwähnt, was DynDialogs.h ist. Bekommst du in der FAQ. "ShowMessage" ist in DynDialogs enthalten. DynDialogs ist eine Unit, die es einem ermöglicht, dynamisch (ohne Resource) einen Dialog zu erzeugen. Ist sehr praktisch.



  • ok tschuldigung hab ich irgendwie überlesen. aber da muss man trotzdem noch einiges überarbeites. du hast die konstanten in der cpp datei, die müssen aber in den header. also das

    // Input-Box-Childs
    #define  ID_INPUT     200
    #define  ID_INFOTEXT  201
    
    // Control Classes
    #define  BUTTON_CLASS       0x0080
    #define  EDIT_CLASS         0x0081
    #define  STATIC_CLASS       0x0082
    #define  LISTBOX_CLASS      0x0083
    #define  SCROLLBAR_CLASS    0x0084
    #define  COMBOBOX_CLASS     0x0085
    
    // Definitions of icon representations in ShowMessage()
    #define  SM_NONE       0
    #define  SM_WARNING    1
    #define  SM_INFO       2
    #define  SM_ERROR      3
    


  • ok, habe es irgendwie noch zum laufen bekommen :p
    aber stürzt ab:

    wsprintf(ptr, " %.2X", (BYTE)addr);

    und den dialog rufe ich so auf

    ShowMemory(NULL, (BYTE*)0x40000000, (BYTE*)0x41000000);

    ist der aufruf falsch?



  • Der macht ja auch die gefährlichsten Sachen mit seinem ptr.



  • @<master>: Schön, dass du dir das mal anschaust. Mit den Konstanten haste recht. Hab ich hier zu Hause auch so, aber hab vergessen, das in der FAQ zu ändern. Sorry. Wird sofort nachgeholt.
    Du kannst natürlich nicht einfach willkührliche Werte für addr_from und addr_to eingeben. Den Speicherbereich zwischen addr_from und addr_to musst du schon für dich allokiert haben. Also z.B. sowas:

    char hallo[10] = "Hallo";
    ShowMemory(hwnd, (BYTE*)hallo, (BYTE*)(hallo + 4);
    

Anmelden zum Antworten