MikoScript 言語仕様

 外部アクセス

本言語では、以下の手法で、外部プログラムにアクセスできます。
本章では、これらの手法について説明します。
    ・簡易実行プロセスオブジェクトDLLオブジェクトDLLコールバック関数COM操作

■簡易実行
記法: ::Execute( cmd, stdin, stdout, stderr, sw )
機能: 外部プログラムを起動します。
引数: cmd は、実行するコマンド文字列を指定します。
       なお、コマンドの実行ではなく、ファイルの拡張子やURL等の関連で
       開くこともできます。その場合、この文字列の先頭に * を付けます。
       ( 下記用例 (4),(5) 参照 )
    stdin は、外部プログラムの標準入力となる文字列を指定します。
       標準入力がなければ、省略します。
    stdout は、外部プログラムの標準出力の文字列を格納する箱を指定します。
       この箱は、本関数が生成するわけではないので、事前に生成しておく
       必要があります。標準出力を取得しない場合、この引数は省略します。
    stderr は、外部プログラムの標準エラーの文字列を格納する箱を指定します。
       この箱は、本関数が生成するわけではないので、事前に生成しておく
       必要があります。標準エラーを取得しない場合、この引数は省略します。
    sw は、ウィンドウの表示形態を、次の値で指定します。
        =0:非表示, =1:最小化, =2:最大化
       この引数が、省略/不正/上記以外の値の時は、通常表示になります。
説明: 引数が cmd だけの場合、
      外部プログラムを起動するだけで、その終了は待ちません。
    引数の個数が2以上の場合、
      外部プログラムを起動してから、その終了まで待ちます。
      標準入出力なしで、外部プログラムの実行終了を待つ場合、
      第2引数等を null にしておきます。
返値: 外部プログラムの起動に成功した時、
      その終了を待っていた場合、その外部プログラムの終了コードを返します。
      待たなかった場合、0 を返します。
    外部プログラムの起動に失敗した時、
      null を返します。
補説: 標準入出力は、通常、コンソールアプリケーションの場合に指定します。
    GUIアプリケーションの場合、標準入出力が無効な場合が多いので、
    標準入出力を使う時は充分に確認しておく必要があります。
用例: (1) Windows の「電卓」を起動
            ::Execute( "calc.exe" );
    (2) カレントパス内のファイル一覧の取得      Windows2000/XP の場合:
            ::Execute( "cmd.exe /c dir", , stdout'new! );
     Windows98SE/ME の場合:
            ::Execute( "command.com /c dir", , stdout'new! );
    (3) 適当なテキストを標準入力として sort を起動 →         その標準出力を取得してプリント
            stdin = "CCCCCC\nAAAAAA\nBBBBBB\n";
            ::Execute( "sort", stdin, stdout'new! );
            print stdout;
    (4) file.txt というファイルを、拡張子 .txt の関連で開く
            ::Execute( "*file.txt" );
    (5) MikoScript のホームページをブラウザで表示する
            ::Execute( "*http://www.venus.dti.ne.jp/mw31/miko/index.html" );
■プロセスオブジェクト  本スクリプトから、外部プログラムを起動して、その実行途中に、標準入出力を 介してやりとりするには、まず、そのプロセス管理オブジェクトを生成して、それを 通して、標準入出力を行ないます。  この手法を使えば、例えば、標準入力からコマンド文字列を受け取って、その 処理結果を標準出力へプリントするという動作を、繰り返して行なうコンソール プログラムを、スクリプトから制御することができます。 プロセス管理オブジェクトの生成 記法: proc = ::Process( cmd, show, stdin, stdout, stderr ); 引数: cmd:   プロセス(外部プログラム)起動コマンド文字列     show:  ウィンドウの表示形態           =0: 非表示, =1: 最小化, =2: 最大化           上記以外/省略/不正時、通常表示     stdin:  標準入力のバッファサイズ(※)     stdout: 標準出力のバッファサイズ(※)     stderr: 標準エラーのバッファサイズ(※)           < 0: 標準出力に混入      ※ このサイズが 0 の時は、デフォールトサイズになります。        また、省略/不正時は、そのバッファは無しになります。 返値: proc: その外部プログラムに対するプロセス管理オブジェクト         エラー時は、null になる 説明: 本関数は、外部プログラムの起動後、その実行終了を待たずに、即時に     復帰します。その後、そのプロセスが稼働中なのか、終了したのかは、       proc.GetExitCode()     で調べることができます。 補説: ここで生成したオブジェクトは、他のオブジェクトの場合と同様に、       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 = ::DLL.Link( file, s );
引数: file には、そのDLLのライブラリファイル名を指定します。
    s は、省略、または、"sys" を指定します。
    file のファイル名に拡張子がなければ、.DLL が付加されます。
    file のファイル名にパスを指定した場合:
      そのファイルは、そのパス内だけから検索されます。
    file がファイル名だけの場合:
     s が省略された時、
       所定のディレクトリ群から検索されます。この詳細に
       関しては、Windows のLoadLibrary() 関数と同じなので、
       その説明をご覧ください。
     s に "sys" が指定された時、
       Windows のシステムディレクトリーだけから検索されます。
返値: dll は、DLLクラスのインスタンスになります。
    但し、エラー時は、null になります。
注意: 指定のDLLが既にロード済みの場合、正常終了して、そのDLLの
    リンクカウントが1つアップします。
用例: 
        User32 = ::DLL.Link( "USER32", "sys" );
DLLエントリーの取得 記法: dll.GetEntry( name, type )     (ここで、dll はDLLクラスのインスタンス) 引数: name は、そのDLL内にあるエントリー名(関数名、または、データ名)を      指定します。     type は、まず、DLL関数の引数の渡し方を規定する       "__stdcall" または "__cdecl"     を指定します。このどちらの指定も無ければ、前者として扱います。     また、type は、DLL関数の返値が、倍精度実数の場合には、       "double"     を指定します。この指定が無ければ、返値は、ULONG または void です。     上記の2種類を同時に指定する場合は、"double __cdecl" のように、     返値の型を最初にして、両者の間に半角空白を入れます。     以上は、エントリーが関数の場合でした。     エントリーがデータの場合には、       "DATA"     とだけ指定します。     type が省略された場合、"__stdcall" で、返値が ULONG または void の     指定として扱います。ちなみに、この場合が、一般的には多いようです。 返値: 正常終了時には、DLL関数、または、DLLデータを特定する値が返ります。     エラー時は、null が返ります。 用例: 
        CreateWindowEx = User32.GetEntry( "CreateWindowExA" );
        DrawText = User32.GetEntry( "DrawTextA" );
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関数の引数は、整数やアドレスの場合、最大 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 =: "Apsaly";
    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 文で、
明示的に破棄できます。また、それが含まれているスコープが無くなる時に、
自動的(暗黙的)に破棄されます。