2019-05-26

14: 'Hi, Console C# UNO Clients', a Sample

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

Likewise for VB.NET. Connecting your program to the LibreOffice/OpenOffice instance, in order to read/write an office document or handle the instance.

Topics


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: .NET Framework

The table of contents of this article


Starting Context



Target Context


  • The reader will know how to make his or her external console .NET Framework program connect to any UNO server (for example, a LibreOffice or Apache OpenOffice instance).
Stage Direction
Here are Hypothesizer 7, Objector 14A, and Objector 14B in front of a computer.


Orientation


Hypothesizer 7
In this article, we will get, build, execute, and understand a console C# UNO client sample.

Although the sample is in C#, any .NET Framework programming language should be able to be used instead.

Objector 14B
. . . How?

Hypothesizer 7
Madam, you can just translate the sample into any .NET Framework programming language.

Objector 14B
Being told "you can just" . . .

Hypothesizer 7
Is there a problem?

Objector 14B
. . . It will be more efficient if you do the translation than each of us does the translation separately.

Hypothesizer 7
I? Into what?

Objector 14B
Into VB.NET, of course.

Objector 14B
Actually, I do not see "us", but only you. . . . Well, if there are enough votes for the VB.NET version, I will create it.

Objector 14B
"votes"? How could I vote?

Hypothesizer 7
Well, somehow. . . . Please state so somewhere, linking to this page; I will notice.

Objector 14B
. . .

While I have heard that there is a tool provided by Microsoft that lets me read and write Microsoft-format document files, how is your way different from that?

Hypothesizer 7
Ah, also I have heard about such a tool although I do not remember the name of it. As far as I remember, the tool directly reads and writes such files, while the way I mean handles any LibreOffice or Apache Office instance (which I will call 'office instance' hereafter).

Objector 14B
I don't understand.

Hypothesizer 7
Handling an office instance means connecting to the office instance and asking the office instance to do some things (reading and writing some Microsoft-format document files are just 2 examples).

Objector 14B
What other things can my program ask than reading and writing some document files?

Hypothesizer 7
In fact, almost anything in the LibreOffice or Apache Office functionality.

Objector 14B
For example?

Hypothesizer 7
For example, your program can spellcheck the contents of each file of the files in a directory, show only each of the problematic files, and move the cursor automatically to each misspelled word.

Objector 14B
Ah, certainly, that can't be done by any program that just reads and writes some files that are stored in a storage.

Objector 14A
Do I really have to read all of the articles cited in that 'Starting Context'?

Hypothesizer 7
Sir, it is fine if you have the requisite knowledge and a requisite environment: you do not have to read anything if you already have them. You know, I have clearly defined those presupposed context just because that is an obligation for any decent technical document.


Main Body


1: Getting and Building the Console C# UNO Client Sample


Hypothesizer 7
Here is a console C# UNO client sample. How to build any sample project of this series is described in a previous article.

Please note that MONO or .NET Core cannot be used, as far as I know; proper .NET Framework is required.

After expanding the ZIP file, 'hiConsoleCsharpUnoClients' is the project directory of the sample program; the other 2 directories are of 2 projects-common projects.

How to build your development environment is explained in a previous article (here for Linux and here for Windows).

Stage Direction
Hypothesizer 7 opens a terminal and builds the sample project.


2: Executing the Sample Program


Hypothesizer 7
Before we execute the sample program, we have to have started a LibreOffice or Apache OpenOffice instance so that it accepts connections from clients, as we can know how in a previous article.

Stage Direction
Hypothesizer 7 starts a LibreOffice instance with the port number 2002.

Hypothesizer 7
We can execute the sample program like this with the current directory positioned at the sample project directory and the file URL adjusted to our environment.

@bash or cmd Source Code
gradle i_executeCsharpExecutableFileTask -Pc_commandLineArguments="socket,host=localhost,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext file://${HOME}/myData/development/hiConsoleCsharpUnoClients/execution/HiConsoleCsharpUnoClientsTests.odt"

Stage Direction
Hypothesizer 7 executes the command in the terminal with the current directory positioned at the sample project directory. A OpenDocument Text file is opened and then closed immediately.

Objector 14A
I don't want the document to be shown on the display . . .

Hypothesizer 7
Sir, that is just a demonstration to show that the sample program has successfully connected to the office instance; if you want to open the file without being shown on the display, you can easily do so.

Objector 14A
Oh, it's fine then.

Hypothesizer 7
Please note that an environment variable, 'URE_BOOTSTRAP', is set at the URL of the 'fundamental.ini' file of LibreOffice or Apache OpenOffice.

We can just change the host name from 'localhost' if the office instance is in a remote host, if some firewalls do not block the communication, of course.

Note that in Windows, '${HOME}' is like '/E:/home/tanichida'.


3: Understanding the Sample Program


Hypothesizer 7
The explanation for the console C# UNO client sample is mostly same with that of the console Java UNO client sample, and I will cite some subsections of the previous article and indicate only the differences, without making almost-same-with-some-descriptions-in-the-previous-article descriptions here.


3-1: Understanding the Projects Structure


Hypothesizer 7
There are three projects: 'coreUtilitiesToBeDisclosed', 'unoUtilitiesToBeDisclosed', and 'hiConsoleCsharpUnoClients'. 'coreUtilitiesToBeDisclosed' contains utility code pieces that are supposed to be commonly used in all kinds of projects; 'unoUtilitiesToBeDisclosed' contains utility code pieces that are supposed to be commonly used in UNO program projects; 'hiConsoleCsharpUnoClients' is the sample project.

As the sample program does not do much than just uses 'unoUtilitiesToBeDisclosed', we have to look into the 'unoUtilitiesToBeDisclosed' project in order to learn how to make our external console C# program connect to any UNO server.

While the utility projects contain also some Java code and some C++ code, you can just eliminate the 'source/java' and 'source/cplusplus' directories if they cause any trouble due to your environment that is not for any Java or C++ UNO code.

Objector 14A
. . . Why won't you provide the sample with such unnecessary things removed?

Hypothesizer 7
Well, I do not want to create any such derivative version of any project, because that complicates the maintenance of my code bases. In the first place, the unnecessary code should be just ignored if the 'commonVolatileProperties.gradle' file is configured appropriately as stated in the previous article that is on building any sample project of this site. I have mentioned on eliminating those directories just in case that you have failed to make the appropriate configuration.

Objector 14A
. . .


3-2: What Matter in Order to Go Beyond Connecting to the UNO Server Using the Utility Projects


Hypothesizer 7
Just in case that you use the utility projects as they are, let us see what matter in order to go beyond connecting to the UNO server using the utility projects.

In fact, as the structure of the C# utility classes and interfaces accords with that of the Java utility classes and interfaces, the descriptions of this subsection of the previous article are valid.


3-3: The Wrapper of UNO Objects Context


Hypothesizer 7
The 'theBiasPlanet.unoUtilities.connectionsHandling.UnoObjectsContext' class in the 'unoUtilitiesToBeDisclosed' project is a wrapper of 'UNO objects context'.

The descriptions on the wrapper of this subsection of the previous article are valid for here.


3-4: Creating a Local UNO Objects Context (Bootstrapping)


Hypothesizer 7
The descriptions on the concept of 'bootstrapping' of this subsection of the previous article are valid for here, although how to create the local UNO objects context is different for C#.

This is how to create the local UNO objects context, as can be seen in the constructor of the 'theBiasPlanet.unoUtilities.programsHandling.UnoProcessEnvironment' class.

@C# Source Code
			using uno.util;
			using unoidl.com.sun.star.uno;
			
						XComponentContext l_originalLocalObjectsContext = Bootstrap.defaultBootstrap_InitialComponentContext ();


3-5: Connecting to the UNO Server


Hypothesizer 7
The descriptions on connecting to the UNO server of this subsection of the previous article are valid for here, except a caveat.

If the connection is done via a TCP/IP socket, the Windows socket feature has to be initialized and terminated explicitly by your program.

This is how it is done so in the sample.

theBiasPlanet/coreUtilities/programsHandling/ProcessEnvironment.cs

@C# Source Code
namespace theBiasPlanet {
	namespace coreUtilities {
		namespace programsHandling {
			~
			using System.Runtime.InteropServices;
			~
			
			public class ProcessEnvironment {
				~
				[StructLayout (LayoutKind.Sequential)]
				internal struct WSAData {
					public short wVersion;
					public short wHighVersion;
					[MarshalAs (UnmanagedType.ByValTStr, SizeConst=257)]
					public string szDescription;
					[MarshalAs (UnmanagedType.ByValTStr, SizeConst=129)]
					public string szSystemStatus;
					public short iMaxSockets;
					public short iMaxUdpDg;
					public int lpVendorInfo;
				}
				[DllImport ("ws2_32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
				internal static extern int WSAStartup (
					[In] short wVersionRequested,
					[Out] out WSAData lpWSAData
				);
				[DllImport ("ws2_32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
				internal static extern int WSACleanup ();
				private const int c_windowsSocketStartupSuccessStatus = 0;
				private const short c_windowsSocketVersion = 0x0202;
				~
				
				public static void windowsSocketStartup () {
					WSAData l_windowsSocketData;
					int l_windowsSocketStartupStatus = WSAStartup (c_windowsSocketVersion, out l_windowsSocketData);
					if (l_windowsSocketStartupStatus != c_windowsSocketStartupSuccessStatus) {
						throw new System.Exception (String.Format ("WSAStartup failed: return code = {0:D}", l_windowsSocketStartupStatus));
					}
				}
				
				public static void windowsSocketCleanup () {
					WSACleanup ();
				}
			}
		}
	}
}

theBiasPlanet/hiConsoleCsharpUnoClients/programs/HiConsoleCSharpUnoClients.cs

@C# Source Code
namespace theBiasPlanet {
	namespace hiConsoleCsharpUnoClients {
		namespace programs {
			~
			using System;
			using theBiasPlanet.coreUtilities.programsHandling;
			
			public class HiConsoleCSharpUnoClients {
				static void Main (String [] a_argumentsArray) {
					try {
						~
						ProcessEnvironment.windowsSocketStartup ();
						~
						ProcessEnvironment.windowsSocketCleanup ();
					}
					catch (Exception l_exception) {
						~
					}
				}
			}
		}
	}
}


3-6: Cutting the Connection


Hypothesizer 7
The descriptions on cutting the connection of this subsection of the previous article are valid for here.


4: Although There Is a Simpler Way of Connecting to an Office Instance . . .


Hypothesizer 7
Actually, there is a simpler way of connecting to an office instance, but that way has some limitations, which are critical in certain cases.

The discussion in this section of the previous article is valid for here.


5: The Conclusion and Beyond


Hypothesizer 7
Now, we can connect to any UNO server from our console C# UNO client.

The reason why I have specified that the sample is a 'console' client is that a GUI C# UNO client sample will come in a future article.

The GUI C# UNO client might not seem to have to be different from the console C# UNO client UNO-wise, but there is a difference: as the UNO client is supposed to be up for some long durations, it is more appropriate to detect connection cuts caused by the UNO server or the network.


References


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