Welcome, Guest
Username: Password: Remember me
Visual Objects

Please use this forum to post questions about Visual Objects and Vulcan.NET
  • Page:
  • 1
  • 2

TOPIC:

Visibility of work areas, variables, viewing contents of objects 06 Feb 2022 19:44 #21463

  • ThomasWYale
  • ThomasWYale's Avatar
  • Topic Author


  • Posts: 42
  • In a forum post dated February 19, 2021, the most recent one I could find, I read that X# development plans include "Runtime Debugging support with windows built in the Runtime to show workareas/cursors, globals, privates and settings".

    I migrated a project in VO 2.8 SP4b with 88,035 lines of code via XSharp VOXPorter, then successfully eliminated all compiler errors. Some warnings appeared, most of which dealt with undeclared variables, which are actually field names in dbf's my application opens. After checking the compiler option "/undeclared", this did not prevent the application from running, save for a minor glitch in processing, which may be due to peculiarities in X# language.

    In any event, when ran the debugger to examine this glitch, I attempted to view the contents of global and local objects, but globals were not present in the Locals treeview. I clicked the node "[+] <Globals>" but it's huge and look a long time to display, and none of the global variables my application constructs were present. I also opened the View DBF Work Areas to view the dbf's I opened (and they'd have to be open, otherwise my application wouldn't run at all), but the list was blank.

    Have I installed XIDE incorrectly or has this feature not yet been implemented? I wonder whether this has to do with the lack of Visual Studio core editor, in addition to some of the other workloads (and I'm not sure which ones I would need, if any). I tried to download it, but the VS downloader froze up, even after repeated attempts.

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 01:59 #21464

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • De heer van der Hulst, is de feature toegevoegd? Ik zag dat je de post hebt bekeken.

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 02:11 #21465

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3236
  • Hi Thomas,
    AFAIK this was a feature planned for the Visual Studio IDE, and since I personally don't use Visual Studio to develop in X#, but XIDE, I cannot say if that was implemented.
    If you are working in XIDE: this is a project of the development team member Chris Pyrgas, and for sure he will answer your questions.
    About debugging in XIDE: in some situations (specially when interacting with web services) the integrated debugger in XIDE does not works well. And in these situations, even not using Visual Studio, I start if up, and connect the debugger to my already running exe, and can use the Visual Studio debugger.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 02:58 #21467

    • Chris
    • Chris's Avatar


  • Posts: 3732
  • Hi Thomas and Wolfgang,

    Indeed, this area needs a lot of improvements. Regarding globals, the problem is that when you expand this node, it shows also DEFINEs (defined in any library), which are so many, which causes this huge delay. Not sure if it's possible to distinguish DEFINEs from GLOBALs in the debugger library, but I will look into it.

    About the View Workareas menu option, this used to work nicely, but recently the RDD interface has changed in the X# runtime and has made this obsolete unfortunately.

    Good news though is that the debugging windows have actually been implemented in the runtime! They are just not linked yet to the IDEs. But at least you can call them manually, even without debugging your app. In order to do this, add a reference to the library XSharp.RT.Debugger and then anywhere in your code call any of those functions (static methods):

    XSharp.RT.Debugger.Functions.DbgShowGlobals()
    XSharp.RT.Debugger.Functions.DbgShowWorkAreas()
    XSharp.RT.Debugger.Functions.DbgShowSettings()

    You can call them for example from a menu or a button event in your app, so they do not depend on if the debugger is actually attached.

    So this should help you for now, but will look into improving the whole system for the next build.
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 03:02 #21468

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Thank you for your reply, Wolfgang. I'm still a little confused. I'm not yet interacting with web services, but "connect" the debugger? Isn't the debugger already part of XIDE? If you use neither XIDE nor Visual Studio, then what do you use to debug your programs? The old VO 2.8 software? I guess that's what I'll have to use. Still further, you say that you can use the VS debugger, but don't.

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 03:03 #21469

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3236
  • Hi Chris,
    thank you very much for your answer!
    I'm sure this will help.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 03:09 #21470

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3236
  • Hi Thomas,
    XIDE make use of an open source debugging library, and sometimes this debugger does not works very well.
    Until you are working with VO style applications the XIDE debugger works very well.
    But there is another powerful debugger that is part of Microsoft Visual Studio, and even if you develop using XIDE (like I do for all my needs, even WPF and Windows Forms applications), you can always use the Visual Studio Debugger. For me is that the case in about 10% of my debugging needs (I have a lot of different projects, and some of them are interacting with web services).
    When you need that, feel free to ask, and someone will explain how to do that.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 03:27 #21471

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Thank you very much for that information, Chris. So X# users do have available debugging information through this option!

    I have one other question, though. Calling one or all of the DbgShow...() functions anywhere in the code (perhaps XApp:Start()?) seems easy enough, and I suppose wherever I set the breakpoints, those windows will be visible. But how does one add the XSharp.RT.Debugger reference to the library? Is it done through the IDE or some other way? Without the reference, I suppose I'd get an "out of context" compiler error.

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 03:29 #21472

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Thanks, Wolfgang, I'll keep that in mind. My main goal now is to enable my application to work online, as opposed to a software download which many don't opt for.

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 03:55 #21473

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Is it here? I was just roaming through the interface, clicked this node and right-click ed for this context menu.

    Attachments:

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 05:08 #21474

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3236
  • Hi Thomas,
    yes, they are the references of your application.
    Personally, I would add a call to the debugging functions somewhere in your menu, so you can call then whenever you like - even when the application is running on another machine than yours.
    But of course, if you add that library to the references, you have to deliver the relative DLL together with your application.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 05:50 #21475

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Hi, Chris.

    I tried it and it works. DbgShowMemvars produces an RTE, but the only other downside is that DbgShowGlobals and I think I may have a solution for that.

    I was thinking of building a dialog, using one or more global variables or objects as arguments, and constructing a class which uses Object2Array() along with IVarListGetInfo(), IVarList() and IVarListClass(). This class implemented in the dialog would traverse the array and add treeview items with data derived from these functions. It would check the type with IsString(), IsSymbol(), IsLogic(), et al to display the values, iterate the element if IsArray(), and in cases of IsObject(), an object within an object, call the method for accessing the object element recursively.

    When I get it to work, would you like me to share the code with you? I don't know whether it would make emulating CAVO's global treeview for objects in XIDE any easier, but if it does, I'd be glad to help.

    Please Log in or Create an account to join the conversation.

    Last edit: by ThomasWYale.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 08:07 #21476

    • Chris
    • Chris's Avatar


  • Posts: 3732
  • Hi Thomas,

    Yes, please send us the code, if it's suitable it can be used in both XIDE and VS!
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 08:17 #21477

    • robert
    • robert's Avatar


  • Posts: 3268
  • Thomas,

    ThomasWYale wrote: De heer van der Hulst, is de feature toegevoegd? Ik zag dat je de post hebt bekeken.


    We are working on this at this moment, as well as an improved "Debugger Expression Evaluator" (both for the VS debugger, the XIDE debugger is another thing).

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 08:18 #21478

    • robert
    • robert's Avatar


  • Posts: 3268
  • Thomas,

    ThomasWYale wrote: Hi, Chris.
    I tried it and it works. DbgShowMemvars produces an RTE, but the only other downside is that DbgShowGlobals and I think I may have a solution for that.


    I am not sure what you mean with RTE, but if it is an exception, can you please share that with us, so we can take care of it.

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 08:55 #21479

    • Chris
    • Chris's Avatar


  • Posts: 3732
  • Robert,

    It gives a runtime exception, this is why I did not include this function in my post above

    System.InvalidCastException
    Unable to cast object of type 'System.Reflection.RtFieldInfo' to type 'System.Reflection.MethodInfo'.
    
    Callstack : 
    XSharp.Debugger.MemVarsWindow.System.Void XSharp.Debugger.MemVarsWindow.LoadValues()() 
    XSharp.Debugger.MemVarsWindow.System.Void XSharp.Debugger.MemVarsWindow..ctor()() 
    static System.Void XSharp.RT.Debugger.Functions.DbgShowMemvars()() 

    Also DbgShowWorkAreas() gives some handled exceptions, looking into it and will open tickets if necessary.
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 15:13 #21480

    • robert
    • robert's Avatar


  • Posts: 3268
  • Chris,
    I checked in a fix

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 07 Feb 2022 20:21 #21485

    • Chris
    • Chris's Avatar


  • Posts: 3732
  • Robert,

    Yes, works fine now!
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Visibility of work areas, variables, viewing contents of objects 10 Feb 2022 11:01 #21501

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Here you are, Chris. I would've finished a lot sooner, but I have a day job, had to contend with walking a few miles to work every day in the wake of a recent snowstorm, among other things.

    I tried to emulate as closely as possible to the way VO 2.8 does this. Like the functions in XSharp.RT.Debugger, it has to be either inserted within the code or called from a menu option. As long-time VO 2.8 users know, however, the feature seems to use a kind of hybrid control with the properties of both a listview and treeview. Since I didn't have that, I settled on a treeview instead. And since I can't include the actual form here, you need only construct one yourself with the two PROTECTs as listed in the class declaration for ViewObjects. One or more GLOBALs, or any combination of objects or arrays to be inspected, are included in an array designated as uExtra argument in ViewObjects.

    LOCAL oViewObjects AS ViewObjects
    ...
    oViewObjects:=ViewObjects{,,,{<arrayOrObject1,arrayOrObject2,...}}
    oViewObjects:Show(SHOWCENTERED)

    Early on I figured that I'd face the problem of a stack overflow error if I constructed a complete tree, particularly if there were circular references, so I put in safeguards prevent that. As in VO, a user double-clicks a node to reveal its content, but the tree adds items only incrementally, revealing only what the user intends to see. That way, the tree indicates the presence of any array elements or object attributes one step in advance, with the [+] designation beside the node as unexpanded.

    I tested it as extensively as I could, and hope that you find use with it.
    CLASS ViewObjects INHERIT DATADIALOG 
    
    	PROTECT oDCtv AS TREEVIEW
    	PROTECT oCCbtnExit AS PUSHBUTTON
    
      //{{%UC%}} USER CODE STARTS HERE (do NOT remove this line)
    
    PROTECT aObjectsInTree AS ARRAY
    PROTECT nStopAdding AS BYTE
    
    METHOD Init(oWindow,iCtlID,oServer,uExtra) CLASS ViewObjects 
    SELF:PreInit(oWindow,iCtlID,oServer,uExtra)
    SUPER:Init(oWindow,ResourceID{"ViewObjects",_GetInst()},iCtlID)
    oDCtv := TreeView{SELF,ResourceID{VIEWOBJECTS_TV,_GetInst()}}
    oDCtv:HyperLabel := HyperLabel{#tv,"View Objects",NULL_STRING,NULL_STRING}
    oCCbtnExit := PushButton{SELF,ResourceID{VIEWOBJECTS_BTNEXIT,_GetInst()}}
    oCCbtnExit:HyperLabel := HyperLabel{#btnExit,"Exit",NULL_STRING,NULL_STRING}
    SELF:Caption := "View Objects"
    SELF:HyperLabel := HyperLabel{#ViewObjects,"View Objects",NULL_STRING,NULL_STRING}
    IF !IsNil(oServer)
     SELF:Use(oServer)
    ENDIF
    SELF:PostInit(oWindow,iCtlID,oServer,uExtra)
    RETURN SELF
    
    METHOD PostInit(oWindow,iCtlID,oServer,uExtra) CLASS ViewObjects
    LOCAL y AS BYTE
    SELF:aObjectsInTree:={}
    SELF:nStopAdding:=0
    FOR y=1 UPTO ALen(uExtra)
     IF IsObject(uExtra[y])
      SELF:doObject(uExtra[y],#ROOT)
     ELSE
      SELF:doArray(uExtra[y],#ROOT)
     ENDIF
    NEXT
    RETURN NIL
    
    METHOD doArray(aArray,sParentName) CLASS ViewObjects
    LOCAL sName AS SYMBOL
    LOCAL y AS BYTE
    LOCAL oTVI AS TreeViewItem
    sName:=String2Symbol(PadL(SELF:oDCtv:ItemCount,3,"0"))
    oTVI:=TreeViewItem{sName,"array",aArray}
    SELF:oDCtv:AddItem(sParentName,oTVI)
    IF SELF:nStopAdding<3
     SELF:nStopAdding:=SELF:nStopAdding+1
     FOR y=1 UPTO ALen(aArray)
      SELF:doAttribute(sName,"["+NTrim(y)+"]",aArray[y],4)
     NEXT
     SELF:nStopAdding:=SELF:nStopAdding-1
    ENDIF
    RETURN NIL
    
    METHOD doAttribute(sParentName,cName,uValue,dwlInfo)  CLASS ViewObjects
    LOCAL sName AS SYMBOL
    LOCAL cExp AS STRING
    LOCAL y AS BYTE
    LOCAL oTVI AS TreeViewItem
    sName:=String2Symbol(PadL(SELF:oDCtv:ItemCount,3,"0"))
    IF IsNil(uValue)
     IF IsArray(uValue)
      oTVI:=TreeViewItem{sName,cName+" NULL_ARRAY ",uValue}
     ELSEIF IsString(uValue)
      oTVI:=TreeViewItem{sName,cName+" NULL_STRING ",uValue}
     ELSEIF IsObject(uValue)
      oTVI:=TreeViewItem{sName,cName+" NULL_OBJECT ",uValue}
     ELSE
      oTVI:=TreeViewItem{sName,cName+" nil ",uValue}
     ENDIF
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsLogic(uValue)
     oTVI:=TreeViewItem{sName,cName+" logic "+LTOC(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsSymbol(uValue)
     oTVI:=TreeViewItem{sName,cName+" symbol "+Symbol2String(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsFloat(uValue)
     oTVI:=TreeViewItem{sName,cName+" float "+NTrim(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsLong(uValue)
     oTVI:=TreeViewItem{sName,cName+" long "+NTrim(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsNumeric(uValue)
     oTVI:=TreeViewItem{sName,cName+" numeric "+NTrim(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsDate(uValue)
     oTVI:=TreeViewItem{sName,cName+" date "+DToC(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsString(uValue)
     oTVI:=TreeViewItem{sName,cName+" string "+CHR(34)+uValue+CHR(34),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsArray(uValue)
     oTVI:=TreeViewItem{sName,cName+" array",uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
     IF SELF:nStopAdding<3
      SELF:nStopAdding:=SELF:nStopAdding+1
      FOR y=1 UPTO ALen(uValue)
       SELF:doAttribute(sName,"["+NTrim(y)+"]",uValue[y],4)
      NEXT
      SELF:nStopAdding:=SELF:nStopAdding-1
     ENDIF
    ELSEIF IsObject(uValue)
     cExp:=cName+" class "+Symbol2String(ClassName(uValue))
     IF AScan(SELF:aObjectsInTree,uValue)>0
      oTVI:=TreeViewItem{sName,cName+" class "+Symbol2String(ClassName(uValue))+" (circular reference)",uValue}
      SELF:oDCtv:AddItem(sParentName,oTVI)
     ELSE
      SELF:doObject(uValue,sParentName)
     ENDIF
    ELSE // IF IsPtr(uValue)
     oTVI:=TreeViewItem{sName,cName+" Other, assuming Pointer",uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ENDIF
    RETURN NIL
    
    METHOD doObject(oObject,sParentName) CLASS ViewObjects
    LOCAL sName,sAttrib AS SYMBOL
    LOCAL y AS BYTE
    LOCAL cExp AS STRING
    LOCAL oTVI AS TreeViewItem
    LOCAL aVarList:=IvarList(oObject)
    cExp:="CLASS "+Symbol2String(ClassName(oObject))
    sName:=String2Symbol(PadL(SELF:oDCtv:ItemCount,3,"0"))
    AAdd(SELF:aObjectsInTree,oObject)
    oTVI:=TreeViewItem{sName,cExp,oObject}
    SELF:oDCtv:AddItem(sParentName,oTVI)
    FOR y=1 UPTO ALen(aVarList)
     sAttrib:=aVarList[y]
     SELF:doAttribute(sName,Symbol2String(sAttrib),IVarGet(oObject,sAttrib),IVarGetInfo(oObject,sAttrib))
    NEXT
    RETURN NIL
    
    METHOD TreeViewMouseButtonDoubleClick(oTreeViewMouseEvent) CLASS ViewObjects
    LOCAL sName,sAttrib AS SYMBOL
    LOCAL y AS BYTE
    LOCAL uValue AS USUAL
    LOCAL oTVI,oTVI2,oTVI3 AS TreeViewItem
    LOCAL aVarList AS ARRAY
    LOCAL oControl AS Control
    oControl:=IF(oTreeViewMouseEvent==NULL_OBJECT,NULL_OBJECT,oTreeViewMouseEvent:Control)
    SUPER:TreeViewMouseButtonDoubleClick(oTreeViewMouseEvent)
    oTVI:=SELF:oDCtv:GetSelectedItem()
    sName:=oTVI:NameSym
    uValue:=oTVI:Value
    IF(!IsArray(uValue).AND.!IsObject(uValue)).OR.IsObject(uValue).AND.AScan(SELF:aObjectsInTree,uValue)>0
     RETURN NIL
    ENDIF
    oTVI2:=SELF:oDCtv:GetFirstChildItem(oTVI)
    IF!oTVI2==NULL_OBJECT
     WHILE!oTVI2==NULL_OBJECT
      IF IsArray(oTVI2:VALUE).OR.IsObject(oTVI2:VALUE).AND.AScan(SELF:aObjectsInTree,oTVI2:VALUE)>0
       oTVI3:=SELF:oDCtv:GetFirstChildItem(oTVI2)
       WHILE!oTVI3==NULL_OBJECT
        IF IsArray(oTVI3:VALUE).AND.SELF:oDCtv:GetFirstChildItem(oTVI3:NameSym)==NULL_OBJECT
         FOR y=1 UPTO ALen(oTVI3:VALUE) 
          SELF:doAttribute(oTVI3:NameSym,"["+NTrim(y)+"]",oTVI3:VALUE[y],4)
         NEXT
        ELSEIF IsObject(oTVI3:VALUE)
         aVarList:=IvarList(oTVI3:VALUE)
         FOR y=1 UPTO ALen(aVarList)
          sAttrib:=aVarList[y]
          SELF:doAttribute(oTVI3:NameSym,Symbol2String(sAttrib),IVarGet(oTVI3:Value,sAttrib),IVarGetInfo(oTVI3:Value,sAttrib))
         NEXT
        ENDIF
        oTVI3:=SELF:oDCtv:GetNextSiblingItem(oTVI3)
       ENDDO
      ENDIF
      oTVI2:=SELF:oDCtv:GetNextSiblingItem(oTVI2)
     ENDDO
    ELSEIF IsArray(uValue).AND.ALen(uValue)>0
     IF SELF:nStopAdding<3
      SELF:nStopAdding:=SELF:nStopAdding+1
      FOR y=1 UPTO ALen(uValue)
       SELF:doAttribute(sName,"["+NTrim(y)+"]",uValue[y],4)
      NEXT
      SELF:nStopAdding:=SELF:nStopAdding-1
     ENDIF
    ENDIF
    RETURN NIL
    
    METHOD btnExit( ) CLASS ViewObjects 
    SELF:EndWindow()
    RETURN NIL

    Please Log in or Create an account to join the conversation.

    Last edit: by ThomasWYale.

    Visibility of work areas, variables, viewing contents of objects 10 Feb 2022 13:31 #21503

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Here you are, Chris. I would've finished a lot sooner, but I have a day job, had to contend with walking a few miles to work every day in the wake of a recent snowstorm, among other things.

    I tried to emulate as closely as possible to the way VO 2.8 does this. Like the functions in XSharp.RT.Debugger, it has to be either inserted within the code or called from a menu option. As long-time VO 2.8 users know, however, the feature seems to use a kind of hybrid control with the properties of both a listview and treeview. Since I didn't have that, I settled on a treeview instead. And since I can't include the actual form here, you need only construct one yourself with the two PROTECTs as listed in the class declaration for ViewObjects. One or more GLOBALs, or any combination of objects or arrays to be inspected, are included in an array designated as uExtra argument in ViewObjects.
    LOCAL oViewObjects AS ViewObjects
    ...
    oViewObjects:=ViewObjects{,,,{<arrayOrObject1,arrayOrObject2,...}}
    oViewObjects:Show(SHOWCENTERED)

    Early on I figured that I'd face the problem of a stack overflow error if I constructed a complete tree, particularly if there were circular references, so I put in safeguards prevent that. As in VO, a user double-clicks a node to reveal its content, but the tree adds items only incrementally, revealing only what the user intends to see. That way, the tree indicates the presence of any array elements or object attributes one step in advance, with the [+] designation beside the node as unexpanded.

    I tested it as extensively as I could, and hope that you find use with it.
    CLASS ViewObjects INHERIT DATADIALOG 
    
    	PROTECT oDCtv AS TREEVIEW
    	PROTECT oCCbtnExit AS PUSHBUTTON
    
      //{{%UC%}} USER CODE STARTS HERE (do NOT remove this line)
    
    PROTECT aObjectsInTree AS ARRAY
    PROTECT nStopAdding AS BYTE
    
    METHOD Init(oWindow,iCtlID,oServer,uExtra) CLASS ViewObjects 
    
    SELF:PreInit(oWindow,iCtlID,oServer,uExtra)
    
    SUPER:Init(oWindow,ResourceID{"ViewObjects",_GetInst()},iCtlID)
    
    oDCtv := TreeView{SELF,ResourceID{VIEWOBJECTS_TV,_GetInst()}}
    oDCtv:HyperLabel := HyperLabel{#tv,"View Objects",NULL_STRING,NULL_STRING}
    
    oCCbtnExit := PushButton{SELF,ResourceID{VIEWOBJECTS_BTNEXIT,_GetInst()}}
    oCCbtnExit:HyperLabel := HyperLabel{#btnExit,"Exit",NULL_STRING,NULL_STRING}
    
    SELF:Caption := "View Objects"
    SELF:HyperLabel := HyperLabel{#ViewObjects,"View Objects",NULL_STRING,NULL_STRING}
    
    IF !IsNil(oServer)
    	SELF:Use(oServer)
    ENDIF
    
    SELF:PostInit(oWindow,iCtlID,oServer,uExtra)
    
    RETURN SELF
    
    METHOD PostInit(oWindow,iCtlID,oServer,uExtra) CLASS ViewObjects
    LOCAL y AS BYTE
    SELF:aObjectsInTree:={}
    SELF:nStopAdding:=0
    FOR y=1 UPTO ALen(uExtra)
     IF IsObject(uExtra[y])
      SELF:doObject(uExtra[y],#ROOT)
     ELSE
      SELF:doArray(uExtra[y],#ROOT)
     ENDIF
    NEXT
    RETURN NIL
    
    METHOD doArray(aArray,sParentName) CLASS ViewObjects
    LOCAL sName AS SYMBOL
    LOCAL y AS BYTE
    LOCAL oTVI AS TreeViewItem
    sName:=String2Symbol(PadL(SELF:oDCtv:ItemCount,6,"0"))
    oTVI:=TreeViewItem{sName,"array",aArray}
    SELF:oDCtv:AddItem(sParentName,oTVI)
    FOR y=1 UPTO ALen(aArray)
     SELF:doAttribute(sName,"["+NTrim(y)+"]",aArray[y],4)
    NEXT
    RETURN NIL
    
    METHOD doAttribute(sParentName,cName,uValue,dwlInfo)  CLASS ViewObjects
    LOCAL sName AS SYMBOL
    LOCAL cExp AS STRING
    LOCAL y AS BYTE
    LOCAL oTVI AS TreeViewItem
    sName:=String2Symbol(PadL(SELF:oDCtv:ItemCount,6,"0"))
    IF IsNil(uValue)
     IF IsArray(uValue)
      oTVI:=TreeViewItem{sName,cName+" NULL_ARRAY ",uValue}
     ELSEIF IsString(uValue)
      oTVI:=TreeViewItem{sName,cName+" NULL_STRING ",uValue}
     ELSEIF IsObject(uValue)
      oTVI:=TreeViewItem{sName,cName+" NULL_OBJECT ",uValue}
     ELSE
      oTVI:=TreeViewItem{sName,cName+" nil ",uValue}
     ENDIF
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsLogic(uValue)
     oTVI:=TreeViewItem{sName,cName+" logic "+LTOC(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsSymbol(uValue)
     oTVI:=TreeViewItem{sName,cName+" symbol "+Symbol2String(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsFloat(uValue)
     oTVI:=TreeViewItem{sName,cName+" float "+NTrim(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsLong(uValue)
     oTVI:=TreeViewItem{sName,cName+" long "+NTrim(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsNumeric(uValue)
     oTVI:=TreeViewItem{sName,cName+" numeric "+NTrim(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsDate(uValue)
     oTVI:=TreeViewItem{sName,cName+" date "+DToC(uValue),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsString(uValue)
     oTVI:=TreeViewItem{sName,cName+" string "+CHR(34)+uValue+CHR(34),uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ELSEIF IsArray(uValue)
     oTVI:=TreeViewItem{sName,cName+" array",uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
     IF SELF:nStopAdding<2
      SELF:nStopAdding:=SELF:nStopAdding+1
      FOR y=1 UPTO ALen(uValue)
       SELF:doAttribute(sName,"["+NTrim(y)+"]",uValue[y],4)
      NEXT
      SELF:nStopAdding:=SELF:nStopAdding-1
     ENDIF
    ELSEIF IsObject(uValue)
     cExp:=cName+" class "+Symbol2String(ClassName(uValue))
     IF AScan(SELF:aObjectsInTree,uValue)>0
      oTVI:=TreeViewItem{sName,cName+" class "+Symbol2String(ClassName(uValue))+" (circular reference)",uValue}
      SELF:oDCtv:AddItem(sParentName,oTVI)
     ELSEIF SELF:nStopAdding<2
      SELF:nStopAdding:=SELF:nStopAdding+1
      SELF:doObject(uValue,sParentName)
      SELF:nStopAdding:=SELF:nStopAdding-1
     ENDIF
    ELSE // IF IsPtr(uValue)
     oTVI:=TreeViewItem{sName,cName+" Other, assuming Pointer",uValue}
     SELF:oDCtv:AddItem(sParentName,oTVI)
    ENDIF
    RETURN NIL
    
    METHOD doObject(oObject,sParentName) CLASS ViewObjects
    LOCAL sName,sAttrib AS SYMBOL
    LOCAL y AS BYTE
    LOCAL cExp AS STRING
    LOCAL oTVI AS TreeViewItem
    LOCAL aVarList:=IvarList(oObject)
    cExp:="CLASS "+Symbol2String(ClassName(oObject))
    sName:=String2Symbol(PadL(SELF:oDCtv:ItemCount,6,"0"))
    AAdd(SELF:aObjectsInTree,oObject)
    oTVI:=TreeViewItem{sName,cExp,oObject}
    SELF:oDCtv:AddItem(sParentName,oTVI)
    FOR y=1 UPTO ALen(aVarList)
     sAttrib:=aVarList[y]
     SELF:doAttribute(sName,Symbol2String(sAttrib),IVarGet(oObject,sAttrib),IVarGetInfo(oObject,sAttrib))
    NEXT
    RETURN NIL
    
    METHOD TreeViewMouseButtonDoubleClick(oTreeViewMouseEvent) CLASS ViewObjects
    LOCAL sName,sAttrib AS SYMBOL
    LOCAL y AS BYTE
    LOCAL uValue AS USUAL
    LOCAL oTVI,oTVI2,oTVI3 AS TreeViewItem
    LOCAL aVarList AS ARRAY
    LOCAL oControl AS Control
    oControl:=IF(oTreeViewMouseEvent==NULL_OBJECT,NULL_OBJECT,oTreeViewMouseEvent:Control)
    SUPER:TreeViewMouseButtonDoubleClick(oTreeViewMouseEvent)
    oTVI:=SELF:oDCtv:GetSelectedItem()
    sName:=oTVI:NameSym
    uValue:=oTVI:Value
    IF(!IsArray(uValue).AND.!IsObject(uValue)).OR.IsObject(uValue).AND.AScan(SELF:aObjectsInTree,uValue)>0
     RETURN NIL
    ENDIF
    oTVI2:=SELF:oDCtv:GetFirstChildItem(oTVI)
    WHILE!oTVI2==NULL_OBJECT
     IF IsArray(oTVI2:Value).OR.IsObject(oTVI2:Value).AND.AScan(SELF:aObjectsInTree,oTVI2:Value)>0
      oTVI3:=SELF:oDCtv:GetFirstChildItem(oTVI2)
      WHILE!oTVI3==NULL_OBJECT
       IF IsArray(oTVI3:VALUE).AND.SELF:oDCtv:GetFirstChildItem(oTVI3:NameSym)==NULL_OBJECT
        FOR y=1 UPTO ALen(oTVI3:VALUE) 
         SELF:doAttribute(oTVI3:NameSym,"["+NTrim(y)+"]",oTVI3:VALUE[y],4)
        NEXT
       ELSEIF IsObject(oTVI3:Value)
        aVarList:=IvarList(oTVI3:VALUE)
        FOR y=1 UPTO ALen(aVarList)
         sAttrib:=aVarList[y]
         SELF:doAttribute(oTVI3:NameSym,Symbol2String(sAttrib),IVarGet(oTVI3:Value,sAttrib),IVarGetInfo(oTVI3:Value,sAttrib))
        NEXT
       ENDIF
       oTVI3:=SELF:oDCtv:GetNextSiblingItem(oTVI3)
      ENDDO
     ENDIF
     oTVI2:=SELF:oDCtv:GetNextSiblingItem(oTVI2)
    ENDDO
    RETURN NIL
    
    METHOD btnExit( ) CLASS ViewObjects 
    SELF:EndWindow()
    RETURN NIL

    Please Log in or Create an account to join the conversation.

    • Page:
    • 1
    • 2