MikoScript3 言語仕様
外部アクセス
本言語では、以下の手法で、外部プログラムにアクセスできます。
本章では、これらの手法について説明します。
・アプリケーションの実行
・プロセスオブジェクト
・DLLオブジェクト
・DLLコールバック関数
・COM操作
■アプリケーションの実行
記法: ::ShellExec( file、param, show );
機能: アプリケーション(外部プログラム)を起動します。
引数: file は、起動するアプリケーションの実行ファイル名、または、
起動するアプリケーションに関連付けられたファイルの名称、または、
URL等を指定します。
param は、起動するアプリケーションに渡すパラメータ(文字列)を
指定します。この省略時には、パラメータは渡されません、
show は、ウィンドウの表示形態を、次の値で指定します。
0: 非表示
1: 最小化
2: 最大化
この引数の省略時には、通常表示になります。
返値: アプリケーションの起動に成功すれば 1、失敗すれば 0 を返します。
注意: 本関数では、標準入出力は扱いません。
アプリケーションを起動するだけで、その終了は待ちません。
用例: (1) Windows の「電卓」を起動
::ShellExec( "calc.exe" );
(2) file.txt というファイルを、拡張子 .txt の関連で開く
::ShellExec( "file.txt" );
(3) MikoScript のホームページをブラウザで表示する
::ShellExec( "http://www.eonet.ne.jp/~mw31/miko3/index.html" );
■プロセスオブジェクト
本スクリプトから、外部プログラムを起動して、その実行途中に、標準入出力を
介してやりとりするには、まず、そのプロセス管理オブジェクトを生成して、それを
通して、標準入出力を行ないます。
この手法を使えば、例えば、標準入力からコマンド文字列を受け取って、その
処理結果を標準出力へプリントするという動作を、繰り返して行なうコンソール
プログラムを、スクリプトから制御することができます。
プロセス管理オブジェクトの生成
記法: ::Process( cmd, show, stdin, stdout, stderr, cse );
引数: cmd: プロセス(外部プログラム)起動コマンド文字列
show: ウィンドウの表示形態
=0: 非表示, =1: 最小化, =2: 最大化
上記以外/省略/不正時、通常表示
stdin: 標準入力のバッファサイズ(※)
stdout: 標準出力のバッファサイズ(※)
stderr: 標準エラーのバッファサイズ(※)
< 0: 標準出力に混入
※ このサイズが 0 の時は、デフォールトサイズになります。
また、省略/不正時は、そのバッファは無しになります。
cse: 文字符号化方式の名称(省略時は、'CharEnc の設定を適用)
返値: その外部プログラムに対するプロセス管理オブジェクト
( エラー時は、null )
説明: 本関数は、外部プログラムの起動後、その実行終了を待たずに、即時に
復帰します。その後、そのプロセスが稼働中なのか、終了したのかは、
proc.GetExitCode()
で調べることができます。
補説: 標準入力の文字列は、引数 cse に指定された文字符号化方式から、
内部形式( UTF-16(LE) )に変換されます。
標準出力の文字列は、内部形式( UTF-16(LE) )から、引数 cse に
指定された文字符号化方式に変換されます。
補説: ここで生成したオブジェクトは、他のオブジェクトの場合と同様に、
delete proc;
で、明示的に破棄できます。また、それが含まれているスコープが
無くなる時に、自動的(暗黙的)に破棄されます。
プロセスの標準入力へ文字列を送出
記法: proc.PutStdin( ... )
引数: 送出する文字列を指定します。この引数は複数個あっても、構いませんが、
文字列データに限ります。
標準入力の終わりをプロセスに認知させるには、引数に 0 を指定します。
引数が、文字列でも、0 でもない場合は、無視されます。
返値: 送出した文字列のバイト数(正常時)
null(エラー時)
注意: プロセス管理オブジェクトが破棄される時、標準入力の終わりが
プロセスに認知されるので、必ずしも引数に 0 を指定して終わる
必要はありません。
プロセスの標準出力から文字列を取り込む
記法: proc.GetStdout()
返値: 標準出力から取り込んだ文字列(正常時)
0(パイプ内が空の時)
null(エラー時)
補注: 標準出力でやり取りできるのは、文字列データのみ
プロセスの標準エラーから文字列を取り込む
記法: proc.GetStderr();
返値: 標準エラーから取り込んだ文字列(正常時)
0(パイプ内が空の時)
null(エラー時)
補注: 標準エラーでやり取りできるのは、文字列データのみ
プロセスの終了コードを取得する
記法: proc.GetExitCode();
返値: 終了コード(正常時) or null(エラー時)
注意: 返値が 259 (=0x103) の時は、プロセスがまだ稼働中であることを示す
特別な値なので、これはプロセスの終了コードには使わないようにする
必要があります。
≪ 用例 ≫
プロセスオブジェクトを使って、外部プログラムと標準入出力でやりとりする
例を以下に示します。
外部プログラム例:
これは、標準入力から1行ずつ読み込んで、その先頭に // を付加して標準出力
する動作を、標準入力が無くなるまで繰り返すコンソールプログラムです。
#include <stdio.h>
#define MAX_LINE 1000 // 入力行の最大長
int main( int argc, char *argv[] )
{
char line[ 2 + MAX_LINE ];
line[0] = '/';
line[1] = '/';
while( fgets( line + 2, MAX_LINE, stdin ) != NULL )
{
fputs( line, stdout );
fflush( stdout );
}
return 1;
}
スクリプト例(1):
これは、上記の外部プログラム("AddCmt.exe" という名前にする)を起動して、
その標準入力へ、テスト用の文字列を1行送出しては、その応答を、標準出力から
取り出してプリントするという動作を繰り返します。
p = ::Process( "AddCmt.exe", 1, 0, 0, -1 );
if( p == null )
'Error!( "外部プログラム起動失敗!\n" );
Text = { "AAA\n", "BBB\n", "CCC\n" };
for( S := Text'first ; S'ref? ; S := Text'next )
{
switch( p.PutStdin( S ))
{
default: print " Stdin: " : S :-; break;
case null: print "標準入力への送出エラー!"; quit;
}
GET_STDOUT:
R = p.GetStdout();
switch( R )
{
default: print "Stdout: " : R :-; break; // 正常に読み出し
case 0: 'sleep( 100 ); goto GET_STDOUT; // まだ空
case null: print "標準出力から取込エラー!"; quit;
}
}
p.PutStdin( 0 ); // 標準入力の終わりを通知
'sleep( 500 );
print "ExitCode = " : p.GetExitCode();
return;
実行結果(1)
上例のスクリプトを実行すると、以下の通り、プリントされます。
Stdin: AAA
Stdout: //AAA
Stdin: BBB
Stdout: //BBB
Stdin: CCC
Stdout: //CCC
ExitCode = 1
スクリプト例(2):
これは、上記の外部プログラム("AddCmt.exe" という名前にした)を起動して、
ダイアログボックスから入力された文字列を、そのプロセスの標準入力へ送出して、
その応答を、標準出力から取り出してプリントするという動作を繰り返します。
この例は、前例と似ていますが、マルチスレッドになっているのが大きな違いです。
^Proc = ::Process( "AddCmt.exe", 1, 0, 0, -1 );
if( ^Proc == null )
'Error!( "外部プログラム起動失敗!\n" );
^IsEnd = #FALSE;
^GetStdoutThread'start(); // 標準出力を取り込むスレッドを起動
while( ! ^IsEnd )
{
S = ::Input( "標準入力に送出する文字列:" );
if( S == null ) // 入力キャンセル?
break;
S += "\n";
switch( ^Proc.PutStdin( S ))
{
default: print " Stdin: " : S :-; continue;
case null: print "標準入力送出エラー!"; quit;
}
}
^IsEnd = #TRUE;
^Proc.PutStdin( 0 ); // 標準入力の終わりを通知
'sleep( 500 );
print "ExitCode = " : ^Proc.GetExitCode();
return;
function ^GetStdoutThread() // 標準出力を取り込むスレッド
{
while( ! ^IsEnd )
{
R = ^Proc.GetStdout();
switch( R )
{
default: print "Stdout: " : R :-; continue; // 正常に読み出し
case 0: 'sleep( 100 ); continue; // まだ空
case null: print "標準出力取込エラー!"; quit;
}
}
}
実行結果(2)
上例のスクリプトを実行すると、文字列入力ボックスが表示されます。ここで、
任意の文字列を入力すると、その先頭に // が付加された文字列が、-Script-
ウィンドウにプリントされます。この動作は、入力ボックスのキャンセルを押す
まで、繰り返されます。
■DLLオブジェクト
本スクリプトから、DLL( Dynamic Link Library )にアクセスするには、
次のようにします。
(1)DLLクラスのインスタンスを生成
(2)そのインスタンスを使って、DLLエントリーを取得
(3)そのDLLエントリーで、DLL関数をコール、または、
DLLデータを読み書き
(4)最後にそのインスタンスを破棄
以下に、この各詳細について説明します。
DLLクラスのインスタンスの生成
記法: ::DLL.Link( file, flag, cse );
引数: file には、そのDLLのライブラリファイル名を指定します。
このファイル名に、拡張子がなければ、".DLL" の拡張子が付加されます。
flag は、file が相対パスの場合に、その検索パスを、次のように規定します。
( file が絶対パスの場合、そこのファイル以外は検索されません。)
flag が省略の場合:
所定のディレクトリー群から検索されます。この詳細に関しては、
Windows の LoadLibrary() 関数と同じなので、その説明をご覧ください。
flag が "sys" の場合:
Windows のシステムディレクトリーだけから検索されます。
cse には、文字符号化方式の名称を指定します。
この省略時は、'CharEnc の設定が適用されます。
この指定は、DLL関数の呼び出しの引数が文字列の時にのみ影響します。
返値: DLLクラスのインスタンスを返します。
但し、エラー時は、null になります。
注意: 指定のDLLが既にロード済みの場合、正常終了して、そのDLLの
リンクカウントを1つアップします。
用例:
User32 = ::DLL.Link( "USER32", "sys" );
DLLエントリーの取得
記法: dll .GetEntry( name, type, cse, flag )
(ここで、dll はDLLクラスのインスタンス)
引数: name は、そのDLL内にあるエントリー名(関数名、または、データ名)を
指定します。
type は、エントリーが関数の場合、まず、DLL関数の引数の渡し方を規定する
"__stdcall" または "__cdecl"
を指定します。このどちらの指定も無ければ、前者として扱います。
また、type は、DLL関数の返値が、倍精度実数の場合には、
"double"
を指定します。この指定が無ければ、返値は、ULONG または void です。
上記の2種類を同時に指定する場合は、"double __cdecl" のように、
返値の型を最初にして、両者の間に半角空白を入れます。
type は、エントリーがデータの場合、
"DATA"
とだけ指定します。
type が省略された場合、"__stdcall" で、返値が ULONG または void の
指定として扱います。ちなみに、この場合が、一般的には多いようです。
cse は、文字符号化方式の名称を指定します。
この省略時は、そのDLLクラスのインスタンスでの設定が適用されます。
この指定は、DLL関数の呼び出しの引数が文字列の時にのみ影響します。
flag は、本関数で取得されるアドレスが、直接か間接かを、0 か 1 で指定します。
直接の場合、そのアドレス自身がエントリーアドレスになります。
間接の場合、そのアドレスは、エントリーアドレスのアドレスになります。
この引数の省略時は、直接アドレスとして解釈されます。
返値: 正常終了時には、DLL関数、または、DLLデータを特定する値が返ります。
エラー時は、null が返ります。
用例:
CreateWindowEx = User32.GetEntry( "CreateWindowExW" );
DrawText = User32.GetEntry( "DrawTextW" );
DLLエントリーの設定
記法: dll .SetEntry( fxp, name, type, cse, flag )
(ここで、dll はDLLクラスのインスタンス)
引数: fxp は、エントリーアドレスを指定します。
name は、エントリー名(関数名、または、データ名)を指定します。
type は、エントリーが関数の場合、まず、DLL関数の引数の渡し方を規定する
"__stdcall" または "__cdecl"
を指定します。このどちらの指定も無ければ、前者として扱います。
また、type は、DLL関数の返値が、倍精度実数の場合には、
"double"
を指定します。この指定が無ければ、返値は、ULONG または void です。
上記の2種類を同時に指定する場合は、"double __cdecl" のように、
返値の型を最初にして、両者の間に半角空白を入れます。
type は、エントリーがデータの場合、
"DATA"
とだけ指定します。
type が省略された場合、"__stdcall" で、返値が ULONG または void の
指定として扱います。
cse は、文字符号化方式の名称を指定します。
この省略時は、そのDLLクラスのインスタンスでの設定が適用されます。
この指定は、DLL関数の呼び出しの引数が文字列の時にのみ影響します。
flag は、本関数で設定するアドレスが、直接か間接かを、0 か 1 で指定します。
直接の場合、そのアドレス自身がエントリーアドレスになります。
間接の場合、そのアドレスは、エントリーアドレスのアドレスになります。
この引数の省略時は、直接アドレスとして解釈されます。
返値: 正常終了時には、DLL関数、または、DLLデータを特定する値が返ります。
エラー時は、null が返ります。
用例:
glMultTransposeMatrixd = ^GL.SetEntry(
^wglGetProcAddress( "glMultTransposeMatrixd" ),
"glMultTransposeMatrixd" );
DLL関数の呼び出し
DLL関数の呼び出しは、GetEntry() で取得したDLL関数を使います。その
書式は、基本的に、通常の関数の場合とほとんど同じです。例えば、
UpdateWindow( hWnd );
のようになります。ここで、UpdateWindow は、次のようにして取得したDLL関数
です。
User32 = ::DLL.Link( "USER32", "sys" );
UpdateWindow = User32.GetEntry( "UpdateWindow" );
DLL関数の呼び出しでは、その関数の定義通りの型と個数の引数を渡す必要が
あります。型には、いろいろな種類ありますが、大抵、その基本的(根本的)な
データ型は、次のどれかになります。
・整数値(4-byte)
・実数値(8-byte)
・アドレス(4-byte)
このうち、整数値と実数値は、本言語の基本データ型と同じなので、その型の変数や
定数を、そのまま引数に指定できます。なお、どうしても、単精度実数値(4-bye)を
引数にする必要がある場合には、'sfv というリレー型関数を使います。
DLL関数の引数に、次のデータ型の変数か定数を指定した場合、そのアドレスが
渡されます。
・文字列
・コールバック関数
・バッファ
・純粋配列
このうち、バッファには、ほぼ任意の構造体のデータを格納できます。
明示的にアドレスを取得する必要がある時には、'addr というリレー型関数を使用します。
例えば、Var という変数のアドレスを取得する場合は、
Var'addr
とします。
DLL関数の引数が文字列の場合、その文字列は、そのDLL関数に指定されている
符号化方式( .GetEntry の cse 引数参照 )の文字コードに変換されてから渡されます。
DLL関数の引数は、整数やアドレスの場合、最大 20 個まで指定できます。一方、実数
の場合には、整数の2倍の個数に相当します。つまり、例えば、引数がすべて実数の場合、
最大 10 個までということになります。
DLL関数の呼び出しで、引数の不一致、つまり、引数の型や個数が、その関数の定義と
合っていない場合には、最悪、暴走することがあります。そこまで行かなくても、内部的
に状態がおかしくなってしまうかもしれません。しかし、単にエラーになるだけの場合も
多いようです。
本言語処理系では、このような引数不一致のDLL関数の呼び出しの異常事態が、致命的
でなければ、対処できるようになっています。その際、例外を発生させます。このエラー
ワープ先は、OnError になります。なお、このエラー代替はありません。この例外発生時
に、エラーワープの設定がなければ、現スレッドの実行は停止します。
DLL関数の返値として、受け取れるのは、
・整数値(4-byte)
・実数値(8-byte)
の2種類だけです。ちなみに、アドレス、または、単精度の実数値が返される場合は、
整数値として受け取り、それ相応の処理を行なう必要があります。その際、例えば、
'pv, 'ps, 'sfv などのリレー型関数を使います。
DLLインスタンスの破棄
DLLクラスのインスタンスは、他のオブジェクトの場合と同様に、delete 文で、
明示的に破棄できます。また、それが含まれているスコープが無くなる時に、自動的
(暗黙的)に破棄されます。
DLLクラスのインスタンスが破棄されると、そのDLLのリンクカウントが1つ
ダウンします。その結果、カウント値が 0 になると、そのDLL用に使われていた
メモリーが開放されます。カウント値が 0 にならなければ、そのメモリーは残存し
ます。
DLLのモジュールハンドルの取得
記法: dll .GetHandle()
(ここで、dll はDLLクラスのインスタンス)
返値: 正常終了時には、そのDLLのモジュールハンドルが返ります。
エラー時は、null が返ります。
用例:
hDll = dll .GetHandle();
■DLLコールバック関数
DLL関数の引数に、本言語の関数を、コールバック関数として指定する場合、
その関数を、事前に、コールバック関数として登録しておく必要があります。
ここでは、その関連について説明します。
コールバック関数の登録
記法: ::DLL.SetCallback( func )
引数: func は、コールバック関数として登録する関数名を指定します。
但し、func には制約条件があります(下記「注意」参照)
返値: 登録成功時は、登録番号が返ります。この値は、0 以上の整数値です。
登録失敗時は、-1 が返ります。
補説: 登録可能なのは、同じ引数の数の関数では、最大4関数までです。
つまり、引数の数が、0個、1個、2個、・・・ の関数は、それぞれ、
最大4関数まで登録可能です。
注意: コールバック関数として登録する関数 func の制約条件:
・引数の数が、0〜8 個まで
・引数または返値のデータ長は、4-byte のみ(つまり実数は不可)
用例:
function WndProc( hWnd, uMsg, wParam, lParam ) { ・・・ }
・・・・・
::DLL.SetCallback( WndProc );
コールバック関数の登録抹消
記法: ::DLL.ResetCallback( func )
引数: func は、コールバック関数の登録を抹消する関数名を指定します。
返値: 成功時は、前登録番号( 0 以上の整数値)が返ります。
失敗時は、-1 が返ります。
補説: コールバック関数の登録可能数には、制限があるため(上記参照)、
もはや使わない関数の登録を抹消して、その空き分を、他の関数の
登録に使うことができるようになっています。
用例:
::DLL.ResetCallback( WndProc )
≪ 用例 ≫
以下に、C言語で書いたDLLのプログラム例と、そのDLLを使うスクリプトの例を
示します。
DLLプログラム例:
このDLLのプログラムには、3つの関数と1つのデータがあります。これらの関数
では、整数、実数、文字列、コールバック関数をやりとりします。
#include <windows.h>
#define SMPL_API __declspec(dllexport)
typedef LONG (CALLBACK *SMPL_FXP)( char*, char*, LONG );
BOOL WINAPI
DllMain( HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved )
{
return TRUE;
}
SMPL_API LONG __stdcall AddLong( LONG i, LONG j )
{
return i + j;
}
SMPL_API double __cdecl SubDouble( double x, double y )
{
return x - y;
}
SMPL_API LONG __stdcall PassString( char* cp, SMPL_FXP fxp )
{
return (*fxp)( cp, "ABC", 123 );
}
SMPL_API char DllSampleText[] = "This DLL サンプル文字列.";
スクリプト例:
このスクリプトは、上記のDLL("SampleDll.dll" という名前にする)を動的に
リンクして、その中の関数とデータにアクセスして、その結果をプリントします。
dll = ::DLL.Link( "SampleDll.dll" );
if( dll == null )
'Error!( "サンプルDLLが見つかりません!\n" );
AddLong = dll.GetEntry( "AddLong" );
SubDouble = dll.GetEntry( "SubDouble", "double __cdecl" );
PassString = dll.GetEntry( "PassString" );
DllSampleText = dll.GetEntry( "DllSampleText", "DATA" );
::DLL.SetCallback( PrintArgs );
print "AddLong( 1, 2 ) = " : AddLong( 1, 2 );
print "SubDouble( 3.14, -2.1 ) = " : SubDouble( 3.14, -2.1 );
print "PassString( \"xyz\", PrintArgs ) = " :
PassString( "xyz", PrintArgs );
print "DllSampleText = " : DllSampleText'addr'ps;
function PrintArgs( a, b, c )
{ print a'ps, b'ps, c; return 99; }
実行結果:
上例のスクリプトを実行すると、以下の通り、プリントされます。
AddLong( 1, 2 ) = 3
SubDouble( 3.14, -2.1 ) = 5.24
xyz, ABC, 123
PassString( "xyz", PrintArgs ) = 99
DllSampleText = This DLL サンプル文字列.
補足説明:
上記のスクリプト例では、DLL関連の情報( dll, AddLong など)は、暗黙の
メイン関数のローカルスコープ内でしか参照されないので、デフォールトスコープ
のままでも構いませんが、プログラムが大きくなって、それらを、各種の関数から
参照する場合には、モジュールローカルスコープ(または、グローバルスコープ)
内におく必要があります。その場合、上記のプログラムは、例えば、以下のように
なります。
^SampleDll = ::DLL.Link( "SampleDll.dll" );
if( ^SampleDll == null )
'Error!( "サンプルDLLが見つかりません!\n" );
^AddLong = ^SampleDll.GetEntry( "AddLong" );
^SubDouble = ^SampleDll.GetEntry( "SubDouble", "double __cdecl" );
・・・・・
■COM操作
本スクリプトから、COM( Component Object Model )を操作するには、まず、
COMオブジェクトを生成して、そのインターフェースを通して、そのメソッドや
プロパティにアクセスします。ここでは、この手法を説明します。
COMオブジェクトの生成
記法: obj = ::COM.Object( ProgID );
引数: ProgID は、そのCOMを特定する文字列です。
返値: obj は、生成されたCOMオブジェクトです。
なお、エラーの時は、null になります。
用例: IE = ::COM.Object( "InternetExplorer.Application" );
XL = ::COM.Object( "Excel.Application" );
補注: 厳密には、返値の obj は、生成されたCOMオブジェクトの実体ではなく、
それへの特別なインターフェースを規定する値ですが、簡単のために、
これを、COMオブジェクトと呼んでいます。
補説: 本スクリプトは、公開されているCOMのインターフェイスのうち、
IDispatch というインタフェースを介して、COMを操作します。
COMオブジェクトのメソッド呼び出し
記法: *obj->メソッド名( 引数 ... )
説明: COMオブジェクトのメソッドの呼び出し(メンバー関数のコール)には、
このような表記を使います。ここで、obj は、COMオブジェクトです。
なお、引数が無い時は、下記の表記になります。
*obj->メソッド名()
返値: 各メソッドに依存します。これは、勿論、数値や文字列の場合もありますが、
obj 内の別のCOMオブジェクト(へのインターフェイス)の場合もあります。
どの場合でも、それを直接使ったり、変数に格納したりできます。
補説: obj としては、次のものが使えます。
・::COM.Object() が生成したもの
・COMオブジェクトのメソッド呼び出しの返値
・COMオブジェクトのプロパティを取得したもの
用例:
*IE->Navigate( "http://www.venus.dti.ne.jp/mw31/apsaly/index.html" );
COMオブジェクトのプロパティ設定
記法: *obj->プロパティ名 =: 式
説明: ここで、obj は、上記「補説」のCOMオブジェクトです。
この実行によって、そのCOMオブジェクトのプロパティに、「式」の評価値が
設定されます。
用例:
*XL->Visible =: 1;
item = *XL->ActiveSheet->Cells->Item( 3, 1 );
*item->Value =: "いろは";
COMオブジェクトのプロパティ取得
記法: *obj->プロパティ名
説明: ここで、obj は、上記の通りです。
取得される値は、各プロパティに依存します。これは、勿論、数値や文字列の
場合もありますが、obj 内の別のCOMオブジェクトの場合もあります。
どの場合でも、それを直接使ったり、変数に格納したりできます。
用例:
while( *IE->Busy )
'sleep( 100 );
item = *XL->ActiveSheet->Cells->Item( 3, 1 );
print *item->Value;
COMオブジェクトの連続表記
COMオブジェクトのメソッド呼び出しの返値や、取得したプロパティが、別のCOM
オブジェクトの場合、それは、勿論、変数に格納できますが、直接連続的に使うことも
できます。その場合、例えば、次のような表記になります。
XL = ::COM.Object( "Excel.Application" );
*XL->Visible =: 1;
*XL->WorkBooks->Add();
*XL->ActiveSheet->Cells->Item( 1, 1 )->Value =: "Hello";
COMオブジェクト/メンバーの特殊表記
COMオブジェクトと、COMのメンバー(メソッドとプロパティ)は、一般に、
「式」でも指定できます。その場合、次の記法を使います。
{ 式 }
この「式」としては、変数、定数、関数コール、あるいは、それらの組み合わせの
演算式など、いろいろな形態がありますが、その式の評価値は、次のようになる
必要があります。
・COMオブジェクトの場合は、そのCOMオブジェクトそのもの
・COMのメンバーの場合は、そのメンバーのID値(整数値)、または、
そのメンバーの名前(文字列)
以下に、この特殊表記を使った例を示します。
GetXL = function() { return ^XL; };
Visible = 558;
Add = "Add";
Active = "Active";
Sheet = "Sheet";
X = 1;
Y = 2.0;
^XL = ::COM.Object( "Excel.Application" );
*^XL->{ Visible } =: 1;
*{ GetXL() }->WorkBooks->{ Add }();
*{ ^XL }->{ Active + Sheet }->Cells->Item( X, Y - 1 )->Value =: "Hello";
*{ GetXL() }->ActiveSheet->Cells->Item( 2.0, 1.0 )->Value =: "Excel";
*XL->ActiveSheet->{ "Cells" }->{ "Item" }( 3, 1 )->Value =: "Epsaly";
print *XL->ActiveSheet->Cells->{ "Item" }( 3, 1 )->Value;
このような特殊表記は、普通ではあまり使う必要がないかもしれませんが、部分的には、
これがないとプログラムが書けない場合や、これを使った方が効率的な場合があります。
デフォールトスコープ以外のスコープに格納されたCOMオブジェクトを使う場合、
* の次にスコープ規定演算子が来るので、若干奇異な感じもしますが、これは特殊表記
というわけではありません。例えば、モジュールローカルスコープの場合、次のような
表記になります。
^IE = ::COM.Object( "InternetExplorer.Application" );
*^IE->Visible =: 1;
*^IE->Navigate( "http://www.venus.dti.ne.jp/mw31/apsaly/index.html" );
COMオブジェクトの破棄
COMオブジェクトは、他のオブジェクトの場合と同様に、delete 文で、
明示的に破棄できます。また、それが含まれているスコープが無くなる時に、
自動的(暗黙的)に破棄されます。