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 文で、
明示的に破棄できます。また、それが含まれているスコープが無くなる時に、
自動的(暗黙的)に破棄されます。