Как определить название приложения из C# (отделено от https://forumooo.ru/index.php/topic,8926.0.html)

Автор Борис_С, 15 декабря 2021, 19:09

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

Борис_С

Ясно. Спасибо, Михаил.
А можно как-то узнать, какое приложение стартовало: LO или OO?
В VB это делается так:

GlobalScope.BasicLibraries.LoadLibrary("Tools")
ProgramName = GetProductname()

Я не очень представляю, как в C# CLI дать ссылку на библиотеку Tools.

Борис_С

Форумчане, подскажите, пожалуйста, в каком файле сидит библиотека Tools.

mikekaganski

Цитата: Борис_С от 15 декабря 2021, 19:09
В VB это делается так:

GlobalScope.BasicLibraries.LoadLibrary("Tools")
ProgramName = GetProductname()


Я подозреваю, что имеется ввиду не VB (Visual Basic), а StarBasic (язык семейства Basic, реализованный в OOo/LO/AOO).

1. Создаёте процедуру, вызывающую GetProductname в Basic IDE.
2. Ставите на неё точку останова.
3. Запускаете процедуру.
4. При остановке отладчика на нужной строке используете функцию Step Into (F8), и попадаете в код вызываемой функции.
5. Изучаете этот код.

В частности, Вам понадобится разобраться, что делает функция GetRegistryKeyContent (её код там же), и реализовать такую же логику чтения конфигурации на C#.
С уважением,
Михаил Каганский

Борис_С

Не знаю почему, но при нажатии на F8 на этом операторе я попадаю на след. оператор, а не вхожу внутрь.
Я не прав. Поставил точку останова не на том операторе.

Борис_С

А зачем это делать, если можно просто сослаться на библиотеку Tools и вызвать из нее функцию GetProductname() ?

mikekaganski

Библиотека Tools - это библиотека Basic. Конечно, можно воспользоваться механизмом invoke, чтобы из любого языка вызвать функции на любом языке, но это примерно как из пушки по воробьям.
С уважением,
Михаил Каганский

Борис_С

Нигде не нашел, как оператор oConfigProvider = createUnoService("com.sun.star.configuration.ConfigurationProvider")
перевести на C#

mikekaganski

Цитата: Борис_С от  6 декабря 2021, 12:37

                XComponentLoader componentLoader = (XComponentLoader)
                    multiServiceFactory.createInstance("com.sun.star.frame.Desktop");


Вот это оно (конечно, нужно изменить имя и тип сервиса).
С уважением,
Михаил Каганский

Борис_С

Забуксовал. Не могу сформировать тип сервиса. У пространства имен unoidl.com.sun.star.configuration нет сервиса ConfigurationProvider.
В API пишут, что сервис ConfigurationProvider находится в пространстве имен com::sun::star::configuration::DefaultProvider::ConfigurationProvider
В пространстве имен unoidl.com.sun.star.configuration нет имени DefaultProvider

mikekaganski

Сервис - это категория, не относящаяся к языку. Это своего рода "гарантия", предоставляемая IDL. Она не отображается на систему типов языка.

Вам нужен тип, и такими типами являются интерфейсы. В IDL их имена всегда начинаются с заглавной "X". Соответственно, когда Вы создаёте экземпляр сервиса, Вы присваиваете возвращаемый объект переменной одного из типов-интерфейсов. В Вашем случае документация сервиса ConfigurationProvider сообщает, что сервис реализует два интерфейса - XMultiServiceFactory и XComponent. Вы выбираете, какой из интерфейсов Вас интересует в данный момент. Поскольку Вы будете дальше вызывать метод createInstanceWithArguments, Вам понадобится объект класса XMultiServiceFactory.

Цитата: Борис_С от 18 января 2022, 19:19В API пишут, что сервис ConfigurationProvider находится в пространстве имен com::sun::star::configuration::DefaultProvider::ConfigurationProvider

Нет. В API пишут, что у сервиса DefaultProvider есть одноимённое свойство. Но оно Вам не нужно.
С уважением,
Михаил Каганский

sokol92

Цитата: mikekaganski от 18 января 2022, 17:09... из любого языка вызвать функции на любом языке, но это примерно как из пушки по воробьям.
Наставление по стрельбе здесь (в том числе и для C#).
Владимир.

Борис_С

В функции GetRegistryKeyContent возвращаемое значение формируется так:

GetRegistryKeyContent() = oConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aNodePath())

где

Dim aNodePath(0) as new com.sun.star.beans.PropertyValue
        oConfigProvider = createUnoService("com.sun.star.configuration.ConfigurationProvider")
aNodePath(0).Name = "nodepath"
aNodePath(0).Value = sKeyName

В коде на C# я написал так:

           PropertyValue[] values = new PropertyValue[1];
            values[0] = new PropertyValue();
            values[0].Name = "nodepath";
            values[0].Value = new uno.Any(sKeyName);
            XMultiServiceFactory oConfigProvider = (XMultiServiceFactory)
                    multiServiceFactory.createInstance("com.sun.star.configuration.ConfigurationProvider");
            GetRegistryKeyContent = oConfigProvider.createInstanceWithArguments(
                "com.sun.star.configuration.ConfigurationAccess", values);

На последнем операторе C# ругается. Говорит 2-ой аргумент должен быть uno.Any[] и не может привести PropertyValue[] к uno.Any[],
хотя в коде на VB 2-ой аргумент - PropertyValue[].

mikekaganski

То, что в коде на Basic (нет у нас VB! даже VBA поддерживается только частично, а это другой зверь) "2-ой аргумент - PropertyValue[]" - неважно. Basic - язык с нестрогой системой типов, и для его работы необходима прослойка преобразований, которая сама заботится о нужных заклинаниях. Вы пользуетесь C#, и для Вас главное - это спецификация.

Действительно, метод ждёт массив из Any. Создавайте его, а отдельные его значения инициализируйте отдельными объектами PropertyValue.
С уважением,
Михаил Каганский

Борис_С

Разобрался. Вот код:

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Microsoft.Win32;

using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.uno;
using unoidl.com.sun.star.bridge;
using unoidl.com.sun.star.frame;
using unoidl.com.sun.star.text;
using unoidl.com.sun.star.script.provider;
using unoidl.com.sun.star.sheet;
using unoidl.com.sun.star.table;
using unoidl.com.sun.star.util;
using unoidl.com.sun.star.beans;
using unoidl.com.sun.star.container;
using unoidl.com.sun.star.style;
using unoidl.com.sun.star.view;
using unoidl.com.sun.star.configuration;

namespace ConsoleApp
{
    public class Program
    {
        XMultiServiceFactory multiServiceFactory;
       
        static void Main(string[] args)
        {
                XComponentContext localContext = uno.util.Bootstrap.bootstrap();
                multiServiceFactory = (XMultiServiceFactory)localContext.getServiceManager();
                // получение имени и версии запущенного приложения
                string productName = GetProductname();
        }

        private string GetProductname()
        {
            PropertyValue values = new PropertyValue();
            values.Name = "nodepath";
            values.Value = new uno.Any("org.openoffice.Setup/Product");
            uno.Any[] args = new uno.Any[1];
            args[0] = new uno.Any(typeof(PropertyValue), values);
            XMultiServiceFactory oConfigProvider = (XMultiServiceFactory)
                    multiServiceFactory.createInstance(
                        "com.sun.star.configuration.ConfigurationProvider");
            XNameAccess xNameAccess =
                (XNameAccess)oConfigProvider.createInstanceWithArguments(
                "com.sun.star.configuration.ConfigurationAccess", args);
            string sProdName = (string)xNameAccess.getByName("ooName").Value;
            string sVersion = (string)xNameAccess.getByName("ooSetupVersion").Value;
            return sProdName + " " + sVersion;
        }
    }
}

Это было не просто, но результат оправдал затраченные усилия. Всем спасибо. Особенно mikekaganski.

sokol92

Владимир.