2022年9月4日日曜日

70: グローバルUNOサービスをC++にて作成する

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

UNOコンポーネントをリモートプログラミング言語環境からインスタンス化するために、またはスプレッドシートセルファンクションなどの作成物を作成するために。

話題


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: C++

この記事の目次


開始コンテキスト



ターゲットコンテキスト



  • 読者は、自らのグローバルUNOサービスをC++にて作成する方法を知る。

オリエンテーション


任意のUNOインターフェイスを作成・登録し、そのマッピングイメージたちを生成する方法についての記事があります。

本シリーズの任意のサンプルプログラムをビルドする方法についての記事があります。

UNOプログラムを開発するための、LinuxまたはWindows環境を構築するための記事があります。


本体

ト書き
Special-Student-7、Morris(C++プログラマー)、Chloe(C++プログラマー)がコンピュータの前にいる。


0: 私たちがここで"UNOサービス"によって意味するもの


Special-Student-7
私たちがここで"UNOサービス"によって意味するものは、ある記事にて説明されているものです。

簡潔に述べると、UNOサービスは、あるUNOオブジェクトたちファクトリ内のアイテムであり、そのファクトリは'UNOサービス群マネージャー'.と呼ばれます。

実のところ、"サービス"は、オフィシャル用語体系において、とても混乱してそして混乱させるように使われている用語であり、私たちは、"UNOサービス"によってオフィシャル用語体系における第2の意味も第3の意味も意味しません。

オフィシャル用語体系における第2の意味の"サービス"をどうすれば作成できるかを知りたいと思われているのであれば、私にはかなり確信がありますが、それはあなたが作成する必要のあるものではありません。

一部の人々はオフィシャル用語体系における第3の意味の"サービス"を便利とみなしているかもしれませんが、それも特にあなたが作成する必要のあるものではありません、そして、私は作成しないよう選択するので、それについて私は説明しません。


1: なぜUNOサービスが望まれるのか?


Special-Student-7
UNOサービスを作成する目的は、リモートプログラミング言語環境から当該UNOコンポーネントをインスタンス化することか、当該UNOコンポーネントがUNOサービスとして登録されることを求める作成物(スプレッドシートセルファンクションのような)を作成することです。

"リモートプログラミング言語環境"が何を意味するかを正確にご理解ください。

Morris
それは何を意味するんだ?

Special-Student-7
任意のリモートプログラミング言語環境は、当該UNOコンポーネントがインスタンス化されるプログラミング言語環境ではないプログラミング言語環境です。

オフィスインスタンス内のJava環境またはPython環境は、そのオフィスインスタンスのC++本体にとってリモートプログラミング言語環境です、なぜなら、そのC++本体だけがそれにとってローカルプログラミング言語環境だからです。

Chloe
そのUNOコンポーネントがその環境から"new"オペレーターでインスタンス化できるか否かの問題でしょう?もしもできるのであれば、そのUNOコンポーネントがUNOサービス群マネージャー(それはUNOコンポーネントインスタンスたちのファクトリである)を介してインスタンス化される必要はない。

Special-Student-7
そのとおりです、マダム。

Chloe
したがって、もしもそのUNOコンポーネントはあるリモートプログラミング言語環境からインスタンス化されるのだとしても、もしも、それはローカルプログラミング言語環境内の別のUNOオブジェクトによってインスタンス化されるとしたら、UNOサービスは不必要ということになる。

Special-Student-7
それもそのとおりです。通常は、あなたのUNOオブジェクトたちの内の最初のものがあるUNOサービス群マネージャーからインスタンス化され、その後、その最初のUNOオブジェクトがあなたのUNOコンポーネントたちのいくつかをインスタンス化できる、等々となります。

Morris
さっきの". . . を求める作成物 . . . を作成すること"うんぬん部分は何だ?

Special-Student-7
一部の種類の作成物たちは、UNOコンポーネントたちUNOサービスたちとして登録されるよう求めます、あなたがリモートプログラミング言語環境をお持ちか否かにかかわらず。

例えば、任意のスプレッドシートセルファンクションは、対応するUNOコンポーネントUNOサービスとして登録されるよう求めます。


2: 注意: 私たちはグローバルUNOサービスを作成します


Special-Student-7
全てのUNOサービスグローバルUNOサービスであるわけではありませんが、私がUNOサービスを作成することについて話すときは、私は、グローバルUNOサービスについて話しています。

Morris
はあ?俺は、そんな制限についてハッピーじゃないがな。

Special-Student-7
そうですか、サー?

Morris
俺の顔を見てみろ!俺がハッピーに見えるか?

Chloe
あなたがハッピーに見えるのを、私は見たことないけど。

Special-Student-7
えーと、各非グローバルUNOサービス群マネージャーは個別の目的・個別の実装のものであり、大抵の場合、あなたのUNOサービスをそこに登録することは、まったく有益ではありません、そのUNOサービス群マネージャーがそうしたカスタマイぜーションをそもそも念頭に置いているのでない限り。

そして、私が推測するには、そのような非グローバルUNOサービス群マネージャーは1つもないでしょう。


3: UNOサービスを作成する



3-1: UNO Componentを用意する


Special-Student-7
当該UNOコンポーネントは、それがUNOサービスとして登録されるためには、特定の要件を満たしていなければなりません。

具体的には、それは、2つのUNOインターフェイス、'::com::sun::star::lang::XServiceInfo'および'::com::sun::star::lang::XInitialization'を実装していなければなりません、以下のように。

theBiasPlanet/tests/models/CplusplusTest1UnoComponent.hpp

@C++ ソースコード
#ifndef __theBiasPlanet_tests_models_CplusplusTest1UnoComponent_hpp__
	#define __theBiasPlanet_tests_models_CplusplusTest1UnoComponent_hpp__
	
	#include <set>
	#include <com/sun/star/lang/IllegalArgumentException.hpp>
	#include <com/sun/star/lang/XInitialization.hpp>
	#include <com/sun/star/lang/XServiceInfo.hpp>
	#include <com/sun/star/uno/Reference.hxx>
	#include <com/sun/star/uno/RuntimeException.hpp>
	#include <com/sun/star/uno/XComponentContext.hpp>
	#include <cppuhelper/implbase3.hxx>
	#include <rtl/ustring.hxx>
	#include "theBiasPlanet/unoDatumTypes/tests/XTest1.hpp"
	
	using namespace ::std;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::uno;
	using namespace ::cppu;
	using namespace ::rtl;
	using namespace ::theBiasPlanet::unoDatumTypes::tests;
	
	namespace theBiasPlanet {
		namespace tests {
			namespace models {
				class CplusplusTest1UnoComponent: public WeakImplHelper3 <XServiceInfo, XInitialization, XTest1> {
					private:
						static string const c_nameOfThisClass;
						static set <string> const c_unoServiceNames;
						static set <string> const c_unoCompoundInterfaceNames;
						Reference <XComponentContext> i_underlyingRemoteUnoObjectsContextInXComponentContext;
						// # Add the other member variables Start
						string i_message;
						// # Add the other member variables End
					public:
						static OUString SAL_CALL getImplementationNameStatically ();
						static Sequence <OUString> SAL_CALL getSupportedUnoCompoundInterfaceNamesStatically ();
						static ::com::sun::star::uno::Reference <XInterface> createInstance (::com::sun::star::uno::Reference <XComponentContext> const & a_underlyingUnoObjectsContextInXComponentContext);
						CplusplusTest1UnoComponent (::com::sun::star::uno::Reference <XComponentContext> const & a_underlyingUnoObjectsContextInXComponentContext);
						~CplusplusTest1UnoComponent ();
						void SAL_CALL initialize (Sequence <Any> const & a_arguments) override;
						OUString SAL_CALL getImplementationName () override;
						sal_Bool SAL_CALL supportsService (OUString const & a_unoCompoundInterfaceName) override;
						Sequence <OUString> SAL_CALL getSupportedServiceNames () override;
						OUString SAL_CALL test1 (OUString const & a_name) override;
				};
			}
		}
	}
#endif


theBiasPlanet/tests/models/CplusplusTest1UnoComponent.cpp

@C++ ソースコード
#include "theBiasPlanet/tests/models/CplusplusTest1UnoComponent.hpp"
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;

namespace theBiasPlanet {
	namespace tests {
		namespace models {
			OUString CplusplusTest1UnoComponent::getImplementationNameStatically () {
				return UnoExtendedStringHandler::getOustring (c_nameOfThisClass);
			}
			
			Sequence <OUString> CplusplusTest1UnoComponent::getSupportedUnoCompoundInterfaceNamesStatically () {
				Sequence <OUString> l_unoCompoundInterfaceNamesSequence;
				l_unoCompoundInterfaceNamesSequence.realloc (c_unoCompoundInterfaceNames.size ());
				int l_sequenceItemIndex = 0;
				for (string const & l_unoCompoundInterfaceName: c_unoCompoundInterfaceNames) {
					l_unoCompoundInterfaceNamesSequence [l_sequenceItemIndex] = UnoExtendedStringHandler::getOustring (l_unoCompoundInterfaceName);
					l_sequenceItemIndex ++;
				}
				return l_unoCompoundInterfaceNamesSequence;
			}
			
			::com::sun::star::uno::Reference <XInterface> SAL_CALL CplusplusTest1UnoComponent::createInstance (::com::sun::star::uno::Reference <XComponentContext> const & a_underlyingUnoObjectsContextInXComponentContext) {
				return Reference <XInterface> ( (XInterface *) (void *) (new CplusplusTest1UnoComponent (a_underlyingUnoObjectsContextInXComponentContext)));
			}
			
			CplusplusTest1UnoComponent::CplusplusTest1UnoComponent (::com::sun::star::uno::Reference <XComponentContext> const & a_underlyingUnoObjectsContextInXComponentContext): i_underlyingRemoteUnoObjectsContextInXComponentContext (a_underlyingUnoObjectsContextInXComponentContext) {
			}
			
			CplusplusTest1UnoComponent::~CplusplusTest1UnoComponent () {
			}
			
			void CplusplusTest1UnoComponent::initialize (Sequence <Any> const & a_arguments) {
				if (a_arguments.getLength () != 1) {
					throw IllegalArgumentException (UnoExtendedStringHandler::getOustring (string ("There must be one argument.")), Reference <XInterface> ( (XInterface *) (void *) this), 0);
				}
				Type l_datumType;
				l_datumType = a_arguments [0].getValueType ();
				if (! (l_datumType == UnoType <OUString>::get ())) {
					throw IllegalArgumentException (UnoExtendedStringHandler::getOustring (string ("The first argument must be a string")), Reference <XInterface> ( (XInterface *) (void *) this), 0);
				}
			    else {
					i_message = UnoExtendedStringHandler::getString (* ( (OUString *) a_arguments [0].getValue ()));
				}
			}
			
			OUString CplusplusTest1UnoComponent::getImplementationName () {
				return getImplementationNameStatically ();
			}
			
			sal_Bool CplusplusTest1UnoComponent::supportsService (OUString const & a_unoCompoundInterfaceName) {
				set <string>::iterator l_unoCompoundInterfaceNamesIterator = c_unoCompoundInterfaceNames.find (UnoExtendedStringHandler::getString (a_unoCompoundInterfaceName));
				return (l_unoCompoundInterfaceNamesIterator != c_unoCompoundInterfaceNames.end ());
			}
			
			Sequence <OUString> CplusplusTest1UnoComponent::getSupportedServiceNames () {
				return getSupportedUnoCompoundInterfaceNamesStatically ();
			}
			
			OUString CplusplusTest1UnoComponent::test1 (OUString const & a_name) {
				return UnoExtendedStringHandler::getOustring (i_message + ", ") + a_name + UnoExtendedStringHandler::getOustring ("!");
			}
		}
	}
}


theBiasPlanet/tests/staticVariablesInitializer/StaticVariablesInitializer.cpp

@C++ ソースコード
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"
#include "theBiasPlanet/tests/globalUnoServicesProvider/TestsGlobalUnoServicesProvider.hpp"
#include "theBiasPlanet/tests/models/CplusplusTest1UnoComponent.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;
using namespace ::theBiasPlanet::tests::models;

namespace theBiasPlanet {
	namespace tests {
		~
		namespace models {
			string const CplusplusTest1UnoComponent::c_nameOfThisClass (string ("theBiasPlanet.tests.models.CplusplusTest1UnoComponent"));
			set <string> const CplusplusTest1UnoComponent::c_unoServiceNames ( [] {
				set <string> l_unoServiceNames;
				l_unoServiceNames.insert (string ("theBiasPlanet.tests.CplusplusTest1UnoComponent"));
				return l_unoServiceNames;
			} ());
			set <string> const CplusplusTest1UnoComponent::c_unoCompoundInterfaceNames;
		}
	}
}

Morris
. . . あんたの趣味を必要事項たちから見分けられないんだがな。

Special-Student-7
必要事項たちは、あなたはそのコンストラクタおよびそれら"override"メソッドたちを何らかの形で適切に実装し、それら3つのスタティックメソッドたち、"getImplementationNameStatically"、"getSupportedUnoCompoundInterfaceNamesStatically"、"createInstance"を、恣意的な名前で、しかし、同じ引数タイプたちおよびリターンタイプたちで持つ必要があるということです。

Morris
何が"適切"なのかを聞いているんだがな。

Special-Student-7
そのコンストラクタは、単一'::com::sun::star::uno::Reference <XComponentContext> const &'引数を取り、その値は通常どこかに格納して置かれるべきです、なぜなら、そのUNOオブジェクト群コンテキストが当該UNO環境へのアクセスポイントであるからです。

注意として、そのUNOサービスのインスタンス化引数たちは、コンストラクタへ渡されるのではなく、その"initialize"メソッドへ渡されます。

Morris
すると、俺はそのコンストラクタをまさにそのシグネチャーで作成しなければならんわけだ。

Special-Student-7
その"getImplementationName"メソッドはフルクラス名を戻します。

"supportsService"および"getSupportedServiceNames"のメソッドたちは、基本的には、オフィシャル用語体系における第2の意味の"サービス"についてであって、UNOサービスについてではありません。

Morris
"基本的には"という言葉は逃げ口上だ、俺に言わせれば。

Special-Student-7
多分、しかし、私は根拠なく断定的であるよりも正直であるべきですから。

実のところ、"サービス"は、ドキュメント内だけでなくオフィスプロダクトコード内でもとてもまぜこぜになっていて、第2の意味の"サービス"の名前が同一名のUNOサービスを意味してご都合主義に乱用されていたり、その逆があったりします。

Morris
ああ、それじゃあ、それら2つのメソッドたちを俺はどうすべきなんだ?

Special-Student-7
一部の種類の作成物は、当該UNOコンポーネントがいくつか特定の第2の意味の"サービス"たちをサポートしているよう求めます、したがって、その場合にはそれらをそれら2メソッドたちはサポートしなければなりません; そうでない場合は、それら2メソッドたちは何らの"サービス"もサポートする必要がありません、もっとも、UNOサービス名をサポートしても何も問題は起こしませんが。

Morris
"サポートする"というのは単に'true'と応答するという意味なのか?

Special-Student-7
"supportsService"についてはイエスです; "getSupportedServiceNames"については、リターンにその"サービス"名を含むことを意味します。

Chloe
えーと、それが、なぜ"getSupportedServiceNames"は複数"サービス"たちをサポートできるかの理由なのね . . .

Special-Student-7
複数のUNOサービスたちをサポートすることは通常有益ではありません; 当該メソッドが複数"サービスたち"をサポートできるのは、それらが第2の意味のものだからです。

いずれにせよ、それら3つのスタティックメソッドたちは、スタティックでなければなりません、名称たちはどうでもよいですが、当該引数タイプたちおよびリターンタイプを持っていなければなりません。

えーと、他は私の趣味から来たものです: 例えば、私は'c_unoServiceNames'を持っていますが、それは、リテラルたちをメソッド間に散らばらせたくないからです。


3-2: グローバルUNOサービス群プロバイダーを作成する


Special-Student-7
私たちはグローバルUNOサービス群プロバイダーを作成しなければなりません。

というか実際には、C++ UNOは、本当にはグローバルUNOサービス群プロバイダーをクラスとして持っていませんが(Java UNOは持っている)、UNOサービスたちが登録されインスタンス化されるのに必要な2グローバルメソッドたちを持っています。私は、その2つのグローバルメソッドたちのセットを'グローバルUNOサービス群プロバイダー'と呼んでいます。

以下は、グローバルUNOサービス群プロバイダーの例です。

theBiasPlanet/tests/globalUnoServicesProvider/TestsGlobalUnoServicesProvider.hpp

@C++ ソースコード
#ifndef __theBiasPlanet_tests_globalUnoServicesProvider_TestsGlobalUnoServicesProvider_hpp__
	#define __theBiasPlanet_tests_globalUnoServicesProvider_TestsGlobalUnoServicesProvider_hpp__

	#include <cppuhelper/implementationentry.hxx>

	using namespace ::cppu;

	namespace theBiasPlanet {
		namespace tests {
			namespace globalUnoServicesProvider {
				class TestsGlobalUnoServicesProvider {
					private:
					public:
						static ImplementationEntry * s_unoComponentEntriesArray;
				};
			}
		}
	}
#endif


theBiasPlanet/tests/globalUnoServicesProvider/TestsGlobalUnoServicesProvider.cpp

@C++ ソースコード
#include "theBiasPlanet/tests/globalUnoServicesProvider/TestsGlobalUnoServicesProvider.hpp"
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <cppuhelper/factory.hxx>
#include <uno/lbnames.h>

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::registry;

extern "C" {
	using namespace ::theBiasPlanet::tests::globalUnoServicesProvider;
	
	SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory (char const * a_implementationName, XMultiServiceFactory * a_globalUnoServicesManager, XRegistryKey * a_registryKey) {
		return component_getFactoryHelper (a_implementationName, a_globalUnoServicesManager, a_registryKey, TestsGlobalUnoServicesProvider::s_unoComponentEntriesArray);
	}
	
	SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment (char const ** a_unoEnvironmentTypeNameAddress, uno_Environment ** a_unoEnvironment) {
		*a_unoEnvironmentTypeNameAddress = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
	}
}


theBiasPlanet/tests/staticVariablesInitializer/StaticVariablesInitializer.cpp

@C++ ソースコード
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"
#include "theBiasPlanet/tests/globalUnoServicesProvider/TestsGlobalUnoServicesProvider.hpp"
#include "theBiasPlanet/tests/models/CplusplusTest1UnoComponent.hpp"

using namespace ::theBiasPlanet::unoUtilities::stringsHandling;
using namespace ::theBiasPlanet::tests::models;

namespace theBiasPlanet {
	namespace tests {
		namespace globalUnoServicesProvider {
			ImplementationEntry * TestsGlobalUnoServicesProvider::s_unoComponentEntriesArray ( [] {
				ImplementationEntry * l_unoComponentEntriesArray (new ImplementationEntry [2]);
				(*l_unoComponentEntriesArray).create = CplusplusTest1UnoComponent::createInstance;
				(*l_unoComponentEntriesArray).createFactory = createSingleComponentFactory;
				(*l_unoComponentEntriesArray).getImplementationName = CplusplusTest1UnoComponent::getImplementationNameStatically;
				(*l_unoComponentEntriesArray).getSupportedServiceNames = CplusplusTest1UnoComponent::getSupportedUnoCompoundInterfaceNamesStatically;
				(*l_unoComponentEntriesArray).moduleCounter = 0;
				(*l_unoComponentEntriesArray).nFlags = 0;
				(* (l_unoComponentEntriesArray + 1)).create = 0;
				(* (l_unoComponentEntriesArray + 1)).createFactory = 0;
				(* (l_unoComponentEntriesArray + 1)).getImplementationName = 0;
				(* (l_unoComponentEntriesArray + 1)).getSupportedServiceNames = 0;
				return l_unoComponentEntriesArray;
			} ());
		}
		~
	}
}


Chloe
ふーむ、ポイントは"HiUnoExtensionsGlobalUnoServicesProvider::s_unoComponentEntriesArray"データを用意することね。


3-3: 拡張機能コンフィグレーションファイルたちを作成する


Special-Student-7
私たちは、当該UNOサービスをあるLibreOfficeまたはApache OpenOffice拡張機能を介して登録しようとしており、そのためには、いくつかのコンフィグレーションファイルたちが必要です。

任意のLibreOfficeまたはApache OpenOffice拡張機能を作成する方法はある記事に説明されています

Morris
えーと . . .

Special-Student-7
私たちはその記事中の"UnoServiceComponentsForLinux64Bits.xml"ファイルを作成します、以下のように。

@XML ソースコード
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://openoffice.org/2010/uno-components">
	<!-- # Change the shared objects library file uri -->
	<component loader="com.sun.star.loader.SharedLibrary" uri="linux64Bits/libtheBiasPlanet.tests.unoExtension.so">
		<!-- # Add service implementation class names -->
		<implementation name="theBiasPlanet.tests.models.CplusplusTest1UnoComponent">
			<!-- # Add service names -->
			<service name="theBiasPlanet.tests.CplusplusTest1UnoComponent"/>
		</implementation>
	</component>
</components>

そして、私たちは、その記事中の"UnoServiceComponentsForMicrosoftWindows64Bits.xml"ファイルを作成します、以下のように。

@XML ソースコード
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://openoffice.org/2010/uno-components">
	<!-- # Change the shared objects library file uri -->
	<component loader="com.sun.star.loader.SharedLibrary" uri="microsoftWindows64Bits/theBiasPlanet.tests.unoExtension.dll">
		<!-- # Add service implementation class names -->
		<implementation name="theBiasPlanet.tests.models.CplusplusTest1UnoComponent">
			<!-- # Add service names -->
			<service name="theBiasPlanet.tests.CplusplusTest1UnoComponent"/>
		</implementation>
	</component>
</components>

Morris
"コンポーネント"は、今の場合、シェアードライブラリファイルまたはダイナミックリンクライブラリファイルを意味しているのか . . .

Special-Student-7
はい、"コンポーネント"がしまりのないオフィシャル用語体系で乱用されているもう一つの例です: "コンポーネント"は何物をも意味することができ、今の場合、シェアードライブラリファイルまたはダイナミックリンクライブラリファイルです。

注意として、そこには、第2の意味の"サービス"名たちと並んで、UNOサービス名も指定されるべきです。

Morris
"節操がない"というべきだろう: 前出の2メソッドたちはUNOサービス名を必要としないのに、このコンフィグレーションファイルはUNOサービス名を必要とする . . .

Special-Student-7
"サービス"は実にご都合主義に乱用されています。

いずれせよ、"manifest.xml"も勿論作成する必要がありますが、ここではそれを示しません、なぜなら、それは、その記事内のものとまったく同じだからです。


3-4: 余談: 必要でないもの


Special-Student-7
何らの"service" IDLファイルも作成される必要はありません、なぜなら、それは、第2の意味の"サービス"または第3の意味の"サービス"を作成するためのものであり、UNOサービスを作成するためのものではないからです。

UNOコンポーネントにいくつかの既存の第2の意味の"サービス"をサポートさせる機会はあるかもしれませんが、ご自身の第2の意味の"サービス"を作成される必要は全くないでしょう、多分。

ご自身の第3の意味の"サービス"を作成されることは可能ですが、作成する方法の説明はいたしません、私は作成しないよう選択しますので。


3-5: 拡張機能ファイルを作成する


Special-Student-7
それでは、拡張機能ファイルを作成しましょう。

私は方法を説明する必要はありません、なぜなら、それは、既にある以前の記事内に詳述されていますので。


3-6: 拡張機能を登録する


Special-Student-7
拡張機能を登録しましょう。

それは、GUIメニュー項目"Tools(ツール)" -> "Extension Manager...(拡張機能)"を介して行なえます。

または、'unopkg'コマンドをお使いになることもできます、もしも、ご自身のビルドスクリプトで拡張機能を登録されたいのであれば、以下のように。

@bash or CMD ソースコード
unopkg add -f -v %the extension file path%

注意として、LibreOfficeまたはApache OpenOfficeインスタンスはそのコマンドの前にシャットダウンされているように想定されています。


3-7: 追加のシェアードライブラリまたはダイナミックリンクライブラリパスたちをオフィスインスタンスへセットする


Special-Student-7
あなたのUNOサービスは、あなたが作られたかなんかのいくつかのシェアードライブラリたちまたはダイナミックリンクライブラリたちを使っていると仮定して、それらライブラリたちは、どこか(多分ローカルファイルシステム内)に置くことができ、パスたちはオフィスインスタンスへセットできます。

Chloe
それって、単に'LD_LIBRARY_PATH'環境変数をセットするだけの問題じゃない?

Special-Student-7
実のところ、はい、そうです、Linuxの場合には; Microsoft Windowsの場合には、'PATH'環境変数をセットします。

そして、それをセットするリーズナブルな1つの方法は、それを、Linuxでは'%オフィスプロダクトディレクトリ%/program/soffice'ファイル内に、以下のように、そのファイルのどこかに書くことです。

@bash ソースコード
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:%the development directory path%/unoUtilitiesToBeDisclosed/target:%the development directory path%/coreUtilitiesToBeDisclosed/target"

Morris
それはどこでもいいのか?

Special-Student-7
ほとんど、多分; 本体が呼び出される前でなければなりません、勿論。

ファイルの先頭に置くのは安全な選択肢です。

Microsoft Windowsの場合、バッチファイルとしての'soffice'ファイルはありません、したがって、1つのリーズナブルな方法は、'%オフィスプロダクトディレクトリ%\program\soffice.bat'ファイルを以下のように作成することです。

@CMD ソースコード
setlocal
        set Path=%Path%;%the office SDK directory path%\lib;%the office directory path%\program;%the development directory path%\unoUtilitiesToBeDisclosed\targetInWindows;%the development directory path%\coreUtilitiesToBeDisclosed\targetInWindows;%the wxWidgets product directory path%\lib\vc_x64_dll;%the OpenSSL product directory path%\lib;%the OpenSSL product directory path%
        call soffice.exe
endlocal

そして、'.exe'ファイルたちが通常'.bat'ファイルたちよりも優先されるので、私は'PATHEXT'環境変数を以下のようにプロジェクトビルドスクリプトか何かからセットします、もしも、'soffice'が'soffice.bat'ファイルを実行して欲しければ。

@CMD ソースコード
setlocal
        set PATHEXT=.bat;.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.com;.exe;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.msc
		~
endlocal



4: UNOサービスをインスタンス化する


Special-Student-7
UNOサービスは、任意のビルトイングローバルUNOサービスと同じようにインスタンス化することができます。

例えば、以下はPythonマクロです。

@Python ソースコード
from typing import Any
from typing import cast
import uno
~
from com.sun.star.script.provider import XScriptContext
from com.sun.star.uno import XComponentContext
XTest1: Any = uno.getClass ("theBiasPlanet.unoDatumTypes.tests.XTest1")

XSCRIPTCONTEXT: XScriptContext
c_underlyingRemoteUnoObjectsContextInXComponentContext: XComponentContext = XSCRIPTCONTEXT.getComponentContext ()
c_cplusplusTest1UnoComponent: "XTest1" = cast (XTest1, c_underlyingRemoteUnoObjectsContextInXComponentContext.getServiceManager ().createInstanceWithArgumentsAndContext ("theBiasPlanet.tests.CplusplusTest1UnoComponent", ["Hey"], c_underlyingRemoteUnoObjectsContextInXComponentContext))

def test1 () ->None:
	~
	c_cplusplusTest1UnoComponent.test1 ("sport")
	~

Chloe
今や、当C++ UNOコンポーネントはリモートプログラミング言語環境からインスタンス化できることになった。


5: ここに動かせるサンプルがあります


Special-Student-7
ここに、動かせるサンプル拡張機能があります

そのサンプルプロジェクトをビルドする方法はある記事に説明されています。

メインプロジェクトは'hiUnoExtensionsUnoExtension'で、それはいくつかのユーティリティプロジェクトたちおよび付加UNOデータタイプたちプロジェクトを使用しています。

UNOデータタイプたちマージされたファイルはオフィスプロダクトへ登録されなければなりません、ある以前の記事に述べられた方法1)にしたがって。

そして、シェアードライブラリたちディレクトリたち(Linuxの場合は、'%開発ディレクトリパス%/unoUtilitiesToBeDisclosed/target'および'%開発ディレクトリパス%/coreUtilitiesToBeDisclosed/target')またはダイナミックリンクライブラリたちディレクトリたち(Microsoft Windowsの場合は、'%開発ディレクトリパス%\unoUtilitiesToBeDisclosed\target'、'%開発ディレクトリパス%\coreUtilitiesToBeDisclosed\target'、'%オフィスSDKディレクトリ\lib'、'%オフィスプロダクトディレクトリ%\program'、'%wxWidgetsプロダクトディレクトリ\lib\vc_x64_dll'、'%OpenSSLプロダクトディレクトリ\lib'、'%OpenSSLプロダクトディレクトリ%')のパスたちがオフィスインスタンスへセットされなければなりません、ある以前のセクション内で説明された方法にしたがって。

Morris
準備が多いなあ . . .

Special-Student-7
もしも、当サンプルが動かない場合は、多分、準備たちが正しくなかったのです。

拡張機能はあるツールボタンたちグループを登録したはずであり、そこからテストマクロが呼び出せます。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>