Поэкспериментировал, после работы в DOI можно сохранить книгу (методом save_as) и переоткрыть ее с помошью OLE. Так все работает более менее нормально.
Передачу данных ABAP->EXCEL лучше выполнять через DOI - метод insert_one_table работает очень быстро
Запуск макроса(ов) лучше произвести через OLE
Все остальное декоративное оформление делается макросом на VBA
Большего, собственно, и не требуется
ABAP:
Code:
* Передача данных, запуск макроса, и открытие EXCEL через DOI/OLE
REPORT ztest NO STANDARD PAGE HEADING.
TYPE-POOLS:
sbdst,
soi,
ole2.
CONSTANTS doc_classname TYPE sbdst_classname VALUE 'Z_TEMPLATES'. " Класс документа (в OAOR)
CONSTANTS doc_classtype TYPE sbdst_classtype VALUE 'OT'. " Тип документа (в OAOR)
CONSTANTS doc_name TYPE bapibds01-objkey VALUE 'TEST'. " Описание в (OAOR)
CONSTANTS xx TYPE I VALUE 1000. " Длиня данных в ячейках тестовой таблицы
* Таблицы и рабочие области
DATA doc_uris TYPE sbdst_uri.
DATA wa_doc_uris LIKE LINE OF doc_uris.
* Объекты DOI/EXCEL
DATA container TYPE REF TO cl_gui_custom_container.
DATA container_control TYPE REF TO i_oi_container_control.
DATA document_proxy TYPE REF TO i_oi_document_proxy.
DATA sheet_interface TYPE REF TO i_oi_spreadsheet.
* Объекты OLE/EXCEL
DATA application TYPE ole2_object. " Application (EXCEL)
DATA workbooks TYPE ole2_object. " Workbooks
DATA workbook TYPE ole2_object. " Workbook
DATA activewindow TYPE ole2_object. " ActiveWindow
* Переменные
DATA retcode TYPE soi_ret_string.
DATA fields_table TYPE soi_fields_table.
DATA handle TYPE cntl_handle.
DATA sapworkdir TYPE STRING.
DATA filepath TYPE STRING.
DATA file_name(256) TYPE C.
DATA text(256) TYPE C.
* Таблица для заполнения данными и передачи в EXCEL
DATA:
BEGIN OF data_table OCCURS 0,
field01(xx) TYPE C,
field02(xx) TYPE C,
field03(xx) TYPE C,
field04(xx) TYPE C,
field05(xx) TYPE C,
field06(xx) TYPE C,
field07(xx) TYPE C,
field08(xx) TYPE C,
field09(xx) TYPE C,
field10(xx) TYPE C,
field11(xx) TYPE C,
field12(xx) TYPE C,
field13(xx) TYPE C,
field14(xx) TYPE C,
field15(xx) TYPE C,
field16(xx) TYPE C,
field17(xx) TYPE C,
field18(xx) TYPE C,
field19(xx) TYPE C,
field20(xx) TYPE C,
field21(xx) TYPE C,
field22(xx) TYPE C,
field23(xx) TYPE C,
field24(xx) TYPE C,
field25(xx) TYPE C,
field26(xx) TYPE C,
field27(xx) TYPE C,
field28(xx) TYPE C,
field29(xx) TYPE C,
field30(xx) TYPE C,
field31(xx) TYPE C,
field32(xx) TYPE C,
field33(xx) TYPE C,
field34(xx) TYPE C,
field35(xx) TYPE C,
field36(xx) TYPE C,
field37(xx) TYPE C,
field38(xx) TYPE C,
field39(xx) TYPE C,
field40(xx) TYPE C,
field41(xx) TYPE C,
field42(xx) TYPE C,
field43(xx) TYPE C,
field44(xx) TYPE C,
field45(xx) TYPE C,
field46(xx) TYPE C,
field47(xx) TYPE C,
field48(xx) TYPE C,
field49(xx) TYPE C,
field50(xx) TYPE C,
END OF data_table.
DATA row TYPE sy-index.
DATA value TYPE P.
FIELD-SYMBOLS <fs>.
* Инициализация:
* Получаем урл шаблона (из BDS - транзакция OAOR)
CALL METHOD cl_bds_document_set=>get_with_url
EXPORTING
classname = doc_classname " 'Z_TEMPLATES'
classtype = doc_classtype " 'TO'
CHANGING
uris = doc_uris
EXCEPTIONS
nothing_found = 1
error_kpro = 2
internal_error = 3
parameter_error = 4
not_authorized = 5
not_allowed = 6
OTHERS = 7.
IF ( sy-subrc <> 0 ).
MESSAGE 'Не нашли шаблон' TYPE 'S'.
RETURN.
ENDIF.
* Найти шаблон в списке
LOOP AT doc_uris INTO wa_doc_uris.
IF ( wa_doc_uris-uri CS doc_name ). " 'TEST'
EXIT.
ENDIF.
ENDLOOP.
IF NOT ( wa_doc_uris-uri CS doc_name ).
MESSAGE 'Не нашли шаблон' TYPE 'S'.
RETURN.
ENDIF.
* Создаем экземпляр SAP DOI ActiveX Control
CLEAR retcode.
CALL METHOD c_oi_container_control_creator=>get_container_control
IMPORTING
control = container_control
* ERROR =
retcode = retcode
.
* Инициализируем объект, container_control содержит ссылку на него
CALL METHOD container_control->init_control
EXPORTING
r3_application_name = 'R/3 application'
parent = container
* register_on_close_event = 'X'
* register_on_custom_event = 'X'
* inplace_enabled = 'X'
* inplace_scroll_documents = 'X'
* no_flush = 'X'
.
* Получаем документ
CLEAR retcode.
CALL METHOD container_control->get_document_proxy
EXPORTING
* DOCUMENT_FORMAT = 'NATIVE'
document_type = ''
* no_flush = ' '
register_container = 'X'
IMPORTING
document_proxy = document_proxy
* ERROR =
retcode = retcode
.
* Открываем книгу EXCEL (шаблон)
CLEAR retcode.
CALL METHOD document_proxy->open_document
EXPORTING
* DOCUMENT_TITLE = ''
document_url = wa_doc_uris-uri
* NO_FLUSH = ' '
* OPEN_INPLACE = ' '
* OPEN_READONLY = ' '
* PROTECT_DOCUMENT = ' '
* ONSAVE_MACRO = ' '
* STARTUP_MACRO = ''
* USER_INFO = USER_INFO
IMPORTING
* ERROR = ERROR
retcode = retcode
.
* Получаем handle
CLEAR retcode.
CALL METHOD document_proxy->get_document_handle
* EXPORTING
* no_flush = ' '
IMPORTING
* error = error
handle = handle
retcode = retcode
.
* Получаем OLE-объект Excel
GET PROPERTY OF handle-obj 'Application' = application.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
* Получаем OLE-объект активного окна
CALL METHOD OF application 'ActiveWindow' = activewindow.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
* Максимизируем активное окно (Application.ActiveWindow.WindowState = xlMaximized)
SET PROPERTY OF activewindow 'WindowState' = -4137. " xlMaximized
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
FREE OBJECT activewindow.
FREE OBJECT application.
* Передаем табличные данные в книгу EXCEL:
* Получим табличный интерфейс
CLEAR retcode.
CALL METHOD document_proxy->get_spreadsheet_interface
* EXPORTING
* NO_FLUSH = ''
IMPORTING
* ERROR =
sheet_interface = sheet_interface
retcode = retcode
.
* Заполняем данными внутреннюю таблицу (для передачи в EXCEL)
REFRESH data_table.
row = 0.
DO 1000 TIMES.
CLEAR data_table.
DO 50 TIMES.
UNASSIGN <fs>.
ASSIGN COMPONENT sy-index OF STRUCTURE data_table TO <fs>.
IF ( <fs> IS ASSIGNED ).
value = row * 50 + sy-index.
WRITE value TO text LEFT-JUSTIFIED NO-GROUPING.
CONCATENATE text 'Hello, Hello, Hello, Hello, Hello, Hello, Hello, Hello, Hello, Hello, Hello!' INTO <fs> SEPARATED BY space.
ENDIF.
ENDDO.
APPEND data_table.
row = row + 1.
ENDDO.
* Получаем описание полей таблицы
CALL FUNCTION 'DP_GET_FIELDS_FROM_TABLE'
TABLES
data = data_table
fields = fields_table
.
* Создаем диапазон в EXCEL
CLEAR retcode.
CALL METHOD sheet_interface->insert_range_dim
EXPORTING
* NO_FLUSH = ' '
name = 'range'
left = 1
top = 1
rows = 1
columns = 1
* UPDATING = -1
* SHEETNAME = ''
IMPORTING
* ERROR = ERROR
retcode = retcode
.
* Вставляем данные из таблицы в EXCEL
CLEAR retcode.
CALL METHOD sheet_interface->insert_one_table
EXPORTING
* DDIC_NAME =
data_table = data_table[]
fields_table = fields_table[]
rangename = 'range'
* NO_FLUSH = ' '
wholetable = 'X' " Вставляем все данные независимо от границ диапазона
* UPDATING = -1
IMPORTING
* ERROR = ERROR
retcode = retcode
.
* Сохраняем книгу EXCEL:
* Директорий для сохранения
CLEAR sapworkdir.
CALL METHOD cl_gui_frontend_services=>get_sapgui_workdir
CHANGING
sapworkdir = sapworkdir
.
* Путь к файлу для сохранения
CONCATENATE sapworkdir '\' doc_name '-' sy-timlo '.xls' INTO filepath.
* Сохраняем книгу EXCEL в файле
file_name = filepath.
CLEAR retcode.
CALL METHOD document_proxy->save_as
EXPORTING
file_name = file_name
* NO_FLUSH = ' '
* PROMPT_USER = ' '
IMPORTING
* ERROR = ERROR
retcode = retcode
.
* Закрываем книгу EXCEL/DOI:
CLEAR retcode.
CALL METHOD document_proxy->close_document
* EXPORTING
* DO_SAVE = ' '
* NO_FLUSH = ' '
IMPORTING
* ERROR = ERROR
* HAS_CHANGED = HAS_CHANGED
retcode = retcode
.
CLEAR retcode.
CALL METHOD document_proxy->release_document
* EXPORTING
* NO_FLUSH = ' '
IMPORTING
* ERROR = ERROR
retcode = retcode
.
FREE sheet_interface.
FREE document_proxy.
FREE container_control.
FREE container.
* Открываем сохраненную книгу EXCEL через OLE:
* Стартуем Excel
CREATE OBJECT application 'EXCEL.APPLICATION'.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
* Получить список книг, изначально пустой
CALL METHOD OF application 'Workbooks' = workbooks.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
* Открываем сохраненную книгу
CALL METHOD OF workbooks 'Open' = workbook EXPORTING #1 = file_name.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
* Делаем EXCEL видимым
SET PROPERTY OF application 'Visible' = 1.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
* Запускаем макрос StartMacro
CALL METHOD OF application 'Run' EXPORTING #1 = 'StartMacro'.
IF ( sy-subrc <> 0 ).
WRITE: / 'Ошибка OLE-Automation:', sy-subrc.
STOP.
ENDIF.
VBA:
Code:
Public Sub StartMacro()
Cells(1, 1).Value = "Hello, SAP!"
Application.WindowState = xlMinimized
Application.WindowState = xlMaximized
MsgBox "Hello, SAP!"
End Sub
В основном проблема была в том чтобы не мешались уже открытые книги EXCEL