クライアント・プログラムを記述する
クライアント・プログラムを構築するには、少なくともcli_types.dllとcli_cppuhelper.dllを参照する必要があります。また、cli_ureは、クラスの1つが使用されているときに参照できます。これらのライブラリは、GACとオフィス・インストールのプログラム・フォルダの中にインストールされます。参照は、例えば、C++(管理された拡張で)は、/A、または、C#コンパイラでは、/referenceの特定のコンパイラ・スイッチで行われます。また、C ++では、#usingを使用してdllを指定する必要があります。
#using <mscorlib.dll>
#using <cli_types.dll>
あなたのプロジェクトを作成するとき、Visual Studioによるc#では、mscorlibが、含まれます。あなたの参照でそれを見たい場合は、.csprojファイルを編集して追加してください。:
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
cli_basetypes、cli_cppuhelper、cli_oootypes、cli_ureとcli_uretypes .dllファイルのために、私は、Visual Studioのプロジェクト参照に、それらを追加します。私は、ここでは、cli_cppuhelperが、:\WINDOWS\assembly\GAC_32\cli_cppuhelper\1.0.22.0__ce2cb7e279207b9e\cli_cppuhelper.dllだと見つけました。そして、 GAC_MSIL中にある他のものは近くの、:\WINDOWS\assembly\GAC_MSIL\cli_basetypes\1.0.19.0__ce2cb7e279207b9e\cli_basetypes.dllにあります。続いて、クラスの1つが使用されるとき、ソースに以下を追加してください。:
using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.uno;
using unoidl.com.sun.star.bridge;
using unoidl.com.sun.star.frame;
using unoidl.com.sun.star.util;
次の例では、オフィス処理に実行することで、どのように、提供したサービスを使用するかを説明します。:
すべてのリモート・クライアント・プログラムの開始位置は、コンポーネント・コンテキストです。それは、クラスuno.util.Bootstrapで提供される、static defaultBootstrap_InitialComponentContextによって作成されます。コンテキストは、UNOコンポーネントを作成するためのサービスマネージャを提供します。しかしながら、これらのコンポーネントは、依然として、クライアント処理にローカルです。すなわち、それら、実行中のオフィスからではありません。そして、その結果、実行中のオフィスに影響を与えることはできません。実際に必要なものは、実行中のオフィスのサービス・マネージャーです。それを実現するためには、ローカル・サービス・マネージャーで提供される、コンポーネントcom.sun.star.bridge.UnoUrlResolverが、使われます。UnoUrlResolverは、リモート・オフィスに接続して、クライアント処理において、オフィスのサービス・マネージャーのプロキシを作成します。サンプルコード(OOo 2.x)は、次のとおりです。:
//C# example
System.Collections.Hashtable ht = new System.Collections.Hashtable();
ht.Add("SYSBINDIR", "file:///<office-dir>/program");
unoidl.com.sun.star.uno.XComponentContext xLocalContext =
uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(
"file:///<office-dir>/program/uno.ini", ht.GetEnumerator());
unoidl.com.sun.star.bridge.XUnoUrlResolver xURLResolver =
(unoidl.com.sun.star.bridge.XUnoUrlResolver)
xLocalContext.getServiceManager().
createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver",
xLocalContext);
unoidl.com.sun.star.uno.XComponentContext xRemoteContext =
(unoidl.com.sun.star.uno.XComponentContext)xURLResolver.resolve(
"uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext");
unoidl.com.sun.star.lang.XMultiServiceFactory xRemoteFactory =
(unoidl.com.sun.star.lang.XMultiServiceFactory)
xRemoteContext.getServiceManager();
OOo 3.xのための、コードは、これです。:
//C# example for OOo 3.x
// OOo 3.xのC#の例
//Workaround which is needed when using a socket connection
// ソケット接続を使用するとき、必要な回避策
//This will initialize the Windows socket library.
// これは、Windowsのソケット・ライブラリを初期化します。
System.Net.Sockets.Socket s = new System.Net.Sockets.Socket(
AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
//
String sUnoIni = "file:///d:/OpenOffice.org%203/URE/bin/uno.ini";
XComponentContext xLocalContext =
uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(sUnoIni, null);
XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager();
XUnoUrlResolver xUrlResolver =
(XUnoUrlResolver)xLocalServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", xLocalContext);
XMultiServiceFactory multiServiceFactory =
(XMultiServiceFactory)xUrlResolver.resolve(
"uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager");
他の方法として、パイプ接続を使用することができ、この場合、あらかじめソケットを作成する必要はありません。
//C# example for OOo 3.x
String sUnoIni = "file:///d:/OpenOffice.org%203/URE/bin/uno.ini";
XComponentContext xLocalContext =
uno.util.Bootstrap.defaultBootstrap_InitialComponentContext(sUnoIni, null);
XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager();
XUnoUrlResolver xUrlResolver =
(XUnoUrlResolver)xLocalServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", xLocalContext);
XMultiServiceFactory multiServiceFactory =
(XMultiServiceFactory)xUrlResolver.resolve(
"uno:pipe,name=some_unique_pipe_name;urp;StarOffice.ServiceManager");
通常、オフィス・インストールにおいて、uno.ini(URE/binフォルダー)に、パスを提供します。その場合、そして、特定のブートストラップ変数を提供したくない場合、(defaultBootstrap_InitialComponentContextの2つ目のパラメータ)続いて、引数を取らないdefaultBootstrap_InitialComponentContextのバージョンを使用することができます。:
XComponentContext xLocalContext =
uno.util.Bootstrap.defaultBootstrap_InitialComponentContext();
XMultiServiceFactory fac = (XMultiServiceFactory) m_xContext.getServiceManager();
手元にある実行中のオフィスのファクトリーで、リモート・オフィスのすべてのコンポーネントにアクセスできます。
実行中のオフィスに接続するクライアントのために、オフィスは、適切なパラメータで開始されている必要があります。この場合、コマンド・ラインはこのように見えます。:
soffice -accept=socket,host=localhost,port=2002;urp
あるいは、パイプ・コネクションを用いて
soffice -accept=pipe,name=pipe_name;urp
OOoのための役に立つ、他のコマンド・ライン・オプションは、以下の通りです。:
-minimized -invisible -nologo -nolockcheck -nodefault
「UNOプロセス間接続」を参照してください。
OOo3.0では、fundamental.iniに、パスが含まれるiniファイルを提供する必要があります。defaultBootstrap_InitialComponentContext関数を使用するとき、iniファイルは、クライアント・プログラムと(拡張子なしで)同じ名前を持つ必要があります。例えば、プログラムは、client.exeの名前が付けられています。そして、また、client.iniが、同じフォルダの中にある必要があります。fundamental.iniへのパスは、ファイルURLである必要があります。それは、特殊文字をエンコードする必要があります。例えば、スペースは、%20として表現されています。例:
[Bootstrap]
URE_BOOTSTRAP=file:///d:/OpenOffice.org%203/program/fundamental.ini
もう一つ、開始する簡単な方法とOOoへの接続は、関数uno.util.Bootstrap.bootstrapを使用することです。この関数は、レジストリ(HKEY_CURRENT_USER\Software\OpenOffice.org\UNO\InstallPathまたはHKEY_LOCAL_MACHINE\Software\OpenOffice.org\UNO\InstallPath)または環境変数UNO_PATHを使用してOOoを検索します。この関数は、最初にHKEY_CURRENT_USERキーを使用します。そして、それが存在しない場合、HKEY_LOCAL_MACHINEキーを使用します。オフィスが開始しない場合、これらのキーを確認します。また、PATH環境変数に別のオフィスへのプログラム・パスが含まれていないことを確認してください。
//C# example. OOo is started automatically.
// C#の例。OOoは、自動的に開始されます。
XComponentContext xContext = uno.util.Bootstrap.bootstrap();
コンテクストを取得するこのメソッドは、iniファイルを全く必要としません。制限は、常にパイプ接続を使用することです。言い換えると、それは、ローカルOOoには適切ですが、別のマシンでは、適していません。
実行中のオフィスに依存しない、UNOアプリケーションを記述することができます。続いて、あなたは、通常は、登録されたサービスのデータベースを提供します。詳細については、手作業によるコンポーネントのインストールを確認して下さい。
CLI-UNO言語結合は、CLI言語で記述される、UNOコンポーネントをサポートしていません。その代わりに、それは、CLIクライアント・プログラムとオフィスの間の連絡役として機能します。クライアント・プログラムは、通常、オフィスからUNOオブジェクトを取得し、その上で操作を実行します。その結果、UNOインターフェイスの実装は、めったに、必要ありません。
UNOオブジェクトから通知を受け取るために、適切なインターフェイスを実装することが必要です。また、UNOメソッドへの引数としてオブジェクトを使用するために、インターフェイスを実装することができます。
インターフェイスは、1つ以上のインターフェイスから派生する、クラスを宣言することによって実装されます。そして、それは、interfaceメソッドの実装を提供します。これを、さまざまなCLI言語のそれぞれのドキュメントで、どのように、実行するかを取り扱います。
オーバーライド問題
原文「The Override Problem」
「オーバーライド問題」という用語は、発生する問題を説明します。基準となるオブジェクトの仮想関数に到達できないとき、なぜなら、インターフェイス・メソッドは、基底クラスの実装をオーバーライドします。例えば、すべてのCLIオブジェクトは、System.Objectから派生します。インターフェイスが、メソッドを持っている場合、System.Objectのメソッドの1つとして、同じシグネチャを持っています。そのため、インターフェイス・メソッドが、仮想である場合、System.Objectのそれぞれのメソッドには、到達できません。
using namespace System;
public __gc __interface XFoo
{
public:
virtual String* ToString();
};
public __gc class Foo : public XFoo
{
public:
virtual String* ToString()
{
return NULL;
}
};
例えば、次のインターフェイスXFooの宣言と、それを実装しているクラスについて考えてみてください。
int main(void)
{
Foo * f = new Foo();
Object * o = f;
f->ToString(); // calls Foo.ToString
o->ToString(); // calls Foo.ToString
return 0;
}
インスタンスのメソッドのToStringが、呼び出される場合、続いて、インターフェイス・メソッドの実装が、呼び出されます。例えば、
これは、意図されていないかもしれません。なぜなら、おそらく、インターフェイス・メソッドは、System.Objectの同名のものとは、別の意味を持っています。
ソリューションは、インターフェイス・メソッドを非仮想にすることなく、インターフェイス・メソッドが、System.Objectのメソッドを上書きするのを防ぎます。CLIは、ILコードのメソッド・ヘッダに添付される「newslot」フラグの改善策を提供します。CLI言語は、「newslot」でメソッドを表示するための、別の手段を備えているかもしれません。
次の例は、さまざまな言語で、Object.ToStringを呼び出すことができる、XFooを実装する方法を示しています。
//C++
//interface methods should be qualified with the interface they belong to
public __gc class A: public XFoo
{
public:
virtual String* XFoo::ToString()
{
Console::WriteLine("A::foo");
return NULL;
}
};
インターフェイス・メソッドは、それらが属しているインターフェイスで修飾する必要があります。
けれども、CLIメソッド・ヘッダには、最終的な属性が、含まれているため、XFoo::ToStringは、継承しているクラスで上書することができない仮想です。再度、XFooから派生し、実装を提供しますが、継承しているクラスの1つで、行うことができます。
C#では、さまざまな方法で実装を提供しています。:
// IL contains: newslot final virtual
// ILには、以下のものが含まれています。:newslot final virtual
public new string ToString()
{
}
新しいキーワードは、CLIメソッド・ヘッダに、newslot属性を挿入します。この実装は、継承しているクラスでは、上書きすることができません。
//IL contains: newslot virtual // ILには、以下のものが含まれています。:newslot virtual public new virtual string ToString() { }
このメソッドは、派生クラスで上書きすることができます。
// Using a qualified method name for the implementation. The virtual
//modifier is not allowed
// 実装のために、修飾付きのメソッド名を使用します。
// 仮想修飾子は、使用できません。
string XFoo.ToString()
{
return null;
}
この実装は、派生クラスでは、上書きすることができません。実装するクラスのインスタンスは、メソッドが、呼び出される前に、XFooにキャストする必要があります。
'VB .NET
Public Shadows Function ToString() As String Implements XFoo.ToString
Console.WriteLine("Foo.toString")
End Function
この実装は、派生クラスでは、上書きすることができません。
Public Overridable Shadows Function ToString() As String _
Implements XFoo.ToString
Console.WriteLine("Foo.toString")
End Function
このメソッドは、上書きできます。
重要なインターフェイスと実装(ヘルパー・クラス)
原文「Important Interfaces and Implementations (Helper Classes)」
UNOオブジェクトは、いくつかが、常に要件に依存している一連のUNOインターフェイスを実装しています。以下のインターフェイスは、オフィスのプログラムディレクトリ内のcli_types.dllというアセンブリに属しています。:
- com.sun.star.lang.XTypeProvider(すべてのUNOオブジェクトで推奨)
- com.sun.star.uno.XWeak(すべてのUNOオブジェクトで推奨)
- com.sun.star.lang.XComponent (オプション)
- com.sun.star.beans.XPropertySet(オプション、定義済みのサービスプロパティに関するサービス実装に必要)
少し簡単に、オブジェクト開発を作成するために、言語結合は、上記のインターフェイスのほとんどのためにヘルパー実装を提供しています。ヘルパー・クラスは、uno.util名前空間に属しており、cli_ure.dllと呼ばれるアセンブリに含まれています。C++やJavaのものと類似しているリスナー・コンテナを実装する見つからないヘルパーに注意して下さい。それが存在する主な理由は、イベント・リスナーの自動通知を確実に行うことです。(com.sun.star.lang.XComponent、com.sun.star.lang.XEventListenerを確認して下さい)。CLI言語は、特定の場合、不必要なヘルパー・クラスを作成するイベント(デリゲート)のために、簡単な仕組みを提供しています。なぜなら、イベント通知は、言語の機能を使って、簡単に実装されます。
uno.util.WeakBase
このクラスは、XTypeProviderとXWeakインターフェイスを実装しています。XWeakは、UNOの弱い参照の仕組みを実装するために用いられます。そして、System.WeakReferenceが、使われていないのは奇妙に思われるかもしれません。あなたは、あなたのUNOオブジェクトが、弱い参照をサポートしていない、他の言語環境内で保持されることを覚えておく必要があります。この方法では、弱い参照は、UNOの概念として実装されています。もちろん!すべてのコンポーネントやアプリケーションができるように、ヘルパーの実装が、System.WeakReferenceを使用している限り、UNOインタフェースへの呼び出しには渡されません。また、コンパイラは、適切に実装をコンパイルすることができません。
uno.util.WeakComponentBase
このクラスは、uno.util.WeakBaseから派生して、XComponentインターフェイスを実装します。コンポーネントが、特別なクリーンアップを実行する必要がある場合、基底クラスとして、このクラスを使用します。クラスは、オブジェクトの廃棄に呼び出される、2つの保護されたメンバー関数を持っています。:
- すべての登録されたイベント・リスナーに通知する前に、呼び出されます。
- すべての登録されたイベント・リスナーに通知する後に、呼び出されます。この方法では、リソースのクリーンアップを実行する必要があります。
uno.util.WeakComponentBaseから継承して、適切なメソッドを上書きします。