2019年12月15日日曜日

22: UNOディスパッチコマンドを実行し、全情報を取得する(C#編)

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

あなたの怠惰な方法は、実行から入手可能な一部の有用な情報を逃しているかもしれません。

話題


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

この記事の目次


開始コンテキスト



ターゲットコンテキスト



  • 読者は、C#でUNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法を知る。
ト書き
Hypothesizer 7、Objector 22A、Objector 22Bがコンピューターの前にいる。


オリエンテーション


Hypothesizer 7
この記事では、C#でUNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法を知ることになります。

Objector 22B
それは、Visual Basic.NETでもできるんでしょう?

Hypothesizer 7
はい、できます、マダム。

Objector 22B
それじゃあ、そのVisual Basic.NET実装はどこにあるの?

Hypothesizer 7
えーと、どの実装のことでしょうか?

Objector 22B
あなたの実装のことよ、もちろん!

Hypothesizer 7
そのような実装を作成した記憶はございませんが...

Objector 22B
作成してないの?

Hypothesizer 7
そう信じております。

Objector 22B
信じられない!

Hypothesizer 7
どうか信じてください。

Objector 22B
じゃあ、いつ作られるの?

Hypothesizer 7
えーと、作成されると計画されたという記憶はございませんが...

Objector 22B
何ですって?なんで?

Hypothesizer 7
それに対して多くの需要を見かけないので。...それが欲しい読者がいらっしゃれば、私にお知らせくださって結構です。

Objector 22B
どうやって?

Hypothesizer 7
どこかでそう述べて、本記事にリンクしてくだされば、私のほうで気付くでしょう。

Objector 22B
...

Objector 22A
お前の長々しい'開始コンテキスト'は何のことか分からん。私が知りたいことを、分かるように簡潔に言ってくれ!

Hypothesizer 7
サー...、技術的知識というものはどれも、基礎から始めて、順序立てて築き上げる必要があります。お分かりのように、まず四則演算を学ぶことなく、微分積分へ行くというわけにはいきません。

Objector 22A
お前は一体何様のつもりだ!

Hypothesizer 7
...私が誰だろうがどうでもよいのです、宇宙の法則についての話をしているのです。

Objector 22A
パラレルユニバースがあるかもしれない!

Hypothesizer 7
...それが本件とどう関係するのでしょうか、サー?

Objector 22A
お前は扁平足だ!

Hypothesizer 7
はあ?


本体


1: UNOディスパッチコマンドを関連情報を取得することなく実行する容易な方法


Hypothesizer 7
最初に、UNOディスパッチコマンドを関連情報を取得することなく実行する方法を知っておきましょう。

Objector 22A
はあ?なぜ、全情報を取得する方法を言わない?

Hypothesizer 7
全情報が常に必要というわけではないかもしれず、一部の準備ステップは共通なので、共通の準備ステップを説明する傍ら、簡略化された方法にも補足的に言及すべきだろうと考えました。

Objector 22A
それじゃあ、私はこのセクションを読みとばす。

Hypothesizer 7
サー、次セクション(全情報を取得することについてのもの)は本セクションをベースとして記述されるので、不運なことに、あなたはどのみち本セクション(少なくとも、その大半)を読むように想定されています。

Objector 22A
「想定されてい」る?私は「想定されてい」る?お前は一体何様のつもりだ?!

Hypothesizer 7
...私の自己認識はどうでもよいのです。本記事の構造について話しているのです。

Objector 22A
お前の足の指は巻き爪だ!

Hypothesizer 7
はあ?...

とにかく、UNOディスパッチコマンドはどれも、あるフレームに対して実行されるので、まず、そのフレームを取得しなければなりません。もしも、UNOディスパッチコマンドをあるドキュメントに対して実行したいのであれば、そのドキュメントを格納するフレームを取得しなければならないでしょう。さもなければ、UNOデスクトップフレームを使います。

Objector 22A
「UNOデスクトップフレーム」というのは、'UNOデスクトップに関連付けられたフレーム'のことなのか、それとも'UNOデスクトップであるフレーム'のことなのか?

Hypothesizer 7
後者です: UNOデスクトップ自体がフレームなのです。

ドキュメントを格納するフレームを取得するためには、まず、そのドキュメントUNOオブジェクトの'unoidl.com.sun.star.frame.XModel' UNOプロキシを取得しなければなりません。

特定のドキュメントのUNOオブジェクトへのアクセスを取得する方法がいくつかあります、しかし、それらの全てに立ち入ることは、ここではしません(ある以降の記事でそうするでしょう)。その代わりに、広く役立つ1つの方法を紹介しましょう: カレントドキュメントのUNOオブジェクトへのアクセスを取得します。

Objector 22A
「広く役立つ」?その通りだ。だが、全てのユースケースをカバーしているわけじゃない。

Hypothesizer 7
勿論です。だから、以降の記事を御参照いただけます。

Objector 22A
まだ存在しない記事を参照などできない...

Hypothesizer 7
以下のコードを見てみましょう('l_objectsContext'は、UNOオブジェクト群コンテキストであり、'l_unoDocumentInXModel'は、当該ドキュメントUNOオブジェクトの'unoidl.com.sun.star.frame.XModel' UNOプロキシです)。

@C# ソースコード
			using unoidl.com.sun.star.frame;
			
							XDesktop2 l_unoDesktopInXDesktop2 = (XDesktop2) l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.Desktop", l_unoObjectsContext);
							XModel l_unoDocumentInXModel = (XModel) l_unoDesktopInXDesktop2.getCurrentComponent ();

Objector 22A
ふーむ。

Hypothesizer 7
次に、当該フレームUNOオブジェクトの'unoidl.com.sun.star.frame.XDispatchProvider' UNOプロキシを取得します、以下のように。

@C# ソースコード
							XController l_controllerInXController = (XController) l_unoDocumentInXModel.getCurrentController ();
							XDispatchProvider l_frameInXDispatchProvider = (XDispatchProvider) l_controllerInXController.getFrame ();

Objector 22A
なるほど。

Hypothesizer 7
その一方、UNOデスクトップフレームUNOオブジェクトの'unoidl.com.sun.star.frame.XDispatchProvider'UNOプロキシは、以下のようにして取得できます。

@C# ソースコード
			using unoidl.com.sun.star.frame;
			
							XDispatchProvider l_frameInXDispatchProvider = (XDispatchProvider) l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.Desktop", l_unoObjectsContext);

Objector 22A
それは予期どおりだ。

Hypothesizer 7
どのフレームへのアクセスを取得したにせよ、次に、UNOディスパッチヘルパーUNOオブジェクトの'unoidl.com.sun.star.frame.XDispatchHelper' UNOプロキシを取得します、以下のように。

@C# ソースコード
							XDispatchHelper l_dispatchHelperInXDispatchHelper = (XDispatchHelper) l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.DispatchHelper", l_unoObjectsContext);

Objector 22A
ははあ。

Hypothesizer 7
最後に、UNOディスパッチコマンドを実行します、コマンドURLおよびコマンド引数群を指定して、以下のように。

@C# ソースコード
			using com.sun.star.beans;
			
							PropertyValue [] l_dispatchArgumentPropertiesArray = new PropertyValue [1];
							l_dispatchArgumentPropertiesArray [0] = new PropertyValue ();
							l_dispatchArgumentPropertiesArray [0].Name = "ToPoint";
							l_dispatchArgumentPropertiesArray [0].Value = "$B$2";
							Object l_commandResult = l_dispatchHelperInXDispatchHelper.executeDispatch (l_frameInXDispatchProvider, ".uno:GoToCell", "_self", -1, l_dispatchArgumentPropertiesArray);

Objector 22A
えーと...

Hypothesizer 7
「_self」および「-1」は、コマンドのターゲットフレーム名とそのフレームを発見するための検索フラグです。

ご推測できるとおり、'_self'は、固有名ではなく、問題にしているフレーム自体(本ケースでは'l_frameInXDispatchProvider')を意味する特殊フレーム名です。

他の特殊フレーム名たちを理解するには、フレームたちがどのように組織されているかを知らなければなりません: どのフレームも1つのフレーム群階層に属し、どの階層もルートフレーム(それがデスクトップです)の下に属します。

'_parent'は、問題にしているフレームの直接の親を意味し、'_top'は、問題にしているフレームが属する階層のトップフレームを意味し('_top'はルートフレームを意味せず、ルートフレームの下のフレームを意味することにご注意ください)、'_blank'は、新たなトップフレームを意味します。

Objector 22A
妙な用語体系だ。トップフレームが全然トップじゃない...

Hypothesizer 7
Calcドキュメントについて言うと、私たちが取得したフレームがトップフレームであり、子はありません。

Objector 22A
特殊名ではなく固有名を使う場合、ファイル名が固有名なのか?

Hypothesizer 7
実は、固有名はブランクです、あなたが明示的にセットしたのでない限り。

Objector 22A
意味がないように思えるなあ...

Hypothesizer 7
ターゲットフレームを発見するための検索フラグとして指定した「-1」は、実のところ、何も意味していません、その引数は、その前の引数に特殊フレーム名が指定された場合は無視されるので。

Objector 22A
うーん...

Hypothesizer 7
結果情報が具体的に何であるかは、UNOディスパッチコマンド次第です、しかし多くの場合、結果情報はあまり有益ではありません。


2: UNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法


Hypothesizer 7
関連情報を取得するには、本セクションで論じられる方法を取らなければなりません。

結果情報および関連情報はそれぞれ'unoidl.com.sun.star.frame.XDispatchResultListener'および'unoidl.com.sun.star.frame.XStatusListener'に通知されるので、'unoidl.com.sun.star.frame.XDispatchResultListener'を実装するクラス1つおよび'unoidl.com.sun.star.frame.XStatusListener'を実装するクラス1つ以上を作成します。単一のクラスに両UNOインターフェースを実装させることもできます。

例えば、以下は、'unoidl.com.sun.star.frame.XDispatchResultListener'の1実装と'unoidl.com.sun.star.frame.XStatusListener'の1実装です。

@C# ソースコード
			using unoidl.com.sun.star.lang;
			
				class ResultInformationListener : XDispatchResultListener {
					public ResultInformationListener () {
					}
					
					public void dispatchFinished (DispatchResultEvent a_dispatchResultEvent) {
						Console.Out.WriteLine ("### The dispatch execution is finished.");
					}
					
					public void disposing (unoidl.com.sun.star.lang.EventObject a_source) {
					}
				}
				
				class RelatedInformationListener : XStatusListener {
					public RelatedInformationListener () {
					}
					
					public void statusChanged (FeatureStateEvent a_featureStateEvent) {
						Console.Out.WriteLine ("### A dispatch execution related information piece is offered.");
					}
					
					public void disposing (unoidl.com.sun.star.lang.EventObject a_source) {
					}
				}
				
							ResultInformationListener l_resultInformationListener = new ResultInformationListener ();
							RelatedInformationListener l_relatedInformationListener = new RelatedInformationListener ();

Objector 21A
それらのイベントオブジェクトの使い方が分からない...

Hypothesizer 7
それらのクラスは、UNO APIドキュメント('unoidl.com.sun.star.frame.DispatchResultEvent'は、ここ、'unoidl.com.sun.star.lang.EventObject'は、ここ、'unoidl.com.sun.star.frame.FeatureStateEvent'は、ここ)で調べてください。

Objector 22B
「unoidl.」という接頭子は、UNO APIにおける名前の1部ではないようだな。それはどこから来たのだ?

Hypothesizer 7
えーと、...メカニズムを正確には知りませんが、ほとんどの.NET Framework UNOタイプ名にはそれが付いています、恐らく、名前の衝突を避けるために。

Objector 22B
...

Hypothesizer 7
フレームUNOオブジェクトの'unoidl.com.sun.star.frame.XDispatchProvider' UNOプロキシを取得しますが、方法は、前セクションで説明したのと同じです。

次に、'unoidl.com.sun.star.util.URL'オブジェクト(UNOオブジェクトではない)を以下のようにセットアップします。

@C# ソースコード
using unoidl.com.sun.star.util;

							unoidl.com.sun.star.util.URL l_urlInURL = new unoidl.com.sun.star.util.URL ();
							l_urlInURL.Complete = ".uno:GoToCell";
							XURLTransformer l_urlTransformerInXURLTransformer = (XURLTransformer) l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.util.URLTransformer", l_unoObjectsContext);
							l_urlTransformerInXURLTransformer.parseStrict (ref l_urlInURL);

Objector 22A
...前セクションではそんな面倒なことをしなくてよかったが...

Hypothesizer 7
それは、その面倒な作業をヘルパーが引き受けたからです。しかし、その面倒な作業を私たちが行なうほうが、より効率的であり得ます、URLトランスフォーマーUNOオブジェクトおよび'unoidl.com.sun.star.util.URL'オブジェクトを最大限に再利用することによって。

Objector 22A
それはあり得ることだ。

Hypothesizer 7
とにかく、次に、ディスパッチャーUNOオブジェクトの'unoidl.com.sun.star.frame.XNotifyingDispatch' UNOプロキシを以下のように取得します。

@C# ソースコード
							XNotifyingDispatch l_dispatcherInXNotifyingDispatch = (XNotifyingDispatch) l_frameInXDispatchProvider.queryDispatch (l_urlInURL, "_self", (short) -1);

Objector 22A
そのディスパッチャーは再利用できるのか?

Hypothesizer 7
同じURLに対しては、できます。別のURLに対しては、一般的にはできません、ただし、そのディスパッチャーがその別URLのディスパッチャーでもあった場合はできます。

Objector 22A
ああ、それでは、URL毎にディスパッチャーが違うわけだ、一般的に言って...

Hypothesizer 7
はい、それが、ディスパッチャーを取得するのにURLを指定しなければならない理由です。

Objector 22A
それはとてもリーズナブルだ。

Hypothesizer 7
次に、関連情報リスナー(複数可能)をディスパッチャーに登録し、最後に、私たちのコマンドをディスパッチャーに送ります、以下のように。

@C# ソースコード
			using unoidl.com.sun.star.beans;
			
							l_dispatcherInXNotifyingDispatch.addStatusListener (l_relatedInformationListener, l_urlInURL);
							PropertyValue [] l_dispatchArgumentPropertiesArray = new PropertyValue [2];
							l_dispatchArgumentPropertiesArray [0] = new PropertyValue ();
							l_dispatchArgumentPropertiesArray [0].Name = "SynchronMode";
							l_dispatchArgumentPropertiesArray [0].Value = new Any (true);
							l_dispatchArgumentPropertiesArray [1] = new PropertyValue ();
							l_dispatchArgumentPropertiesArray [1].Name = "ToPoint";
							l_dispatchArgumentPropertiesArray [1].Value = new Any ("$B$2");
							l_dispatcherInXNotifyingDispatch.dispatchWithNotification (l_urlInURL, l_dispatchArgumentPropertiesArray, l_resultInformationListener);
							l_dispatcherInXNotifyingDispatch.removeStatusListener (l_relatedInformationListener, l_urlInURL);

Objector 22A
'SynchronMode'引数を指定することでそれを明示的に同期にしなければならないようだな。

Hypothesizer 7
非同期にしたければ必要ありません、私は同期にしたがるでしょうが、ほとんど常に。

'statusChanged'メソッドは複数回呼ばれる可能性があり(または全然呼ばれないかもしれない)、'dispatchFinished'メソッドは最後に一度だけ呼ばれます。

私の各種サンプル(コンソールC# UNOクライアントファイルコンバーター, など)で使用されている私のUNOユーティリティプロジェクト、'unoUtilitiesToBeDisclosed'では、UNOドキュメントラッパークラスである'theBiasPlanet.unoUtilities.documentsHandling.UnoDocument'が両リスナーインターフェースを実装しており、'dispatch'というメソッドも持っています。このメソッドは、UNOディスパッチコマンドを実行し、結果情報および関連情報をリターン値にパックして戻します。

Objector 22B
...

Hypothesizer 7
'dispatch'メソッドの第1引数である'UnoDispatchSlotsConstantsGroup.BaseDispatchSlot a_dispatchSlot'は、実行しようとするUNOディスパッチコマンドのURLと引数名群を保持しているオブジェクトです。実は、'theBiasPlanet.unoUtilities.constantsGroups.UnoDispatchSlotsConstantsGroup'クラスがそうしたオブジェクトたちを保持しています。そうした情報は、各プログラムに文字列リテラルとして散らばらせるよりも1箇所においたほうが望ましいだろうと思いました。


3: 結びとその先


Hypothesizer 7
これで、C#でUNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法を知りました。

もちろん、UNOディスパッチコマンドは、他のプログラミング言語(Java、C++、Python、LibreOffice BasicまたはApache OpenOffice Basic、BeanShell、JavaScript)で実行することもできます。JavaC++でそうする方法を以前の記事で学びましたし、いくつかの他のプログラミング言語でそうする方法を以降の記事群(PythonおよびLibreOfficeまたはApache OpenOffice Basic)で学びます。

LibreOffice基盤のためのUNOディスパッチコマンドの未完の(今のところ)リストとリストされたコマンドの仕様説明および LibreOffice CalcのためのUNOディスパッチコマンドの未完の(今のところ)リストとリストされたコマンドの仕様説明があります。

UNOディスパッチコマンドを実行するのは、LibreOfficeまたはApache OpenOfficeのインスタンスを操作する1つの方法ですが、LibreOfficeまたはApache OpenOfficeのインスタンスの操作で私たちができることの全てをカバーしているわけではありません: UNOオブジェクトを直接操作することでもっと多くのことを行なえます(本シリーズの目次を御参照ください)。


参考資料


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