IecVarAccessLibrary.IBaseTreeNode methon

2025-08-20
2025-08-25
  • jzhvymetal77 - 2025-08-20

    I had this code working in a previous version of CoDeSys to read variables from a GVL that were added to the Symbol configuration. The problem now is that when I get the _IBaseTreeNode_Parent, it returns a valid interface, but none of the methods or properties work.

    If you monitor the _IBaseTreeNode in the watch window, it does show the correct child count. However, it fails at step 30, where the child count incorrectly returns zero. In the image, you can see that the watch window displays the correct value that the property should return.

    Attached is the full project code.

    FUNCTION_BLOCK Symbols_TO_STR
    VAR_INPUT
        i_sPath                     :   STRING(255);
        i_diIndexChild              :   DINT;
        i_diIndexComponent          :   DINT; 
    END_VAR
    VAR_OUTPUT
        q_diChildCount              :   DINT;
        q_diComponentCount          :   DINT;
        q_sName                     :   STRING(255);
        q_sValue                    :   STRING(255);
        q_sType                     :   STRING(80);
        q_sErrorResult              :   STRING(80);
    END_VAR
    VAR
        uiStepCopy                  :   UINT;
        uiStep                      :   UINT;
        uiStepProcessCopy           :   UINT;
        uiStepProcess               :   UINT;
    
        _IBase                      :   IecVarAccessLibrary.IBase;
        _pIIecVarAccess5            :   POINTER TO IecVarAccessLibrary.IIecVarAccess5;
        _IIecVarAccess5             :   IecVarAccessLibrary.IIecVarAccess5;
        _RTS_IEC_RESULT             :   IecVarAccessLibrary.RTS_IEC_RESULT;
        _udiResult                  :   UDINT;
        _VariableInformationStruct  :   IecVarAccessLibrary.VariableInformationStruct;
        _IBaseTreeNode_Parent       :   IecVarAccessLibrary.IBaseTreeNode;
    
        _IBaseTreeNode_Child        :   IecVarAccessLibrary.IBaseTreeNode;  
        _ITypeDesc_Child            :   IecVarAccessLibrary.ITypeDesc;
        _TypeDescAsUnion_Child      :   IecVarAccessLibrary.TypeDescAsUnion;
        _arIBaseTreeNode_Child      :   ARRAY[0..20] OF IecVarAccessLibrary.IBaseTreeNode;
        _TypeClass_Child            :   IecVarAccessLibrary.IBaseLibrary.TypeClass;
        _psSymbolName_Child         :   POINTER TO STRING;
        _sSymbolName_Child          :   STRING(255);
    
        _IBaseTreeNode_Component    :   REFERENCE TO IecVarAccessLibrary.IBaseTreeNode; 
        _TypeClass_Component        :   IecVarAccessLibrary.IBaseLibrary.TypeClass;
        _ByteAddress_Component      :   __XWORD;    
        _ByteOffset_Component       :   __XWORD;    
        _sArrayIndexName_Component  :   STRING(20);
        _diArrayIndexCalc_Component :   DINT;
        _diArrayIndexValue_Component:   DINT;
        _psSymbolName_Component     :   POINTER TO STRING;
        _sSymbolName_Component      :   STRING(255);
    END_VAR
    
        uiStepCopy:=uiStep;
        uiStepProcessCopy:=uiStepProcess;
        CASE uiStep OF  
            10: // GET IBASE FROM CURRENT APP
                _IBase:= IecVarAccessLibrary.IecVarAccGetFirstInterface2(0);
                IF _IBase<>0 THEN
                    uiStep:=20;
                ELSE    
                    q_sErrorResult:=CONCAT(UINT_TO_STRING(uiStep), ': IecVarAccGetFirstInterface2');
                    uiStep:=9000;
                END_IF
            20:  //QueryInterface IIecVarAccess5 from IBASE     
                _pIIecVarAccess5 := _IBase.QueryInterface(IecVarAccessLibrary.ITFID_IIecVarAccess5, ADR(_RTS_IEC_RESULT));
                IF _pIIecVarAccess5<>0 AND _RTS_IEC_RESULT=0 THEN
                    _IIecVarAccess5 := _pIIecVarAccess5^;
                    uiStep:=30;
                ELSE    
                    q_sErrorResult:=CONCAT(UINT_TO_STRING(uiStep), ': QueryInterface_IIecVarAccess5');
                    uiStep:=9000;
                END_IF
            30:  // Get IBaseTreeNode_Parent
                _IBaseTreeNode_Parent := _IIecVarAccess5.VarAccGetNode3(ADR(i_sPath), ADR(_VariableInformationStruct), ADR(_RTS_IEC_RESULT));
                IF _IBaseTreeNode_Parent<>0 AND _RTS_IEC_RESULT=0 THEN
                    q_diChildCount:=_IBaseTreeNode_Parent.ChildCount;
    
                    uiStep:=40;
                ELSE    
                    q_sErrorResult:=CONCAT(UINT_TO_STRING(uiStep), ': IBaseTreeNode_Parent');
                    uiStep:=9000;
                END_IF
            40:  // Get IBaseTreeNod_Child
                IF(q_diChildCount-1>=i_diIndexChild AND i_diIndexChild >=0) THEN
                    _IBaseTreeNode_Child := _IBaseTreeNode_Parent.GetChild(i_diIndexChild);
                    IF _IBaseTreeNode_Child<>0 THEN
                        uiStep:=50;
                    ELSE    
                        q_sErrorResult:=CONCAT(UINT_TO_STRING(uiStep), ': IBaseTreeNode_Parent');
                        uiStep:=9000;
                    END_IF      
                ELSE
                    q_sErrorResult:=CONCAT(UINT_TO_STRING(uiStep), ': i_diIndexChild OutBounds');
                    uiStep:=9000;
                END_IF
    
     
  • jzhvymetal77 - 2025-08-25

    I got this code working again. 3S/CoDeSys, your level of obfuscation and lack of documentation turns a simple task into a monumental complex challenge.

    The issue was that at some point the IecVarAccessLibrary changed and no longer allowed using IBaseTreeNode to retrieve a child or the number of children. The attached code has been updated to use IIecVarAccess6.VarAccBrowseGetChildByIndex instead. The code was also cleaned up but is still a work in progress.

    The current example only works one layer deep. This means native data types, arrays, and single-layer structures are supported. However, structure arrays and nested structures are not yet supported.

     

    Last edit: jzhvymetal77 2025-08-25

Log in to post a comment.