2017年11月5日日曜日

1: シリーズ「BasicマクロでUNOを使用することについての覚え書き」の前書き

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

本文 START

本シリーズは、メインシリーズ、「UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を開発する」の記述をBasicマクロでのUNOの使用に適用するための、メインシリーズへの補完である

話題: UNO (Universal Network Objects)

話題: LibreOffice

話題: Apache OpenOffice

話題: LibreOffice Basicプログラミング言語

本シリーズの目的

バイアス惑星の山あいの小川のほとりのある部屋でコンピュータースクリーンの前に座る-Hypothesizerと-Rebutter。

-Hypothesizer

既に、シリーズ、「UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を開発する」があり、これはJavaによるUNOコンポーネント(UNOコンポーネントが何かを知るには、ここを参照)からなるUNO拡張機能を開発することについてのものだが、その基本的な考えのほとんどは、BasicマクロでUNOを使用することにもあてはまる。というのも、それらは、UNOを使用することについてであって、UNOは、基本的に言語に独立な仕様だから。

-Rebutter

オーケー。

-Hypothesizer

しかしながら、UNOのBasicマッピングにはいくつかの特別な扱いが与えられているので、我々はそれらを知らなければならない。

-Rebutter

UNOのBasicマッピングにはなぜそのような特別な扱いが与えられているのか?

-Hypothesizer

UNOに必須ないくつかの機能がLibreOffice Basicには欠けているので、それが必要なわけだ。もっとも目立つところでは、Basicにはインターフェースの概念がない。

-Rebutter

ははあ。

このシリーズで我々が扱うこと

前場と同じ。

-Hypothesizer

あらかじめ言っておくが、我々は、大規模なロジックをBasicで実装する習慣にないので、BasicでUNOを使ってロジックを組むことについて、包括的なコメントをするつもりはない。

-Rebutter

よく分からないな。

-Hypothesizer

例えば、我々は、メインシリーズでスプレッドシートセルから読んだりスプレッドシートセルに書いたりする方法について取り扱ったが、このシリーズでは、そのような個別のロジックについて取り扱ったりはしない。

-Rebutter

ああ、そこで記述されたロジックはBasicに適用できるはずだ。あとは、そのロジックがどのプログラミング言語で書かれているかというだけの問題だ。

-Hypothesizer

だから、我々は、同じ議論を、ただBasicのコードでそれを示すというためだけに繰り返しはしない。

-Rebutter

いいだろう。

-Hypothesizer

実際のところ、Basicの大規模なコードを書こうという動機が私には全然ない。

-Rebutter

なぜないのか?

-Hypothesizer

JavaでUNOコンポーネントを作ることで、はるかにもっと広範囲のロジックをもっと効率的かつ堅牢に書けるから。Javaはより堅牢だ(より厳格にデータ型チェックをしてくれる)し、大規模なプログラミングにより適している(本格的なオブジェクト指向言語だ)し、機能もより豊富だ(BigDecimal、List、Set、Mapなどの豊富なデータ型がある、マルチスレッディングが行なえる、よりリッチなGUIが作れる、JNIを通してOSネイティブの機能にもアクセスできる)。

-Rebutter

実のところ、我々はBasicにあまり通じていない。

-Hypothesizer

そう、そしてそれが最大の理由だ。

-Rebutter

ははあ。

-Hypothesizer

また、我々は、個々のUNOコンポーネントの詳細を取り扱わない。というのも、それらは、メインシリーズで取り扱われている、または、取り扱われるであろうから。

-Rebutter

それらもやはり、言語に独立だ。

-Hypothesizer

このシリーズでは、UNOコンポーネント一般を呼び出す方法のみを取り扱う。

コンポーネントコンテキストに対する特別な扱い

前場と同じ。

-Hypothesizer

UNOを使用することについての汎用ルールは、「コンポーネントコンテキストを取得しろ。そうすれば、そのコンポーネントコンテキストを使って、許されていることは何でもできる」だ。

-Rebutter

コンポーネントコンテキストはUNO環境へのハンドルであって、UNOサービスインスタンス(UNOサービスが何かを知るにはここを参照)としてのUNOオブジェクト(UNOオブジェクトが何かを知るにはここを参照)は、コンストラクタの引数としてもれなくそれを受け取り、外部UNOプログラムは、希望するUNO環境へ接続してそれを得る。それが、シリーズ、「UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を開発する」とシリーズ、「外部JavaプログラムでUNOを使用する(LibreOfficeまたはApache OpenOfficeのドキュメントを操作する)方法」で我々が学んだことだ。

-Hypothesizer

しかし . . .

-Rebutter

. . . しかし、何だ?

-Hypothesizer

「しかし」というべきだったのかどうか。. . . 実際、Basicマクロにおいても、間違いなく、コンポーネントコンテキストを得られるし、コンポーネントコンテキストを使って、UNO環境を操作することができる。

-Rebutter

それでは、何が問題なのか?

-Hypothesizer

特に何も。実際、コンポーネントコンテキストは以下のようにして得られる。

-Hypothesizerは、LibreOfficeインスタンスを起動し、あるBasicモジュールを開き、そのモジュールに1つのSubを書く。

@LibreOffice Basic Source Code
Sub testToGetDefaultComponentContext
 Dim l_componentContext As Variant
 
 l_componentContext = GetProcessServiceManager ().getPropertyValue ("DefaultContext")
End Sub
-Rebutter

ふむ?まあ、どのようにコンポーネントコンテキストを得るにせよ、Javaでやったのと基本的に同じ方法でそれを使えるのだろう?

-Hypothesizer

そうだ。. . . しかし . . .

-Rebutter

. . . しかし、何だ?

-Hypothesizer

うーん、以下が、BasicでUNOサービスのインスタンスを生成する典型的な方法だ。

-Hypothesizerは、先ほどのモジュールに別のSubを書く。

@LibreOffice Basic Source Code
Sub testToCreatServiceInstanceInTypicalWay
 Dim l_globalServicesManager As Variant
 Dim l_arguments (0)
 Dim l_heyUnoExtensionsUnoObject As Variant
 
 l_globalServicesManager = GetProcessServiceManager ()
 l_arguments (0) = "Good morning"
 l_heyUnoExtensionsUnoObject = l_globalServicesManager.createInstanceWithArguments ("thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsService", l_arguments ())
End Sub
-Rebutter

えー、コンポーネントコンテキストを得るのに先程使ったファンクション、'GetProcessServiceManager'は、実はグローバルUNOサービスマネージャー(グローバルUNOサービスマネージャーが何かを知るにはここを参照)を戻している。. . . 'createInstanceWithArguments'というメソッドは何だ?Javaでは'createInstanceWithArgumentsAndContext'というメソッドをコンポーネントコンテキストを渡して使ったが。

-Hypothesizer

Javaでも前者のメソッドを使うことはできるが、そうしなかった、というのは、そういうやり方は最良ではないから。

-Rebutter

なぜ?

-Hypothesizer

コンポーネントコンテキストはUNO環境へのハンドルだと言ってきたが、実際には、コンポーネントコンテキストは、実行時環境としての、いくつかのプロパティのコンテナでもある。

-Rebutter

ははあ . . .

-Hypothesizer

コンポーネントコンテキストは、UNOオブジェクトの生成スタックに沿って伝達されると想定されているものだ。そして、コンポーネントコンテキストは、その途中で、変更されたバージョンで置き換えることができる。

-Rebutter

例えば、あるUNOオブジェクトが生成されるとき、それは、あるコンポーネントコンテキストを受け取る。それは、必要であれば、そのコンポーネントコンテキストの変更バージョンを作る(いくつかのプロパティを追加、いくつかのプロパティを削除、いくつかのプロパティ値を変更、またはそれらの一部またはすべてを行なう)ことができ、最新版のコンポーネントコンテキスト(変更されていれば変更されたもの、変更されていなければ受け取ったもの)を、別の新たに生成されたUNOオブジェクトに渡す . . .

-Hypothesizer

そう。'createInstanceWithArguments'を使うと、我々は、新たに生成されたUNOオブジェクトに最新版のコンポーネントコンテキストを渡さない。グローバルUNOサービスマネージャーがデフォルトコンポーネントコンテキストとして認識するコンポーネントコンテキストが新たに生成されたUNOオブジェクトに渡される。

-Rebutter

そして、それが正に、上記の典型的なコードが行なっていることだ . . .

-Hypothesizer

そうだ。

-Rebutter

まあ、結局、Basicモジュールは、UNOコンポーネントではないから、特定のコンポーネントコンテキストを受け取らない、または、デフォルトコンポーネントコンテキストを受け取るのだと言えるのかもしれない。そして、そのデフォルトコンポーネントコンテキストを、新たに生成されたUNOオブジェクトに明示的に渡そうが渡さまいが、実際的には同じことだ、どちらにしろ、デフォルトコンポーネントコンテキストが渡されるのだから。

-Hypothesizer

そのように思われる。

Basicランタイムは、デフォルトコンポーネントコンテキストが常に使われるという前提に立っているから、デフォルトコンポーネントコンテキストを直接には公開せず、グローバルUNOサービスマネージャーを公開している。そして、ほとんどの場合、使用するコンポーネントコンテキストを明示的に指定しなくても問題ない。しかし、特定のコンポーネントコンテキストを明示的に指定しなければならなかったり、したい場合は、いつでもそうできる。実際、以下のコードは問題なく動作する。

-Hypothesizerは先程のモジュールにあるSubを書く。

@LibreOffice Basic Source Code
Sub testToCreatServiceInstanceExplicitlySpecifyingComponentContext
 Dim l_componentContext As Variant
 Dim l_globalServicesManager As Variant
 Dim l_arguments (0)
 Dim l_heyUnoExtensionsUnoObject As Variant
 
 l_componentContext = GetProcessServiceManager ().getPropertyValue ("DefaultContext")
 l_globalServicesManager = l_componentContext.getServiceManager ()
 l_arguments (0) = "Good morning"
 l_heyUnoExtensionsUnoObject = l_globalServicesManager.createInstanceWithArgumentsAndContext ("thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsService", l_arguments (), l_componentContext)
End Sub
-Rebutter

特定のUNOサービス専用UNOサービスインスタンスファクトリー(「特定のUNOサービス専用UNOサービスインスタンスファクトリー」で我々が何を意味しているかを知るにはここを参照)を通してUNOサービスインスタンスを生成する場合はどうか?

-Hypothesizer

同じだ。コンポーネントコンテキストを渡さなくても問題ないが、渡したければ渡すことができる。

-Rebutter

コンポーネントコンテキストを受け取る第1引数の存在をただ無視すればよいということか、nullを第1引数に渡すのではなく?

-Hypothesizer

そうだ。

-Rebutter

ところで、我々がこれまで話してきたコンポーネントコンテキストは、Basicのコードが動作するLibreOfficeインスタンスのものだろう?

-Hypothesizer

そう。それが、通常、Basicマクロが操作するように想定されているUNO環境だ。

-Rebutter

別のUNO環境(例えば、リモートホスト上のUNO環境)のコンポーネントコンテキストは、どうすれば得られるのか?

-Hypothesizer

Basicだけでそれを行なう方法を私は知らない。自分のUNOコンポーネントを通してそうすることはできるだろう、必要ならば。

-Rebutter

ああ、シリーズ、「外部JavaプログラムでUNOを使用する(LibreOfficeまたはApache OpenOfficeのドキュメントを操作する)方法」の記述にしたがえばそうすることができる。

UNOインターフェースに対する特別な扱い

-Hypothesizer

Basicでは、各UNOインターフェース(UNOインターフェースが何かを知るには、ここを参照)を代理するUNOプロキシ(UNOプロキシが何かを知るには、ここを参照)を明示的に得る必要はない。UNOオブジェクトに対して任意のメソッドをただ呼ぶことができる。

-Rebutter

その機能(ここを参照)をサポートするようにUNOコンポーネントが作られた場合に限りそうだと記憶しているが。

-Hypothesizer

そう、そのはずだ。

どのUNOオブジェクトを参照させる場合も、変数タイプにVariantを使う

-Hypothesizer

どのUNOオブジェクトを参照させる場合も、変数タイプにはVariantを使う。

-Rebutter

ああ、Javaでは、UNOオブジェクト(厳密に言えば、UNOプロキシ)を参照させるのに、変数タイプとしてUNOインターフェースを使う。

-Hypothesizer

Basicではインターフェースを使えないから、ただVariantを使って済ませる。

この参考文書は、変数タイプとしてObjectを使うべきでないと言っている、とはいえ、Objectは参考文書内の例で頻繁に使われているのだが。

-Rebutter

つまり、参考文書が言うようにすべきであって、参考文書がしているようにではないということか . . .

データタイプマッピングを知らなければならない

-Rebutter

UNOとBasicの間のデータタイプマッピングを知らなければならないだろう。

-Hypothesizer

それは、ここで調べることができる。

本文 END

参考資料

  • Apache OpenOffice Wiki. (2009/05/13). OpenOffice.org Basic. Retrieved from https://wiki.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Basic/OpenOffice.org_Basic

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