このページではJavaScriptを使用しています。

9-11. OLEオートメーション

9-11-1.概要

AZ-Prologは、WindowsのOLEオートメーション機能をサポートしています。
これを利用する事で、AZ-Prolog自体を1つのオブジェクトとしてパッケージ化し、他のWindowsプログラムと連動させる事が出来、開発の効率化を計る事が出来ます。
例えばWindowsのGUI部分は、他のGUI向きの開発言語でコーディングし、複雑なロジックを必要とするプログラム本体は、それを容易に記述出来るAZ-Prologでコーディングし、これらの連携によるシステムを実現させるといったものです。


OLEオートメーション機能の利用例


これにより、各々の言語等のアプリケーションの特徴を最大限に利用する事でシステムの設計・開発が容易になり、またこの柔軟性により、Windows上でのプログラム開発の可能性を拡大させる事が出来ます。
具体的には、AZ-Prologパッケージには、OLEオートメーション機能をサポートした言語によるサンプルプログラムが付属していますので、それを実行してみたりソースファイルに目を通すと、より直感的に理解出来るかと思われますので、そちらも参照してみてください。

この章では、AZ-PrologのOLEオートメーション機能のサポート形式の説明、そして実際のOLEオートメーションサーバの作成例を解説します。
サポート形式の説明は、多少堅苦しく記述されていますが、作成例を読みながらもう一度参照し直すと理解しやすいかと思います。

9-11-2.OLEオートメーション機能のサポート形式

(1)automation/3述語

OLEオートメーションを使用する場合は、まずプログラムのクラス名、及びCLSIDを決める必要があります。
クラス名はアプリケーションをクライアントから呼び出すときに使用する名前、CLSIDはウインドウズオブジェクト(複合ドキュメントのオブジェクト、オートメーションオブジェクト等)をWindowsのレジストリデータベースに登録する時に指定する識別番号です。
CLSIDはアプリケーション毎に異なる値を持つ必要があり、逆に同一アプリケーションのCLSIDは(実行するコンピュータが異なっても、また、バージョンが異なっても同一アプリケーションといえる限りは)同じものである必要があります。
この登録、及びOLEオートメーションサーバの実行を行う為の述語「automation/3」が用意されています。

automation(CLSID, ProgID, EXEname)

実際の動作はコマンドライン引数によって以下のようになります。

第一引数が「/Automation」の場合
サーバとしての動作を行います。通常はクライアントのオブジェクト生成要求に従ってOLEによってプログラムが起動された場合がこれにあたります。
クライアントがオブジェクトを破棄することによって述語は成功終了します。
第一引数が「/Setup」またはここで述べる他のいずれにも該当しない場合
プログラムの登録を行います。
クライアントが登録名ProgIDのオブジェクトの生成を要求すると、次のコマンドラインでサーバが起動されるようになります。

“<EXEname> /Automation -Embedded <Args>”

ここでは述語の引数、 は登録時のコマンドライン引数から第一引数の「/Setup」を除いたものです。
登録終了時、第一引数が'/Setup'でない場合、登録完了を知らせるメッセージが表示されます。
第一引数が「/Uninstall」または「/SilentUninstall」の場合
登録の削除を行います。
削除終了時、第一引数が「/Uninstal」の場合、削除完了を知らせるメッセージが表示されます。

②または③の場合、「/Setup」等に続いて「/Private」または「/Public」を指定することでプログラムの登録が現在ログインしているユーザーだけに有効なものかシステム全体に有効なものにするかを指定できます。
この指定を省略するとシステム全体に有効なものになります。
システム全体に有効な登録はUACによって制限されるので、一時的にUACを無効にするなどの対策が必要になります。
従って開発中のものを登録する場合等は「/Private」で登録するのがよいでしょう。


CLSID プログラム固有のインターフェースIDの文字列表現
ProgID トップレベルオブジェクト(次項参照)の公開名(クラス名)
EXEname 実行ファイル名及びサーバ起動時「/Automation -Embedded」の前に必要なコマンドライン引数
(2)外部インターフェース
クライアントが最初に取得するオブジェクトをトップレベルオブジェクトと呼びます。
これはインタプリタのトップレベルに相当する物です。トップレベルオブジェクトは以下のメソッドを持ちます。

メソッドCallFormula(Formula,Term)

式の実行を開始します。
引数Formulaは実行すべき式、TermはFormulaの実行が成功した時結果表示オブジェクトを通して取得すべき項です。
戻り値はオブジェクトです。
CallFormulaの戻り値として得られるオブジェクトを結果表示オブジェクトと呼びます。
結果表示オブジェクトは以下のプロパティ、及びメソッドを持ちます。


プロパティ Status

Formula実行の現在の状況を示します。


"Succ" 成功している。
"Fail" 失敗している。
"Error" エラーが起こった。

プロパティ Value (デフォルトプロパティ)

Status="Succ"の時、Termの現在の値を示します。
Status="Error"の時、エラー番号を示します。


メソッドGetAlternative

結果表示をフェイルさせ、別解を探索します。

(3)例外

Prolog内部で起こったエラーは常に結果表示オブジェクトのStatusプロパティを通して報告されます。以下の状況ではOLEのエラーとなり例外コードが返されます。


例外コード1001 結果表示オブジェクトの参照が解除されないままトップレベルオブジェクトが使用された。
例外コード1002 Status="Fail"の時にValueプロパティを取得しようとした。
例外コード1003 Status="Succ"以外の時にGetAlternativeメソッドを実行しようとした。

9-11-3.OLEオートメーションサーバの作成

(1)はじめに

ここではクライアントプログラムの例はVBのコーディングで示すことにします。

(2)プログラム本体の記述

プログラム本体の記述に関しては特別な事は何もありません。普通に述語を作成してコンソール上でデバッグします。

(3)オートメーションサーバとして動かす
A AZSERV.EXEに読み込ませて使う。
B インタプリタを使用する。
C コンパイルする。

の3種類の方法が考えられます。
以下、それぞれの方法について説明します。

A.AZSERV.EXEに読み込ませる

この場合にはPrologでのプログラムは本体だけで他には必要ありません。
呼び出し側のプログラムで以下のようにして使用します。

<VBでのコーディング例 (VB2010の場合)>

Public Class Form1
    Dim objToplevel As Object
    Dim objQuery As Object

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        objToplevel = CreateObject("Prolog.Toplevel")
        objQuery = objToplevel.CallFormula("consult('C:¥programs¥myapp.pl') ", "_")
        System.Runtime.InteropServices.Marshal.ReleaseComObject(objQuery)
    End Sub
End Class

このプロシージャを実行した後はToplevelオブジェクトを使用して述語呼び出しを行うことができます。


B.インタプリタを使用する

この場合はまずプログラムのクラス名及びCLSIDを決める必要があります。
クラス名はアプリケーションをクライアントから呼び出すときに使用する名前、CLSIDはウインドウズオブジェクト(複合ドキュメントのオブジェクト、オートメーションオブジェクト等)をWindowsのレジストリデータベースに登録する時に指定する識別番号です。

CLSIDはアプリケーション毎に異なる値を持つ必要があり、逆に同一アプリケーションのCLSIDは(実行するコンピュータが異なっても、また、バージョンが異なっても同一アプリケーションといえる限りは)同じものである必要があります。
新規アプリケーションのCLSIDを生成するには通常はWindows SDKやVisual C++などの開発ツールに付属するGUIDGEN.EXEというプログラムを使用します。
GUIDGENの使用方法はそちらのマニュアルを参照して下さい。
NEWGUID.EXEはコマンドラインから実行すると新しいCLSIDを生成して標準出力に書き出します。
リダイレクトしてファイルに埋めこむ等の方法で使用して下さい。
ここでは仮にプログラム本体が「C:¥programs¥myapp.pl」にあるとし、クラス名を「MyApp.Toplevel」、CLSIDを「{12B061D0-DEAC-11CE-A641-0000F4CA088B}」として説明します。(このCLSIDはこの原稿を書いている時にNEWGUID.EXEを使用して生成した値です。)
プログラム初期化コマンドファイルとして「C:¥programs¥myapp.ini」を作成し、以下の内容を書き込みます。(もちろんmyapp.plの末尾に追加しても構わないですが)

myapp.iniの内容

:-consult('C:¥programs¥myapp.pl').
:-automation(
        '{12B061D0-DEAC-11CE-A641-0000F4CA088B}',
        'MyApp.Toplevel',
        'C:¥azprolog¥bin¥prolog.exe -s C:¥programs¥myapp.ini -nologo -p').
:-halt.

Prologの起動オプション-nologoはインタプリタ起動時のメッセージ表示を抑止します。
Prolog(及びコンパイルオプション「/i」あるいは「/curses」をつけてコンパイルしたスタンドアロンPrologアプリケーション)は最初にコンソール入出力を行ったときはじめてコンソールウィンドウを表示するようになっています。
通常は起動メッセージの表示のために起動と同時にコンソールウィンドウが表示されますが、-nologoオプションをつけて起動すればプログラムが入出力を行わない限り(あるいはトップレベルのプロンプトを表示するまで)コンソールウィンドウは表示されません。
プログラムに絶対パスを埋めこむことが不都合なら起動パラメータからディレクトリ名を得る等の方法が考えられます。これはAZSERV.EXEが行っている方法なのでAZSERV.EXEのソース(AZ-PrologインストールディレクトリのSYSTEMサブディレクトリにあります。)を参照してください。
他にもインストール毎に異なる情報をサーバプログラムに伝えるために起動パラメータを使用できます。
初期化コマンドファイルを作成したらプログラムをウィンドウズのレジストリに登録します。
これは作成したプログラムを単に実行することで行われます。

C:¥programs>prolog -s myapp.ini -nologo

これで登録が完了した旨のメッセージボックスが表示され、MyApp.Toplevelという名前でプログラムが呼び出せるようになります。
セットアッププログラムから実行する場合などメッセージボックスが邪魔な場合はプログラムパラメータのはじめに「/Setup」を指定します。

C:¥programs>prolog -s myapp.ini -nologo -p /Setup /Private

こうすると登録は同様に行われますが、メッセージは何も表示せず登録完了後直ちに終了します。
また、「/Private」を指定しているので登録を実行したユーザーのみに有効な登録になります。
クライアントアプリケーションはクラス名MyApp.Toplevelのオブジェクトを取得するだけでプログラムを呼び出すことができます。


<VBでのコーディング例(VB2010の場合)>

Public Class Form1
    Dim objToplevel As Object

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        objToplevel = CreateObject("MyApp.Toplevel")
    End Sub
End Class

あとはAZSERV.EXEを使用する場合と同様です。


C.コンパイルする

コンパイルする場合もインタプリタで実行する場合とほぼ同じ手順になります。
以下の内容をプログラムに挿入するか一緒にコンパイルしてリンクします。
(もちろんクライアントから呼び出される述語はpublicにします。)

top_level:-
     automation(
           '{12B061D0-DEAC-11CE-A641-0000F4CA088B}',
           'MyApp.Toplevel',
           'C:¥azprolog¥bin¥myapp.exe -p').

プログラムをコンパイルしmyapp.exeを作成し、それを単に実行して登録します。クライアント側はインタプリタで実行するばあいと全く同じプログラムで使用できます。

9-11-4.OLEオートメーション関連述語一覧

 ole_initialize/0  OLEオートメーションシステムの初期化
 ole_uninitialize/0  OLEオートメーションシステムの終了処理
 ole_create_object/2  オートメーションオブジェクトの取得
 ole_release_object/1 オートメーションオブジェクトの使用終了
 ole_call_method/5  メソッドの呼び出し
 ole_get_property/5  オートメーションオブジェクトのプロパティの値を取得
 ole_put_property/4  オートメーションオブジェクトのプロパティの値を設定