Работа с LibreOffice, как с Com-объектом

Автор Борис_С, 22 октября 2021, 17:15

0 Пользователи и 1 гость просматривают эту тему.

Борис_С

Всем доброго дня.
Подскажите, пожалуйста, можно ли работать с LibreOffice, OpenOffice как с Com-объектоми, и если да, как их запустить на c#?
Спасибо.

sokol92

Владимир.

Борис_С

Какое отношение имеет тема "После обработки документа во Writer из макроса нельзя закрыть приложение" к работе с Com-объектом?
Это абсолютно разные вещи.
Мне бы хотелось бы работать с LibreOffice (OpenOffice) так же как и с Microsoft Office через Com (ActiveX).
Есть ли такая возможность?

mikekaganski

Цитата: Борис_С от 25 октября 2021, 12:57Какое отношение имеет тема "После обработки документа во Writer из макроса нельзя закрыть приложение" к работе с Com-объектом?
Возможно то, что скрипт в той теме создавал и работал с COM-объектами?
С уважением,
Михаил Каганский

Борис_С

Почему вы так решили? Там нигде про это не написано. Там просто говорится о работе с макросом.

mikekaganski

Цитата: Борис_С от 25 октября 2021, 13:15Почему вы так решили?
Потому что мы внимательно читали ;)

Тот вопрос про запуск и управление ЛО из скрипта VBS, который не связан с ЛО. Он создаёт объекты с помощью VBS-вызова CreateObject (и всё это там написано ;))
С уважением,
Михаил Каганский

sokol92

#6
Цитата: Борис_С от 25 октября 2021, 12:57Мне бы хотелось бы работать с LibreOffice (OpenOffice) так же как и с Microsoft Office через Com (ActiveX).
Рассмотрим, например, фрагменты скрипта из сообщения #19 указанной темы (фрагменты).

ServMan = CreateObject("com.sun.star.ServiceManager")  ' создает ActiveX объект ("фабрика" для создания сервисов LO)
Dsctp = ServMan.createInstance("com.sun.star.frame.Desktop")  ' создает объект для работы с фреймами
' ------------------
WriteDoc = Dsctp.loadComponentFromURL("file:///c:/temp/mail_a1.dotx", "_blank", 0, arg)  ' открывет документ (шаблон Word)
' ------------------
Set BFields = WriteDoc.getBookmarks() ' создает объект для работы с закладками документа
' ------------------


Указанный скрипт можно, естественно, запускать из приложений MS Office (VBA) или из любой программы, поддерживающей работу с ActiveX объектами (с поправками на синтаксис языка). Интересно, что объекты 64-разрядного LO могут управляться через интерфейсы автоматизации из 32-разрядных приложений (например, из 32-разрядной версии Excel).
Владимир.

Борис_С

А работает это в С#, и, если да, какие библиотеки нужно подключить?

mikekaganski

https://api.libreoffice.org/examples/examples.html#OLE_examples

Кроме ActiveX, есть ещё привязка CLI. Я сам не писал на C# для ЛО, но например здесь пишут про подключение библиотек cli_*.dll из SDK.
С уважением,
Михаил Каганский

Борис_С

Спасибо за информацию.
Нашел в интернете очень хорошую статью про ActiveX и CLI - http://venec.ulstu.ru/lib/disk/2014/45.pdf
Там много кода и вопросы запуска приложения, загрузки документов и закрытия приложения сразу решились.
Начал с ActiveX. Выяснилось, что ActiveX не поддерживает некоторые методы API (при обращении к этим методам
получаю исключение), а кроме того при этом очень сложно отлаживаться, т.к. все объекты, с которыми нужно работать имеют тип Object.
Перешел на работу с использованием CLI-библиотек.
Нигде не нашел описание объектов и методов CLI-библиотек.
Научился читать информацию из документов,
вставлять гиперссылки в ячейках в OO Calc (как это сделать нашел в Spreadsheet Example).
Но нигде не нашел, как вставлять гиперссылки в ОО Writer.
Также не нашел, как найти гиперссылки в OO Calc и в ОО Writer.
Буду признателен за любые советы.

sokol92

#10
На вопрос "где искать" первый ответ (часто и последний) - у А.Питоньяка. Про поиск гиперссылок в ячейках Calc см. раздел 15.11 OOME_4_0.odt.

Моя точка зрения: для LO в настоящий момент целесообразно использовать Basic и/или Python.
Владимир.

Борис_С

У Питоньяка описана работа с API OpenOffice. Я же работаю с объектами, их методами и свойствами CLI-библиотек.

Для API OpenOffice для получения гиперссылок в ячейке используется операторы
oCell = ThisComponent.Sheets(0).getCellByPosition(0, 0)
oParEnum = oCell.getText().createEnumeration()

Для API CLI-библиотек все иначе (на C#):
unoidl.com.sun.star.sheet.XSpreadsheetDocument mxDocument =
                        (unoidl.com.sun.star.sheet.XSpreadsheetDocument)xComponent;
unoidl.com.sun.star.sheet.XSpreadsheets d =
                        (unoidl.com.sun.star.sheet.XSpreadsheets)(((unoidl.com.sun.star.sheet.
XSpreadsheetDocument)xComponent).getSheets());
string[] sheets = d.getElementNames();                   
uno.Any t = d.getByName(sheets[0]);
unoidl.com.sun.star.sheet.XSpreadsheet xSheet =
           unoidl.com.sun.star.sheet.XSpreadsheet)t.Value;
unoidl.com.sun.star.table.XCell xCell = xSheet.getCellByPosition(0, 0)
у xCell нет метода getText()
и соответственно и createEnumeration() мне не получить

mikekaganski

#12
Цитата: Борис_С от 30 ноября 2021, 21:11
У Питоньяка описана работа с API OpenOffice. Я же работаю с объектами, их методами и свойствами CLI-библиотек.

...

Для API CLI-библиотек все иначе (на C#):
...
unoidl.com.sun.star.table.XCell xCell = xSheet.getCellByPosition(0, 0)
у xCell нет метода getText()
и соответственно и createEnumeration() мне не получить

Вы ошибаетесь. В обоих случаях используется один и тот же UNO API, документированный здесь. Разница лишь в используемом языке: если Вы используете язык с нестрогой типизацией, типа Basic (или с утиной динамической типизацией, типа Python), то Вы просто обращаетесь с объектом, как имеющим нужный Вам интерфейс, и если это оказывается верно в рантайме, всё в порядке. В шарпе нужно явно приводить объект к нужному типу, если Вы хотите воспользоваться методами/свойствами определённого интерфейса, реализуемого им. Конкретный объект, возвращаемый getCellByPosition, реализует целую кучу интерфейсов, а не только com.sun.star.table.XCell. createEnumeration - метод com.sun.star.container.XEnumerationAccess, что легко определить поиском метода на странице документации API, указанной выше. getText имеют несколько интерфейсов (см. скриншот). Интерфейсы, реализованные в объекте, можно узнать методом getTypes интерфейса com.sun.star.lang.XTypeProvider. Ещё полезен список сервисов, возвращаемый getSupportedServiceNames.

Кстати, именно единство API является одновременно сильной стороной (из любого языка можно получить доступ ко всему; переход с языка на язык производится просто сменой синтаксиса) и проблемой для неопытных программистов (нет упрощённых способов сделать частоиспользуемые действия, и нужно постоянно обращаться к очень технически ориентированной документации, которая не имеет хорошего описания и достаточного количества примеров).
С уважением,
Михаил Каганский

sokol92

Замечательная программа (расширение) MRI является еще и полиглотом!

Открываем (создаем) документ Calc. Запускаем
mri ThisComponent
далее в меню MRI Tools / Code / C# CLI.
Переходим на вкладку Methods и последовательно вызываем соответствующие методы с соответствующими параметрами (вплоть до получения Enumeration).
Получаем записанный код:

using System;
using unoidl.com.sun.star.container;
using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.sheet;
using unoidl.com.sun.star.table;
using unoidl.com.sun.star.text;
using unoidl.com.sun.star.uno;

public class Snippet {
public void snippet(XComponentContext xContext, object oInitialTarget)
{
try
{
XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument) oInitialTarget;
XSpreadsheets xSpreadsheets = xSpreadsheetDocument.getSheets();

XIndexAccess xIndexAccess = (XIndexAccess) xSpreadsheets;
XSpreadsheet xSpreadsheet = (XSpreadsheet) xIndexAccess.getByIndex(0).Value;
XCellRange xCellRange = (XCellRange) xSpreadsheet;
XCell xCell = xCellRange.getCellByPosition(0, 0);

XTextRange xTextRange = (XTextRange) xCell;
XText xText = xTextRange.getText();

XEnumerationAccess xEnumerationAccess = (XEnumerationAccess) xText;
XEnumeration xEnumeration = xEnumerationAccess.createEnumeration();

}
catch (IndexOutOfBoundsException e)
{
// getByIndex, getCellByPosition
Console.WriteLine(e.Message);
}
catch (WrappedTargetException e)
{
// getByIndex
Console.WriteLine(e.Message);
}
catch (RuntimeException e)
{
// createEnumeration
Console.WriteLine(e.Message);
}
}
}


Протестируйте, пожалуйста, этот подход и расскажите нам о впечатлениях.

Кстати, гуру @JohnSUN выложил в YouTube обучающее видео, посвященное MRI (в ностальгическом стиле старого немого кино, правда, цветное и без музыкального сопровождения. :)).

Владимир.

Борис_С

Цитата: mikekaganski от  1 декабря 2021, 09:18Интерфейсы, реализованные в объекте, можно узнать методом getTypes интерфейса com.sun.star.lang.XTypeProvider.
Попробовал использовать метод getTypes и получил такой результат.