Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

UDTView debug utility for viewing UDT members

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • UDTView debug utility for viewing UDT members

    This is a simple utility that demonstrates one approach to the issue of looking at members of a UDT when debugging a program.

    It simply consists of a DLL you load into your program ... you simply call the UDT_Init function, giving it the name of the UDT you want to look at as well as the filename it resides in.

    Then whenever you want to have a look at the UDT simply call UDT_Update from your code.

    When calling UDT_Update you provide the address of the UDT, so you can give it the address of any member of a UDT array, such as VARPTR(MyUDT(3)).

    It doesn't support viewing nested UDTs although it will show the address of those UDTs, but it DOES support arrays inside the UDT. It simply expands them. For example, "bBytes(2) AS BYTE" will become:
    bBytes(0) AS BYTE
    bBytes(1) AS BYTE
    bBytes(2) AS BYTE

    Consider for example the following simple UDT ...
    TYPE MyUDT
    xString AS STRING * 15
    xAsciiz AS ASCIIZ * 20
    xByte AS BYTE
    xDword AS DWORD
    END TYPE


    And then initialised with some dummy data ...
    UDT.xString = "Im a string"
    UDT.xAsciiz = "Im an asciiz"
    UDT.xByte = &h69
    UDT.xDword = &hA0A1A2A3


    UDTView shows it like this:



    udtview.bas
    Code:
    #PBFORMS CREATED V1.51
    #COMPILE DLL "udtview.dll"
    
    #INCLUDE "WIN32API.INC"
    #INCLUDE "COMMCTRL.INC"
    #INCLUDE "PBForms.INC"
    
    #PBFORMS BEGIN CONSTANTS
    %DIALOG1         =  101
    %LISTVIEW        = 1002
    #PBFORMS END CONSTANTS
    
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    #PBFORMS DECLARATIONS
    
    GLOBAL hDlg1 AS DWORD, hList AS DWORD, ListItems AS DWORD
    GLOBAL gBASFile AS STRING, gUDTName AS STRING, gUDTAddr AS DWORD, gUDTSize AS DWORD
    
    TYPE Var
     szName AS ASCIIZ * 128
     szType AS ASCIIZ * 20
     wLen AS WORD
    END TYPE
    GLOBAL Vars() AS Var
    
    SUB AdjustListviewHeaders
     LOCAL i AS DWORD
     ListView_SetColumnWidth(hList, 0, %LVSCW_AUTOSIZE)
     FOR i = 1 TO 4: ListView_SetColumnWidth(hList, i, %LVSCW_AUTOSIZE_USEHEADER): NEXT
    END SUB
    
    SUB AddToList(sName AS STRING, sType AS STRING, BYVAL dwLen AS DWORD, BYVAL dwAddr AS DWORD, sData AS STRING)
      LOCAL tLVI   AS LV_ITEM, szBuf AS ASCIIZ * 2048
      REDIM PRESERVE Vars(ListItems+1) AS Var
      Vars(ListItems).szName = sName
      Vars(ListItems).szType = sType
      Vars(ListItems).wLen = dwLen
      tLVI.stateMask = %LVIS_FOCUSED
      tLVI.pszText   = VARPTR(szBuf)
      tLVI.iItem     = ListItems
      szBuf         = sName
        tLVI.iSubItem = 0:  tLVI.lParam   = ListItems
        tLVI.mask = %LVIF_TEXT OR %LVIF_PARAM OR %LVIF_STATE
        ListView_InsertItem(hList, tLVI)
      szBuf         = sType
        tLVI.iSubItem = 1:  tLVI.lParam   = ListItems
        tLVI.mask = %LVIF_TEXT
        ListView_SetItem(hList, tLVI)
      szBuf         = TRIM$(STR$(dwLen))
        tLVI.iSubItem = 2:  tLVI.lParam   = ListItems
        tLVI.mask = %LVIF_TEXT
        ListView_SetItem(hList, tLVI)
      szBuf         = HEX$(dwAddr,8)
        tLVI.iSubItem = 3:  tLVI.lParam   = ListItems
        tLVI.mask = %LVIF_TEXT
        ListView_SetItem(hList, tLVI)
      szBuf         = sData
        tLVI.iSubItem = 3:  tLVI.lParam   = ListItems
        tLVI.mask = %LVIF_TEXT
        ListView_SetItem(hList, tLVI)
      INCR ListItems
    END SUB
    
    
    FUNCTION VarOffset(BYVAL dwVar AS DWORD) AS DWORD
    LOCAL I AS DWORD, dwOffset AS DWORD
    IF dwVar = 0 THEN EXIT FUNCTION
    FOR i = 0 TO dwVar - 1
        dwOffset = dwOffset + Vars(i).wLen
    NEXT i
    FUNCTION = dwOffset
    END FUNCTION
    
    
    SUB UDT_Update ALIAS "UDT_Update" (BYVAL dwUDTAddr AS DWORD, BYVAL idx AS DWORD) EXPORT
      LOCAL tLVI   AS LV_ITEM, szBuf AS ASCIIZ * 2048, i AS DWORD
      LOCAL bPtr AS BYTE PTR, dwPtr AS DWORD PTR, szPtr AS ASCIIZ PTR, wPtr AS WORD PTR, dwOffset AS DWORD, qPtr AS DOUBLE PTR
      gUDTAddr = dwUDTAddr
      DIALOG SET TEXT hDlg1, "UDTView - Viewing " & gUDTName & "(" & TRIM$(STR$(idx)) & ") at 0x" & HEX$(gUDTAddr,8)
      tLVI.stateMask = %LVIS_FOCUSED
      tLVI.pszText   = VARPTR(szBuf)
      FOR i = 0 TO ListItems - 1
        szBuf = ""
        tLVI.iItem    = i
        SELECT CASE Vars(i).szType
            CASE "STRING", "ASCIIZ":
                dwOffset = gUDTAddr + VarOffset(BYVAL i)
                szBuf = PEEK$(dwOffset, Vars(i).wLen)
            CASE "ASCIIZ PTR", "ASCIZ PTR", "STRING PTR":
                dwPtr = gUDTAddr + VarOffset(BYVAL i)
                szBuf = "0x" & HEX$(dwPtr,8) & ": " & PEEK$(@dwPtr,4) & "..."
                dwOffset = dwPtr
            CASE ELSE:
                SELECT CASE Vars(i).wLen
                    CASE 1: bPtr = gUDTAddr + VarOffset(BYVAL i): dwOffset = bPtr
                            szBuf = "0x" & HEX$(@bPtr,2) & "  (" & TRIM$(STR$(@bPtr)) & ")"
                    CASE 2: wPtr = gUDTAddr + VarOffset(BYVAL i): dwOffset = wPtr
                            szBuf = "0x" & HEX$(@wPtr,4) & "  (" & TRIM$(STR$(@wPtr)) & ")"
                    CASE 4: dwPtr = gUDTAddr + VarOffset(BYVAL i): dwOffset = dwPtr
                            szBuf = "0x" & HEX$(@dwPtr,8) & "  (" & TRIM$(STR$(@dwPtr)) & ")"
                    CASE ELSE: dwPtr = gUDTAddr + VarOffset(BYVAL i): dwOffset = dwPtr
                            szBuf = "0x" & HEX$(dwPtr,8)
                END SELECT
        END SELECT
        tLVI.iSubItem = 4 'lCol
        tLVI.lParam   = i
        tLVI.mask = %LVIF_TEXT
        ListView_SetItem(hList, tLVI)
        szBuf = HEX$(dwOffset,8)
        tLVI.iSubItem = 3 'lCol
        tLVI.lParam   = i
        tLVI.mask = %LVIF_TEXT
        ListView_SetItem(hList, tLVI)
      NEXT i
    END SUB
    
    SUB LoadUDT
     LOCAL hFile AS DWORD, sBuf AS STRING, lUDT AS STRING, sVar AS STRING, sFullType AS STRING, sType AS STRING, dwLen AS DWORD, i AS DWORD, dwCnt AS DWORD
     lUDT = LCASE$(gUDTName)
     hFile = FREEFILE
     OPEN gBASFile FOR INPUT AS #hFile
     DO UNTIL EOF(hFile)
         LINE INPUT #hFile, sBuf
         IF UCASE$(LEFT$(sBuf,5)) = "TYPE " THEN
             sBuf = TRIM$(sBuf)
             REPLACE "  " WITH " " IN sBuf
             IF LCASE$(sBuf) = "type " & lUDT THEN
                 DO
                     LINE INPUT #hFile, sBuf
                     sBuf = TRIM$(sBuf)
                     IF sBuf = "" THEN ITERATE
                     IF UCASE$(sBuf) = "END TYPE" THEN GOTO UDTLoaded
                     sVar = LEFT$(sBuf, INSTR(1, sBuf, " ") - 1)
                     IF INSTR(1, sBuf, "'") > 0 THEN
                        sBuf = LEFT$(sBuf, INSTR(1, sBuf, "'") - 1)
                        sBuf = RTRIM$(sBuf)
                     END IF
                     sBuf = UCASE$(sBuf)
                     i = INSTR(1, sBuf, " AS ") + 4
                     sFullType = RIGHT$(sBuf, LEN(sBuf) - i + 1)
                     sType = sFulltype
                     IF INSTR(1, sType, " ") > 0 THEN sType = LEFT$(sType, INSTR(1, sType, " ") - 1)
                     IF RIGHT$(sFulltype,4) = " PTR" OR RIGHT$(sFulltype,8) = " POINTER" THEN
                         sType = sFulltype
                         dwLen = 4
                     ELSE
                         SELECT CASE sType
                             CASE "STRING", "ASCIIZ", "ASCIZ": dwLen = VAL( RIGHT$(sFulltype, LEN(sFulltype) - INSTR(-1, sFulltype, "*") - 1) )
                             CASE "BYTE": dwLen = 1
                             CASE "INTEGER", "WORD": dwLen = 2
                             CASE "DWORD", "LONG", "SINGLE": dwLen = 4
                             CASE "QUAD", "DOUBLE", "CURRENCY", "CURRENCYX", "CUR", "CURX": dwLen = 8
                             CASE "EXT", "EXTENDED": dwLen = 10
                             CASE ELSE: dwLen = 4
                         END SELECT
                     END IF
                     IF LEN(sType) > 19 THEN sType = LEFT$(sType, 19) & ".."
                     IF INSTR(1, sVar, "(") > 0 THEN
                         sVar = LEFT$(sVar, LEN(sVar) - 1)
                         dwCnt = VAL(RIGHT$(sVar, LEN(sVar) - INSTR(1, sVar, "(")))
                         sVar = LEFT$(sVar, INSTR(1, sVar, "("))
                         FOR i = 0 TO dwCnt
                             AddToList sVar & TRIM$(STR$(i)) & ")", sType, BYVAL dwLen, BYVAL 0, ""
                         NEXT i
                     ELSE
                         AddToList sVar, sType, BYVAL dwLen, BYVAL 0, ""
                     END IF
                 LOOP
             END IF
         END IF
     LOOP
    UDTLoaded:
     CLOSE #hFile
     UDT_Update BYVAL gUDTAddr, BYVAL 0
     AdjustListviewHeaders
    END SUB
    
    FUNCTION LIBMAIN(BYVAL hInstance   AS LONG, _
                     BYVAL fwdReason   AS LONG, _
                     BYVAL lpvReserved AS LONG) EXPORT AS LONG
      IF fwdReason = %DLL_PROCESS_ATTACH THEN
           PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR %ICC_INTERNET_CLASSES)
      END IF
      FUNCTION = 1
    END FUNCTION
    
    SUB CreateListHeaders
        LOCAL lCol   AS LONG
        LOCAL hCtl   AS DWORD
        LOCAL tLVC   AS LV_COLUMN
        LOCAL tLVI   AS LV_ITEM
        LOCAL szBuf  AS ASCIIZ * 32
        LOCAL lStyle AS LONG
        lStyle = ListView_GetExtendedListViewStyle(hList)
        ListView_SetExtendedListViewStyle(hList, lStyle OR %LVS_EX_FULLROWSELECT _
            OR %LVS_EX_GRIDLINES)
        tLVC.mask    = %LVCF_FMT OR %LVCF_TEXT OR %LVCF_SUBITEM
        tLVC.fmt     = %LVCFMT_LEFT
        tLVC.pszText = VARPTR(szBuf)
        szBuf = "Name":   tLVC.iOrder = 0
        ListView_InsertColumn(hList, 0, tLVC)
        szBuf = "Type":   tLVC.iOrder = 1
        ListView_InsertColumn(hList, 1, tLVC)
        szBuf = "Len":    tLVC.iOrder = 2
        ListView_InsertColumn(hList, 2, tLVC)
        szBuf = "Address":   tLVC.iOrder = 3
        ListView_InsertColumn(hList, 3, tLVC)
        szBuf = "Data":   tLVC.iOrder = 4
        ListView_InsertColumn(hList, 4, tLVC)
        FOR lCol = 0 TO 4: ListView_SetColumnWidth(hList, lCol, %LVSCW_AUTOSIZE_USEHEADER): NEXT
    END SUB
    
    CALLBACK FUNCTION ShowDIALOG1Proc()
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                LoadUDT
    
            CASE %WM_SIZING            '// To prevent window from getting too small
                LOCAL rc AS RECT, pRc AS RECT PTR
                pRC = CBLPARAM
                GetWindowRect CBHNDL, rc
                IF (@pRc.nRight - @pRc.nLeft) < 200 THEN   '// Prevent change of width
                    @pRc.nLeft  = rc.nLeft: @pRc.nRight = rc.nLeft + 200
                END IF
                IF (@pRc.nBottom - @pRc.nTop) < 150 THEN   '// Prevent change of height
                    @pRc.nTop  = rc.nTop: @pRc.nBottom = rc.nTop + 150
                END IF
                FUNCTION = 1
    
            CASE %WM_SIZE      '// Resize controls when window is resized
                LOCAL bx AS LONG, by AS LONG, x AS LONG, y AS LONG
                IF IsIconic(CBHNDL) THEN EXIT SELECT                  '// Ignore if the window is minimized
                CONTROL GET SIZE CBHNDL, %LISTVIEW TO bx, by
                DIALOG GET SIZE CBHNDL TO x, y
                CONTROL SET SIZE CBHNDL, %LISTVIEW, x - 5, y - 15
                DIALOG REDRAW CBHNDL
        END SELECT
    END FUNCTION
    
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
    #PBFORMS BEGIN DIALOG %DIALOG1->->
        LOCAL hDlg  AS DWORD
        DIALOG NEW hParent, "UDTView", 63, 60, 230, 142, %WS_POPUP OR %WS_BORDER _
            OR %WS_DLGFRAME OR %WS_CAPTION OR %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_THICKFRAME OR _
            %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME _
            OR %DS_CENTER OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
            %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
            %WS_EX_RIGHTSCROLLBAR, TO hDlg
        CONTROL ADD "SysListView32", hDlg, %LISTVIEW, "SysListView32_1", _
            0, 0, 230, 140, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _
            %LVS_REPORT OR %LVS_SHOWSELALWAYS, %WS_EX_LEFT OR %WS_EX_CLIENTEDGE _
            OR %WS_EX_RIGHTSCROLLBAR
    #PBFORMS END DIALOG
        CONTROL HANDLE hDlg, %LISTVIEW TO hList
        hDlg1 = hDlg
        CreateListHeaders
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
    #PBFORMS BEGIN CLEANUP %DIALOG1
    #PBFORMS END CLEANUP
        FUNCTION = lRslt
    END FUNCTION
    
    FUNCTION DlgThread (BYVAL x AS LONG) AS LONG
    ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    
    SUB UDT_Init ALIAS "UDT_Init" (sBASFile AS STRING, sUDTName AS STRING, BYVAL dwUDTAddr AS DWORD, BYVAL dwUDTSize AS DWORD) EXPORT
        LOCAL hThread AS DWORD
        IF DIR$(sBASFile,39) = "" THEN
            MSGBOX "Source file not found: " & sBASFile
            EXIT SUB
        END IF
        gBASFile = sBASFile: gUDTName = sUDTName: gUDTAddr = dwUDTAddr: gUDTSize = dwUDTSize
        THREAD CREATE DlgThread(BYVAL 0) TO hThread
    END SUB
    
    SUB UDT_End ALIAS "UDT_End" () EXPORT
        REDIM Vars(0) AS Var:
        DIALOG END hDlg1
    END SUB

    Here is a simple example of how to use the DLL. You simply call UDT_Init at the start to tell the DLL which UDT in which source file you want to look at, and then call UDT_Update whenever you want to refresh the view.

    calltest.bas
    Code:
    #COMPILE EXE
    #INCLUDE "win32api.inc"
    
    '// UDTView declarations
    DECLARE SUB UDT_Init LIB "udtview.dll" ALIAS "UDT_Init" (sBASFile AS STRING, sUDTName AS STRING, BYVAL dwUDTAddr AS DWORD, BYVAL dwUDTSize AS DWORD)
    DECLARE SUB UDT_Update LIB "udtview.dll" ALIAS "UDT_Update" (BYVAL dwUDTAddr AS DWORD, BYVAL idx AS DWORD)
    DECLARE SUB UDT_End LIB "udtview.dll" ALIAS "UDT_End" ()
    '\\ End of UDTView decs
    
    TYPE MyUDT
        xString AS STRING * 15      '15
        xAsciiz AS ASCIIZ * 20      '1
        xByte AS BYTE               '1
        xDword AS DWORD             '4
    END TYPE
    
    
    FUNCTION PBMAIN() AS LONG
     LOCAL sBasfile AS STRING, sUDTName AS STRING, UDT AS MyUDT
    
     '// Fill with dummy data
     UDT.xAsciiz    = "Im an asciiz"
     UDT.xString    = "Im a string"
     UDT.xByte      = &h69
     UDT.xDword     = &hA0A1A2A3
    
     '// Initialise the DLL
     sBasfile = "c:\dev\pb\utilities\udtview\calltest.bas"  '// CHANGE BEFORE COMPILING!
     sUDTName = "MyUDT"
     UDT_Init sBASFile, sUDTName, BYVAL VARPTR(UDT), BYVAL SIZEOF(UDT)
     
     STDOUT "Press enter to change the values ...";: WAITKEY$
    
     UDT.xAsciiz    = "This is a NEW asciiz!"
     UDT.xString    = "And this is a NEW string!"
     UDT.xByte      = &hCC
     UDT.xDword     = &hF1F2F3F4
    
     '// Update UDTView
     UDT_Update BYVAL VARPTR(UDT), BYVAL 2
    
     STDOUT "Done": WAITKEY$
     UDT_End
    END FUNCTION
    Attached Files
    Last edited by Wayne Diamond; 2 Jul 2008, 03:23 AM. Reason: cos i can
    -
Working...
X