[ABAP] Globale Objekte eines Programms ermitteln und Infos anzeigen

Variante 1 (lokale Infoklasse)

* Quellen: https://blogs.sap.com/2018/08/27/sapgui-is-dying-but-still-secrets-to-reveal.../
*          https://github.com/tricktresor/container_hierarchy

CLASS lcl_global_symbols DEFINITION.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_obj_info,
             name          TYPE rfieldlist-name,
             type          TYPE rfieldlist-type,
             reftypeloc    TYPE rfieldlist-reftypeloc,
             global_name   TYPE string,
             relative_name TYPE string,
             object_name   TYPE string,
             object_id     TYPE i,
             reference     TYPE REF TO object,
             error         TYPE string,
           END OF ty_obj_info.

    TYPES: ty_it_obj_info TYPE STANDARD TABLE OF ty_obj_info WITH DEFAULT KEY.

    CONSTANTS: null TYPE REF TO object VALUE IS INITIAL.

    CLASS-METHODS:
      get_obj_info
        IMPORTING
                  iv_name               TYPE rfieldlist-name
                  iv_type               TYPE rfieldlist-type DEFAULT 'r'
                  iv_reftypeloc         TYPE rfieldlist-reftypeloc DEFAULT 'CLAS'
        RETURNING VALUE(rv_it_obj_info) TYPE ty_it_obj_info.
ENDCLASS.

CLASS lcl_global_symbols IMPLEMENTATION.
  METHOD get_obj_info.
    DATA: it_fieldlist TYPE STANDARD TABLE OF rfieldlist WITH DEFAULT KEY.
* Liste der globalen Daten eines Programms
    CALL FUNCTION 'GET_GLOBAL_SYMBOLS'
      EXPORTING
        program      = sy-repid
        name_pattern = '*'
      TABLES
        fieldlist    = it_fieldlist.

    DATA(lv_where) = ||.

    IF NOT iv_name IS INITIAL.
      lv_where = |name CP iv_name AND type = iv_type AND reftypeloc = iv_reftypeloc|.
    ENDIF.

    LOOP AT it_fieldlist ASSIGNING FIELD-SYMBOL(<f>) WHERE (lv_where).

      DATA(lv_global_name) = |({ sy-repid }){ <f>-name }|.
      DATA(lv_relative_name) = ||.
      DATA(lv_object_name) = ||.
      DATA(lv_error) = ||.
      DATA: lv_oid TYPE i.

* Wenn Referenztyp
      IF <f>-type = 'r'.
* Dirty Assign: Namen an Feldsymbol vom TYPE ANY binden
        ASSIGN (lv_global_name) TO FIELD-SYMBOL(<o>).

        IF NOT <o> IS INITIAL.
          IF <o> IS ASSIGNED.
            TRY.
* <o> ist eine Referenz
                IF <o> IS BOUND.
* Descriptor für Objektreferenz
                  DATA(o_desc) = cl_abap_typedescr=>describe_by_object_ref( <o> ).

                  lv_relative_name = o_desc->get_relative_name( ).

* ObjektID zur Referenz ermitteln
                  CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'GET_OBJID'
                                         ID 'OBJID'  FIELD lv_oid      " Rückgabe: ObjectID
                                         ID 'OBJ'    FIELD <o>.

                  lv_object_name = |\{O:{ lv_oid }*{ o_desc->absolute_name }|.
                ENDIF.
              CATCH cx_root INTO DATA(e_txt).
                lv_error = e_txt->get_text( ).
            ENDTRY.
          ENDIF.
        ENDIF.
      ENDIF.

      APPEND VALUE #(
                      name          = <f>-name
                      type          = <f>-type
                      reftypeloc    = <f>-reftypeloc
                      global_name   = lv_global_name
                      relative_name = lv_relative_name
                      object_name   = lv_object_name
                      object_id     = lv_oid
                      reference     = COND #( WHEN ( <o> IS ASSIGNED AND NOT <o> IS INITIAL ) THEN <o> ELSE null )
                      error         = lv_error
                    ) TO rv_it_obj_info.
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

DATA: o_dock TYPE REF TO cl_gui_docking_container.
DATA: o_text TYPE REF TO cl_gui_textedit.

PARAMETERS: p_matnr TYPE mara-matnr.

INITIALIZATION.

  IF NOT o_dock IS BOUND.
* GUI-Objekte für Test erzeugen
    o_dock = NEW #( side  = cl_gui_docking_container=>dock_at_bottom
                    ratio = 90 ).

    o_text = NEW #( parent = o_dock ).
  ENDIF.

START-OF-SELECTION.

* Infos zu 'o_dock' holen
  DATA(it_one) = lcl_global_symbols=>get_obj_info( iv_name = 'o_dock' ).

  LOOP AT it_one ASSIGNING FIELD-SYMBOL(<one>).

    DATA(lv_ref_one) = ||.

    IF <one>-reference IS BOUND.
      lv_ref_one = <one>-object_name.
    ENDIF.

    WRITE: / <one>-name, <one>-type, <one>-reftypeloc, <one>-global_name, <one>-relative_name, <one>-object_name, <one>-object_id, lv_ref_one, <one>-error.
  ENDLOOP.

  ULINE.

* Infos zu allen Objekten holen
  DATA(it_all) = lcl_global_symbols=>get_obj_info( iv_name = '' ).

  LOOP AT it_all ASSIGNING FIELD-SYMBOL(<o>).

    DATA(lv_ref) = ||.

    IF <o>-reference IS BOUND.
      lv_ref = <o>-object_name.
    ENDIF.

    WRITE: / <o>-name, <o>-type, <o>-reftypeloc, <o>-global_name, <o>-relative_name, <o>-object_name, <o>-object_id, lv_ref, <o>-error.
  ENDLOOP.

Variante 2 (Container)

DATA: o_dock TYPE REF TO cl_gui_docking_container.
DATA: o_text TYPE REF TO cl_gui_textedit.

DATA: it_fieldlist TYPE STANDARD TABLE OF rfieldlist WITH DEFAULT KEY.

PARAMETERS: p_matnr TYPE mara-matnr.

INITIALIZATION.

  IF NOT o_dock IS BOUND.
* GUI-Objekte für Test erzeugen
    o_dock = NEW #( side  = cl_gui_docking_container=>dock_at_bottom
                    ratio = 90 ).

    o_text = NEW #( parent = o_dock ).
  ENDIF.

AT SELECTION-SCREEN.
* Liste der globalen Daten eines Programms
  CALL FUNCTION 'GET_GLOBAL_SYMBOLS'
    EXPORTING
      program      = sy-repid
      name_pattern = '*'
    TABLES
      fieldlist    = it_fieldlist.

START-OF-SELECTION.
* globalen Daten nach Referenztypen durchloopen
  LOOP AT it_fieldlist ASSIGNING FIELD-SYMBOL(<f>) WHERE type = 'r' AND reftypeloc = 'CLAS' AND name(1) <> '%'.

    WRITE: / '         name:', <f>-name.

* Globalen Namen des Objekts ermitteln
    DATA(lv_global_name) = |({ sy-repid }){ <f>-name }|.
    WRITE: / '  global name:', lv_global_name.

* Dirty Assign: Namen an Feldsymbol vom TYPE ANY binden
    ASSIGN (lv_global_name) TO FIELD-SYMBOL(<o>).
    IF <o> IS ASSIGNED.
      TRY.
* <o> ist eine Referenz
          IF <o> IS BOUND.
* Descriptor für Objektreferenz
            DATA(o_desc) = cl_abap_typedescr=>describe_by_object_ref( <o> ).

            WRITE: / 'relative name:', o_desc->get_relative_name( ).

            DATA: lv_oid TYPE i.

* ObjektID zur Referenz ermitteln
            CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'GET_OBJID'
                                   ID 'OBJID'  FIELD lv_oid      " Rückgabe: ObjectID
                                   ID 'OBJ'    FIELD <o>.

            WRITE: / '  object name:', |\{O:{ lv_oid }*{ o_desc->absolute_name }|.

* Gegenprobe
            DATA: o_ref_weak TYPE REF TO object.

* Referenz zur ObjektID ermitteln
            CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'WEAK_REF_GET'
                                   ID 'OID'    FIELD lv_oid
                                   ID 'OBJ'    FIELD o_ref_weak. " Rückgabe: Objekt-Referenz

            IF o_ref_weak IS BOUND.
* Descriptor für Objektreferenz
              DATA(o_desc_weak) = cl_abap_typedescr=>describe_by_object_ref( o_ref_weak ).
              WRITE: / 'relative name weak:', o_desc_weak->get_relative_name( ).
              WRITE: / '  object name weak:', |\{O:{ lv_oid }*{ o_desc_weak->absolute_name }|.
            ENDIF.

* Falls cl_gui_container: Children anzeigen
            TRY.
                DATA(o_cont) = CAST cl_gui_container( <o> ).

                LOOP AT o_cont->children ASSIGNING FIELD-SYMBOL(<child>).
                  DATA(o_desc_child) = cl_abap_typedescr=>describe_by_object_ref( <child> ).
                  WRITE: / ' --> child relative name:', o_desc_child->get_relative_name( ).
                ENDLOOP.
              CATCH cx_root.
            ENDTRY.
          ELSE.
            WRITE: 'keine Referenz verfügbar.'.
          ENDIF.

        CATCH cx_root INTO DATA(e_txt).
          WRITE: / e_txt->get_text( ).
      ENDTRY.
    ELSE.
      WRITE: 'Feldsymbol nicht zugewiesen:', lv_global_name.
    ENDIF.

    ULINE.
  ENDLOOP.