[ABAP] Desktop Office Integration (DOI): Eventhandler, leeres Dokument erzeugen, Zugriff auf Ole-Funktionen für Ole-Automation

* https://www.consolut.com/fileadmin/user_upload/SAP_PrintDoku/de/BCCIOFFI/BCCIOFFI.PDF
* https://www.saptechpro.com/post/SAPRDEMO_MS_DEMO
* https://www.saptechpro.com/post/SAPRDEMODOCUMENTCONTAINER2

* Eventhandler für Excel on_closed
CLASS lcl_events DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: on_close FOR EVENT on_close_document OF i_oi_document_proxy
      IMPORTING
          document_proxy
          has_changed.
ENDCLASS.

CLASS lcl_events IMPLEMENTATION.
  METHOD on_close.
    MESSAGE 'Excel closed.' TYPE 'S' DISPLAY LIKE 'W'.
  ENDMETHOD.
ENDCLASS.

* Dummy-Screen für cl_gui_container=>default_screen deklarieren
SELECTION-SCREEN BEGIN OF SCREEN 100.
SELECTION-SCREEN END OF SCREEN 100.

START-OF-SELECTION.

  TRY.

* Daten mit DOI (Excel inplace) anzeigen
      DATA: o_oic TYPE REF TO i_oi_container_control.
      DATA: o_oid TYPE REF TO i_oi_document_proxy.
      DATA: o_err TYPE REF TO i_oi_error.
      DATA: it_errors TYPE STANDARD TABLE OF REF TO i_oi_error WITH NON-UNIQUE DEFAULT KEY.

      c_oi_container_control_creator=>get_container_control( IMPORTING
                                                               control = o_oic
                                                               error   = o_err ).

      APPEND o_err TO it_errors.

      IF abap_true = o_err->has_succeeded.
        o_oic->init_control( EXPORTING
                               inplace_enabled         = abap_false
                               no_flush                = abap_true
                               r3_application_name     = 'Excel Daten'
                               parent                  = cl_gui_container=>default_screen
                               register_on_close_event = abap_true
                             IMPORTING
                               error                   = o_err ).

        APPEND o_err TO it_errors.

        IF abap_true = o_err->has_succeeded.
          o_oic->get_document_proxy( EXPORTING
                                       document_type  = soi_doctype_excel_sheet " 'Excel.Sheet'
                                     IMPORTING
                                       document_proxy = o_oid
                                       error          = o_err ).
          APPEND o_err TO it_errors.

          IF abap_true = o_err->has_succeeded.
* neues, leeres Workbook einfügen
            o_oid->create_document( EXPORTING
                                      document_title = 'Excel Test'
                                      open_inplace   = abap_false
                                    IMPORTING
                                      error          = o_err ).

* Event-Handler für on_close Event
            SET HANDLER lcl_events=>on_close FOR o_oid.

* Abfrage nach dem Automation-Handle des Dokumentes
            DATA: lv_cntl_handle TYPE cntl_handle.
            o_oid->get_document_handle( IMPORTING
                                          handle  = lv_cntl_handle
                                          error   = o_err ).

            APPEND o_err TO it_errors.

            IF abap_true = o_err->has_succeeded.

* Ole-Funktionen Direkt aufrufen
              DATA: o_xl_ole TYPE ole2_object.
              DATA: o_cell_ole TYPE ole2_object.
              GET PROPERTY OF lv_cntl_handle-obj 'Application' = o_xl_ole.
              CALL METHOD OF o_xl_ole 'Cells' = o_cell_ole
                EXPORTING
                  #1 = 1
                  #2 = 1.
              SET PROPERTY OF o_cell_ole 'Value' = 'Test'.
              FREE OBJECT o_cell_ole.
              FREE OBJECT o_xl_ole.

* leere Toolbar ausblenden
              cl_abap_list_layout=>suppress_toolbar( ).

* cl_gui_container=>default_screen erzwingen
              CALL SCREEN 100.

* Schließen eines Dokuments in der Office-Anwendung
              o_oid->close_document( IMPORTING error = o_err ).

              APPEND o_err TO it_errors.

              IF o_err->has_succeeded = abap_true.

* Schließen eines Visual-Basic-Dokuments
                o_oid->close_activex_document( IMPORTING error = o_err ).

                APPEND o_err TO it_errors.

                IF o_err->has_succeeded = abap_true.

* Freigabe des für das Dokument reservierten Speichers
                  o_oid->release_document( IMPORTING error = o_err ).

                  APPEND o_err TO it_errors.

                  IF o_err->has_succeeded = abap_true.
                    FREE: o_oid.
                  ENDIF.
                ENDIF.
              ENDIF.
            ENDIF.

* baut das Control ab
            o_oic->destroy_control( IMPORTING error = o_err ).

            APPEND o_err TO it_errors.

            IF o_err->has_succeeded = abap_true.
              FREE: o_oic.
            ENDIF.

          ENDIF.
        ENDIF.
      ENDIF.

* Ausgabe Fehlerprotokoll
      DATA: lv_message_id TYPE sy-msgid.
      DATA: lv_message_number TYPE sy-msgno.
      DATA: lv_param1 TYPE sy-msgv1.
      DATA: lv_param2 TYPE sy-msgv2.
      DATA: lv_param3 TYPE sy-msgv3.
      DATA: lv_param4 TYPE sy-msgv4.

      LOOP AT it_errors ASSIGNING FIELD-SYMBOL(<e>).
        <e>->get_message( IMPORTING
                            message_id     = lv_message_id
                            message_number = lv_message_number
                            param1         = lv_param1
                            param2         = lv_param2
                            param3         = lv_param3
                            param4         = lv_param4
                        ).
        WRITE: / <e>->error_code, lv_message_id, lv_message_number, lv_param1, lv_param2, lv_param3, lv_param4.
      ENDLOOP.

    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] Excel-Datei (*.xlsx) mit Desktop-Office-Integration (DOI) laden und anzeigen

* Dummy-Screen für cl_gui_container=>default_screen deklarieren
SELECTION-SCREEN BEGIN OF SCREEN 100.
SELECTION-SCREEN END OF SCREEN 100.

START-OF-SELECTION.

  TRY.
      DATA: lv_rc TYPE i.
      DATA: it_files TYPE filetable.
      DATA: lv_action TYPE i.

* FileOpen-Dialog aufrufen
      cl_gui_frontend_services=>file_open_dialog( EXPORTING
                                                    file_filter = |xlsx (*.xlsx)\|*.xlsx\|{ cl_gui_frontend_services=>filetype_all }|
                                                  CHANGING
                                                    file_table  = it_files
                                                    rc          = lv_rc
                                                    user_action = lv_action ).

      IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn Datei ausgewählt wurde
        IF lines( it_files ) > 0.

          DATA: o_oic TYPE REF TO i_oi_container_control.
          DATA: o_oid TYPE REF TO i_oi_document_proxy.
          DATA: o_err TYPE REF TO i_oi_error.

          c_oi_container_control_creator=>get_container_control( IMPORTING
                                                                   control = o_oic
                                                                   error   = o_err ).

          IF abap_true = o_err->has_succeeded.
            o_oic->init_control( EXPORTING
                                   inplace_enabled     = abap_true
                                   no_flush            = abap_true
                                   r3_application_name = 'Excel Tabelle'
                                   parent              = cl_gui_container=>default_screen
                                 IMPORTING
                                   error               = o_err ).

            IF abap_true = o_err->has_succeeded.
              o_oic->get_document_proxy( EXPORTING
                                           document_type  = soi_doctype_excel_sheet " 'Excel.Sheet'
                                         IMPORTING
                                           document_proxy = o_oid
                                           error          = o_err ).

              IF abap_true = o_err->has_succeeded.
* URL muss für das Laden eines lokalen Files mit 'FILE://' beginnen
                DATA(lv_file) = 'FILE://' && it_files[ 1 ]-filename.
* *.xlsx von URL (File) laden und anzeigen
                o_oid->open_document( EXPORTING
                                        document_title = 'Excel'
                                        document_url   = CONV swk_url( lv_file )
                                        open_inplace   = abap_true
                                      IMPORTING
                                        error          = o_err ).

                IF abap_true = o_err->has_succeeded.
* leere Toolbar ausblenden
                  cl_abap_list_layout=>suppress_toolbar( ).

* cl_gui_container=>default_screen erzwingen
                  CALL SCREEN 100.

* Schließen eines Dokuments in der Office-Anwendung
                  o_oid->close_document( IMPORTING error = o_err ).
                  IF o_err->has_succeeded = abap_true.

* Schließen eines Visual-Basic-Dokuments
                    o_oid->close_activex_document( IMPORTING error = o_err ).
                    IF o_err->has_succeeded = abap_true.

* Freigabe des für das Dokument reservierten Speichers
                      o_oid->release_document( IMPORTING error = o_err ).

                      IF o_err->has_succeeded = abap_true.
                        FREE: o_oid.
                      ENDIF.
                    ENDIF.
                  ENDIF.

* baut das Control ab
                  o_oic->destroy_control( IMPORTING error = o_err ).

                  IF o_err->has_succeeded = abap_true.
                    FREE: o_oic.
                  ENDIF.

                ENDIF.
              ENDIF.
            ENDIF.
          ENDIF.
        ENDIF.
      ENDIF.

    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] Desktop-Office-Integration (DOI) (Listausgabe / MS Excel inplace)

Vorteile

  • Einfacher unkomplizierter Zugriff auf MS Excel-Dateien

Nachteile

  • Office muss auf dem Clientrechner installiert sein, nicht zur Ausführung per Job geeignet
  • Einbettung in SAP Document Container Control: Kapselung von ActiveX / OLE2, daher rel. langsam
  • Interface unterstützt nur 9999 Zeilen und Spalten, da row und column vom Typ C(4)
  • kann alles besser über OLE2-Objekte manuell abgebildet werden -> mehr Freiheitsgrade
* Demoprogramme:
*   SAPRDEMO_DOI_BDS
*   SAPRDEMO_FORM_INTERFACE
*   SAPRDEMO_SPREADSHEET_INTERFACE
*   SAPRDEMO_MAILMERGE_INTERFACE
* Interface:
*   I_OI_DOCUMENT_PROXY

DATA: lv_has_activex TYPE abap_bool.

CALL FUNCTION 'GUI_HAS_ACTIVEX'
  IMPORTING
    return = lv_has_activex.

IF lv_has_activex = abap_true.
  DATA: lv_error TYPE REF TO i_oi_error.
  DATA: lv_size TYPE i.
  DATA: it_xl_upload TYPE umb_bds_content.
  DATA: o_control TYPE REF TO i_oi_container_control.
  DATA: o_document TYPE REF TO i_oi_document_proxy.
  DATA: o_spreadsheet TYPE REF TO i_oi_spreadsheet.

  cl_gui_frontend_services=>gui_upload( EXPORTING
                                          filename     = 'c:\temp\Excel.xlsx'
                                          filetype     = 'BIN'
                                          read_by_line = space
                                        IMPORTING
                                          filelength   = lv_size
                                        CHANGING
                                          data_tab     = it_xl_upload ).

* Erzeugt eine Container-Control-Instanz
  c_oi_container_control_creator=>get_container_control( IMPORTING
                                                           control = o_control
                                                           error   = lv_error ).

  IF lv_error->has_succeeded = abap_true.
* erzeugt und initializiert das Control
    o_control->init_control( EXPORTING
                               no_flush                 = abap_true
                               r3_application_name      = 'DOI Beispiel'
                               parent                   = cl_gui_container=>default_screen
                               inplace_enabled          = abap_true
                               inplace_show_toolbars    = abap_false
                               inplace_scroll_documents = abap_true
                               register_on_close_event  = abap_true
                               register_on_custom_event = abap_true
                             IMPORTING
                               error                 = lv_error ).

    IF lv_error->has_succeeded = abap_true.
* erzeugt eine Instanz für die Verwaltung eines Dokuments
      o_control->get_document_proxy( EXPORTING
                                       document_type  = soi_doctype_excel_sheet
                                       no_flush       = abap_true
                                     IMPORTING
                                       document_proxy = o_document
                                       error          = lv_error ).

      IF lv_error->has_succeeded = abap_true.
* Öffnen eines bereits existierenden Dokuments
        o_document->open_document_from_table( EXPORTING
                                                 document_size    = lv_size
                                                 document_table   = it_xl_upload
                                                 document_title   = 'DOI Beispiel'
                                                 open_inplace     = abap_true " SAP Inplace anzeigen oder extern in MS Excel
                                                 protect_document = ' '
                                               IMPORTING
                                                 error            = lv_error ).

        IF lv_error->has_succeeded = abap_true.
* liefert eine Interface-Referenz zurück
          o_document->get_spreadsheet_interface( IMPORTING
                                                   sheet_interface = o_spreadsheet
                                                   error           = lv_error ).

          IF lv_error->has_succeeded = abap_true.
            DATA: it_cells TYPE soi_generic_table.
            DATA: it_ranges TYPE soi_range_list.
            DATA: lv_retcode TYPE soi_ret_string.

            it_ranges = VALUE #( ( name = 'MyRange' ) ).

* Einfügen eines Bereiches ausgehend von den Dimensionen
            o_spreadsheet->insert_range_dim( EXPORTING
                                               name = it_ranges[ 1 ]-name
                                               top = 1
                                               left = 1
                                               rows = 10
                                               columns = 10
                                               no_flush = abap_true ).

* Holen der Namen und der Daten der Bereiche
            o_spreadsheet->get_ranges_data( EXPORTING
                                              all      = abap_false
                                            IMPORTING
                                              contents = it_cells
                                              error    = lv_error
                                              retcode  = lv_retcode
                                            CHANGING
                                              ranges   = it_ranges ).

            LOOP AT it_cells ASSIGNING FIELD-SYMBOL(<fs_cells>) GROUP BY <fs_cells>-row.
              DATA(lv_line) = ||.

              LOOP AT GROUP <fs_cells> ASSIGNING FIELD-SYMBOL(<fs_col>).
                IF lv_line IS INITIAL.
                  lv_line = |{ <fs_col>-value WIDTH = 20 }|.
                ELSE.
                  lv_line = |{ lv_line }{ <fs_col>-value WIDTH = 20 }|.
                ENDIF.
              ENDLOOP.

              WRITE: / <fs_cells>-row, lv_line.
            ENDLOOP.

* Schließen eines Dokuments in der Office-Anwendung
            o_document->close_document( IMPORTING error = lv_error ).
            IF lv_error->has_succeeded = abap_true.

* Schließen eines Visual-Basic-Dokuments
              o_document->close_activex_document( IMPORTING error = lv_error ).
              IF lv_error->has_succeeded = abap_true.

* Freigabe des für das Dokument reservierten Speichers
                o_document->release_document( IMPORTING error = lv_error ).

                IF lv_error->has_succeeded = abap_true.
                  FREE: o_document.
                ENDIF.
              ENDIF.
            ENDIF.

* baut das Control ab
            o_control->destroy_control( IMPORTING error = lv_error ).

            IF lv_error->has_succeeded = abap_true.
              FREE: o_control.
            ENDIF.

          ENDIF.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDIF.
ENDIF.

Links