2020-09-20

51: Invoke Any LibreOffice or OpenOffice Macro from Your Program

<The previous article in this series | The table of contents of this series | The next article in this series>

"Any" means user-owned, application-owned, in-document, or in-extension, and Python or whatever. No, we do not call 'soffice', which is handicapped.

Topics


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: the Java programming language
About: C++
About: C#
About: the Python programming language
About: LibreOffice Basic
About: Apache OpenOffice Basic
About: JavaScript
About: BeanShell

The table of contents of this article


Starting Context



Target Context


  • The reader will know how to invoke any LibreOffice or Apache OpenOffice macro from his or her program.

Orientation


Creating your user-owned or application-owned Python macro has been addressed in a previous article.

Creating your in-document Python macro has been addressed in a previous article.

Creating your in-extension Python macro has been addressed in a previous article.

The details of Python macro programming will be dug into in some future articles.

Using an external full Python has been addressed in a previous article.


Main Body

Stage Direction
Here are Hypothesizer 7, Objector 51A, and Objector 51B in front of a computer.


1: Calling 'soffice' Is Handicapped


Hypothesizer 7
It seems that some people call 'soffice' in order to invoke LibreOffice or Apache OpenOffice macros from their programs.

Objector 51A
. . . I do, actually. Are you accusing me?

Hypothesizer 7
No, sir. I am informing you that that scheme is handicapped.

Objector 51A
You are making fun of me! You are like "That fool calls 'soffice'. Ha-ha!".

Hypothesizer 7
. . . Sir, I did not laugh at all, did I?

Objector 51A
Oh, you were guffawing in your heart! You were like "Look at that dunce! That stupid look on his face!"

Hypothesizer 7
. . . Sir, are you all right?

Objector 51B
Leave that dunce alone; just explain how it is handicapped.

Hypothesizer 7
Well, madam, you cannot pass appropriate arguments that way, can you?

Objector 51B
What do you mean by "appropriate"?

Hypothesizer 7
Can you pass a UNO object argument?

Objector 51B
I'm not sure.

Hypothesizer 7
Can you get a UNO object return?

Objector 51B
. . . I'm not sure.

Hypothesizer 7
Can you call a in-document macro?

Objector 51B
Why do I have to be interrogated?! You are like "I'm going to grill that chick! He-he"!

Hypothesizer 7
"chick"? "He-he"? . . . Are you all right?

Objector 51A
Leave that chick alone.

Hypothesizer 7
Anyway, also efficiency-wise, it is not any laudable: invoke an external process per macro call?

Objector 51A & Objector 51B
You are mocking me!


2: The Preparation


Hypothesizer 7
As a part of the preparation, let us get the UNO objects context to the LibreOffice or Apache OpenOffice instance.

Objector 51A
Huh? You are jibber-jabbering.

Hypothesizer 7
. . . If you do not know how, you can refer to one of the links listed in 'Starting Context'.

Objector 51A
I can't believe it!

Hypothesizer 7
You do not need to believe anything; you need to hypothesize and validate, unboundedly.

Objector 51A
. . . I can skip the part, right?

Hypothesizer 7
Not right, sir.

Objector 51A
. . . You are mean! Why don't you just let me skip?

Hypothesizer 7
It is not about my temperament or intention, sir.

Objector 51A
. . . You are sinister, I say.

Stage Direction
Hypothesizer 7 sighs deeply.

Hypothesizer 7
Next, if you want to call an in-document macro, you have to get the UNO object of the opened document that contains the macro.

Objector 51A
You are jibber-jabbering again.

Hypothesizer 7
If you are going to open the document yourself, the way to do so is written in a previous article on converting files (for Java, C++, C#, Python, and Basic); if you are going to get the current already-opened document, the way to do so is written in some previous articles on executing UNO dispatch commands (for Java, C++, C#, Python, and Basic).

Objector 51A
What if I am going to get a non-current already-opend document?

Hypothesizer 7
You can do so.

Objector 51A
. . . I'm asking how.

Hypothesizer 7
That depends on by what you are going to identify the document.

Objector 51A
By the file name, perhaps.

Hypothesizer 7
Ah, that is easy.

Objector 51A
. . . I'm asking how.

Hypothesizer 7
I cannot explain it here, but in a future article. If you are interested, you can stay tuned.

Objector 51A
. . .


3: Getting the Macro Handlers Provider


Hypothesizer 7
Let us get the macro handlers provider.

Objector 51B
"macro handlers provider"?

Hypothesizer 7
It is a UNO object from which we can get the handler of any macro that is managed by it.

Objector 51B
Whatever it is, I need to get it?

Hypothesizer 7
Yes, you do.

The way to get it is different depending on whether the macro is non-in-document or in-document.


3-1: For Any Non-In-Document Macro


Hypothesizer 7
The macro handlers provider for any non-in-document macro can be gotten as a global UNO service instance, like these, where 'l_remoteUnoObjectsContext' is the UNO objects context to the LibreOffice or Apache OpenOffice instance.

@Java Source Code
~
import com.sun.star.script.provider.XScriptProvider;
~
import com.sun.star.uno.UnoRuntime;
~
						XScriptProvider l_macroHandlersProviderInXScriptProvider = UnoRuntime.queryInterface (XScriptProvider.class, l_remoteUnoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.script.provider.MasterScriptProvider", l_remoteUnoObjectsContext));

@C++ Source Code
~
	#include <com/sun/star/script/provider/XScriptProvider.hpp>
	~
	#include <com/sun/star/uno/Reference.hxx>
	~
	using namespace ::com::sun::star::script::provider;
	~
	using namespace ::com::sun::star::uno;
	~
									Reference <XScriptProvider> l_macroHandlersProviderInXScriptProvider (l_remoteUnoObjectsContext->getServiceManager ()->createInstanceWithContext ("com.sun.star.script.provider.MasterScriptProvider", l_remoteUnoObjectsContext), UNO_QUERY);

@C# Source Code
~
			using unoidl.com.sun.star.script.provider;
			~
									XScriptProvider l_macroHandlersProviderInXScriptProvider = (XScriptProvider) l_remoteUnoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.script.provider.MasterScriptProvider", l_remoteUnoObjectsContext);			

@Python Source Code
~
from typing import cast
~
from com.sun.star.script.provider import XScriptProvider
~
						l_macroHandlersProviderInXScriptProvider: XScriptProvider = cast (XScriptProvider, l_remoteUnoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.script.provider.MasterScriptProvider", l_remoteUnoObjectsContext))				


3-2: For Any In-Document Macro


Hypothesizer 7
The macro handlers provider for any in-document macro can be gotten from the document UNO object, using the '::com::sun::star::script::provider::XScriptProviderSupplier' UNO interface, like these, where 'l_unoDocumentInXModel' is the document UNO object.

@Java Source Code
~
import com.sun.star.script.provider.XScriptProvider;
import com.sun.star.script.provider.XScriptProviderSupplier;
~
						XScriptProvider l_macroHandlersProviderInXScriptProvider = UnoRuntime.queryInterface (XScriptProviderSupplier.class, l_unoDocumentInXModel).getScriptProvider ();

@C++ Source Code
	~
	#include <com/sun/star/script/provider/XScriptProvider.hpp>
	#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
	#include <com/sun/star/uno/Reference.hxx>
	~
	using namespace ::com::sun::star::script::provider;
	using namespace ::com::sun::star::uno;
	~
									Reference <XScriptProvider> l_macroHandlersProviderInXScriptProvider (Reference <XScriptProviderSupplier> (l_unoDocumentInXModel, UNO_QUERY)->getScriptProvider ());

@C# Source Code
			~
			using unoidl.com.sun.star.script.provider;
			~
									XScriptProvider l_macroHandlersProviderInXScriptProvider = ( (XScriptProviderSupplier) l_unoDocumentInXModel).getScriptProvider ();

@Python Source Code
~
from typing import cast
~
from com.sun.star.script.provider import XScriptProvider
from com.sun.star.script.provider import XScriptProviderSupplier
~
						l_macroHandlersProviderInXScriptProvider = cast (XScriptProviderSupplier, l_unoDocumentInXModel).getScriptProvider ()


4: Getting the Macro Handler


Hypothesizer 7
Let us get the macro handler from the macro handlers provider, like these, where 'l_macroLocationName' and 'l_macroPathString' are set according to the specifications cited in the subsequent tables.

@Java Source Code
~
import com.sun.star.script.provider.XScript;
~
				String l_macroProgrammingLanguageName = "Python";
				~
						String l_macroUrl = String.format ("vnd.sun.star.script:%s?language=%s&location=%s", l_macroPathString, l_macroProgrammingLanguageName, l_macroLocationName);
						XScript l_macroHandlerInXScript = l_macroHandlersProviderInXScriptProvider.getScript (l_macroUrl);

@C++ Source Code
~
#include <com/sun/star/script/provider/XScript.hpp>
~
						string l_macroProgrammingLanguageName ("Python");
						~
									string l_macroUrl (StringHandler::format ("vnd.sun.star.script:%s?language=%s&location=%s", l_macroPathString, l_macroProgrammingLanguageName, l_macroLocationName));
									Reference <XScript> l_macroHandlerInXScript (l_macroHandlersProviderInXScriptProvider->getScript (UnoExtendedStringHandler::getOustring (l_macroUrl)));

Where 'StringHandler::format (string const & a_formatString, T const & a_currentItem, U const & ... a_remainderItems)' is my utility class method template that does like Java 'String.format', and '::theBiasPlanet::unoUtilities::stringsHandling::UnoExtendedStringHandler::getOustring (string const & a_utf8String)' is my utility class method that creates a UNO string instance from the specified UTF-8 '::std::string' instance, which will not be necessary to be shown here.

@C# Source Code
~
							String l_macroProgrammingLanguageName = "Python";
							~
									String l_macroUrl = String.Format ("vnd.sun.star.script:{0:s}?language={1:s}&location={2:s}", l_macroPathString, l_macroProgrammingLanguageName, l_macroLocationName);
									XScript l_macroHandlerInXScript = l_macroHandlersProviderInXScriptProvider.getScript (l_macroUrl);

@Python Source Code
~
from com.sun.star.script.provider import XScript
~
			l_macroProgrammingLanguageName: str = "Python"
			~
						l_macroUrl = "vnd.sun.star.script:{0:s}?language={1:s}&location={2:s}".format (l_macroPathString, l_macroProgrammingLanguageName, l_macroLocationName)
						l_macroHandlerInXScript = l_macroHandlersProviderInXScriptProvider.getScript (l_macroUrl)

The macro location names

NameMeaning
useruser-owned in place
user:uno_packagesuser-owned in an extension
shareapplication-owned in place
share:uno_packagesapplication-owned in an extension
documentin a document

Macro paths

Macro LanguageLocationPath
Javain place or in-document%the library name%.%the function name% like 'JavaEnvironmentChecker.theBiasPlanet.javaEnvironmentChecker.macros.JavaEnvironmentChecker.checkJavaEnvironment2'
Javain-extension%the extension file name%/Scripts/java/%the library name%.%the function name% like 'theBiasPlanet.javaEnvironmentChecker.unoExtension.oxt/Scripts/java/JavaEnvironmentChecker.theBiasPlanet.javaEnvironmentChecker.macros.JavaEnvironmentChecker.checkJavaEnvironment2'
Pythonin place or in-document%the module file path with '/' delimited%$%the function name% like 'theBiasPlanet/pythonEnvironmentChecker/macros/PythonEnvironmentChecker.py$checkPythonEnvironment2'
Pythonin-extension%the extension file name%/Scripts/python/%the module file path with '/' delimited%$%the function name% like 'theBiasPlanet.pythonEnvironmentChecker.unoExtension.oxt/Scripts/python/theBiasPlanet/pythonEnvironmentChecker/macros/PythonEnvironmentChecker.py$checkPythonEnvironment2'
JavaScriptin place or in-document%the library name%.%the macro file name% like 'JavascriptEnvironmentChecker.checkJavascriptEnvironment2.js'
JavaScriptin-extension%the extension file name%/Scripts/javascript/%the library name%.%the macro file name% like 'theBiasPlanet.javascriptEnvironmentChecker.unoExtension.oxt/Scripts/javascript/JavascriptEnvironmentChecker.checkJavascriptEnvironment2.js'
BeanShellin place or in-document%the library name%.%the macro file name% like 'BeanshellEnvironmentChecker.checkBeanshellEnvironment2.bsh'
BeanShellin-extension%the extension file name%/Scripts/beanshell/%the library name%.%the macro file name% like 'theBiasPlanet.beanshellEnvironmentChecker.unoExtension.oxt/Scripts/beanshell/BeanshellEnvironmentChecker.checkBeanshellEnvironment2.bsh'

Objector 51B
You have forgotten Basic.

Hypothesizer 7
Ah, you have noticed; in fact, I have ignored it than "have forgotten" it.

Objector 51B
Don't.

Hypothesizer 7
Why don't we forget Basic?

Objector 51B
Why?

Hypothesizer 7
Because it is not advisable as a programming language.

Objector 51B
. . .

Hypothesizer 7
Honestly, I am offended by it . . .

Objector 51B
Do you contradict your title, "Any LibreOffice or OpenOffice Macro"?!

Hypothesizer 7
. . . Well, if you say so.

Certainly, you can invoke any Basic macro from your program, but things are unsymmetrical for Basic somehow.

In fact, the macro location names are 'application' and 'document'.

Objector 51B
Huh? How user-owned macros and application-owned macros are distinguished?

Hypothesizer 7
They are not, oddly.

Objector 51B
. . . What do you mean by "are not"?

Hypothesizer 7
The name space is shared.

Objector 51B
In-extension macros are not . . .

Hypothesizer 7
. . . distinguished.

Objector 51B
. . .

Hypothesizer 7
The macro path should be '%the library name%.%the module name%.%the function name%', whatever the macro location is.

Objector 51B
. . .

Hypothesizer 7
And note that the 'com.sun.star.script.provider.MasterScriptProvider' UNO global service instance has to be instantiated with a string argument.

Objector 51B
Of what value, exactly?

Hypothesizer 7
That does not seem to matter, as far as I know.

Objector 51B
What do you mean by "not seem to matter"?

Hypothesizer 7
Any value seems to work, for example, an empty string.

Objector 51B
. . .

Hypothesizer 7
I do not know or care how the argument is used.


5: Invoking the Macro


Hypothesizer 7
Let us invoke the macro, like these, where 'l_macroArgumentsArray' (or 'l_macroArgumentsSequence' or 'l_macroArguments'), 'l_macroOutputArgumentIndicesArray' (or 'l_macroOutputArgumentIndicesSequence'or 'l_macroOutputArgumentIndices'), and 'l_macroOutputArgumentsArray' (or 'l_macroOutputArgumentsSequence' or 'l_macroOutputArguments') are the arguments (including the output arguments), the output argument indices, and the output arguments.

@Java Source Code
~
				Object [] l_macroArgumentsArray = new Object [1];
				l_macroArgumentsArray [0] = "Hi bro!!";
				short [] [] l_macroOutputArgumentIndicesArray = new short [1] [0];
				Object [] [] l_macroOutputArgumentsArray = new Object [1] [0];
				Object l_macroReturn = null;
				~
						l_macroReturn = l_macroHandlerInXScript.invoke (l_macroArgumentsArray, l_macroOutputArgumentIndicesArray, l_macroOutputArgumentsArray);

@C++ Source Code
~
#include <com/sun/star/uno/Any.hxx>
~
							Sequence <Any> l_macroArgumentsSequence (1);
							l_macroArgumentsSequence [0] = Any (UnoExtendedStringHandler::getOustring (string ("Hi bro!!")));
							Sequence <short> l_macroOutputArgumentIndicesSequence;
							Sequence <Any> l_macroOutputArgumentsSequence;
							Any l_macroReturn;
							~
									l_macroReturn = l_macroHandlerInXScript->invoke (l_macroArgumentsSequence, l_macroOutputArgumentIndicesSequence, l_macroOutputArgumentsSequence);

@C# Source Code
~
			using uno;
			~
							Any [] l_macroArgumentsArray = new Any [1];
							l_macroArgumentsArray [0] = new Any ("Hi bro!!");
							short [] l_macroOutputArgumentIndicesArray = new short [0];
							Any [] l_macroOutputArgumentsArray = new Any [0];
							Any l_macroReturn;
							~
									l_macroReturn = l_macroHandlerInXScript.invoke (l_macroArgumentsArray, out l_macroOutputArgumentIndicesArray, out l_macroOutputArgumentsArray);

@Python Source Code
~
from typing import List
from typing import Optional
~
				l_macroArguments: List [Optional [object]] = ["Hi bro!!"]
				l_macroOutputArgumentIndices: List [int] = []
				l_macroOutputArguments: List [object] = []
				l_macroReturn: object = None
				~
						l_macroReturn = l_macroHandlerInXScript.invoke (l_macroArguments, l_macroOutputArgumentIndices, l_macroOutputArguments)

Objector 51B
Um?

Hypothesizer 7
Note that the Java version takes 2-dimensional arrays because it is a Java UNO rule that any UNO-space output argument becomes a Java-space array: any UNO-space output-elements sequence becomes a Java-space 2-dimensional array because the sequence becomes an array and each element of the sequence becomes an array.

Objector 51B
. . . Why only Java?

Hypothesizer 7
Because otherwise, Java cannot get any output, because there is no such thing as any reference in Java.

Objector 51B
But that is also true for Python, isn't it?

Hypothesizer 7
Yes, it is, but Python UNO has coped with the problem in another way.

Objector 51B
In what way, exactly?

Hypothesizer 7
The output argument values are returned in the returned list.


References


<The previous article in this series | The table of contents of this series | The next article in this series>