SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++で作ったアプリケーションとJScriptの連携

C++からJScriptの実行とその逆の実行

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースコード (9.5 KB)

C++からJScriptの関数を呼び出す

本章の目的

 本章ではC++からJScriptの関数を呼び出してみます。2つの数を引数として、それらを割った値を画面に表示し、戻り値として返すDivide関数をJScriptで作成します。引数はJScriptのArrayオブジェクトで渡すことにし、画面表示にはSimpleMsgBox.Showを使います(ソースコードは「jscript_array」を参照してください)。

2つの数を割るスクリプト
function Divide(a){ // a : Array オブジェクト
  var result=a[0]/a[1];
  SimpleMsgBox.Show(a[0]+"/"+a[1]+"="+result,a.title);
  return result;"
}
JScriptのArrayオブジェクト
 VARIANT型で配列を表すには、vtメンバにVT_ARRAYを使いますが、これはJScriptの配列変数であるArrayオブジェクトと互換性がありません。それは次のような理由があるためです。
  • Arrayオブジェクトは添え字の数値が連続している必要がない。例えば0、1、2の次が100でも構わない。
  • Arrayオブジェクトは連想配列のため添え字に文字列を指定できる。JScriptではmyObject.nameのようにアクセスできる。
  • Arrayオブジェクトはexpandoプロパティを持っている。
  • Arrayオブジェクトは長さを返すlengthなどのプロパティを持つ。
この非互換性を克服する方法としてよく使われるのがVBArrayオブジェクトです。このオブジェクトを使うとVT_ARRAYなVARIANT型の変数をArrayオブジェクトに変換できます。
しかし、VBArrayオブジェクトは値の取得のみが可能でありスクリプト上で直接作成できません。そこで今回はC++側でArrayオブジェクトを作成し、引数として渡すようにしてみます。

実装手順

  1. スクリプトエンジンのIDispatchインターフェースを取得し、Arrayオブジェクトを作成する。
  2. ArrayオブジェクトのIDispatchExを取得し、2つの数とタイトル文字列を設定する。
  3. IDispatch::GetIDsOfNamesを呼び出し、Divide関数のDISPIDを取得する。
  4. 関数に渡す引数をDISPPARAMS構造体に設定し、IDispatch::Invokeを呼び出す。
DISPIDとは
 DISPIDとはメソッドやプロパティに対して関連付けられたIDです。

Arrayオブジェクトの作成と、値の設定

 まずスクリプトエンジンのIDispatchインターフェースを取得します。これによりJScriptの組み込みオブジェクトにアクセスできます。Invokeを使ってArrayオブジェクトを作成します。

jscript_array.cpp
//MyScriptSiteクラス
_variant_t Run(LPOLESTR pBootstrap[],_variant_t arg1,_variant_t arg2,
               LPCOLESTR pScript) {
  _variant_t result_t;
  IDispatch *pD=NULL;
  DISPID idMethod; 
  pAsp->ParseScriptText(pScript,NULL,NULL,NULL,0,0
    ,SCRIPTTEXT_ISPERSISTENT,NULL,NULL);
  pAs->SetScriptState(SCRIPTSTATE_CONNECTED);
  pAs->GetScriptDispatch(NULL,&pD);
  // Array オブジェクトを作成する
  IDispatch *pArray=NULL;
  _variant_t new_array;
  LPOLESTR array_name[]={L"Array"};
  DISPPARAMS no_params = {NULL,0,0,0};
  pD->GetIDsOfNames(IID_NULL, array_name, 1, ::GetUserDefaultLCID(), 
                    &idMethod); 
  pD->Invoke(idMethod,IID_NULL,::GetUserDefaultLCID(), DISPATCH_METHOD
    ,&no_params,&new_array,NULL,NULL);
  pArray=new_array.pdispVal;

 次に、作成したArrayオブジェクトに2つの数とタイトルのプロパティを設定します。これは作成したArrayオブジェクトからIDispatchExインターフェースを取得し、InvokeExを使うことにより設定できます。IDispatchではなくIDispatchExを使う理由はArrayオブジェクトのexpandoプロパティにアクセスするためです。

jscript_array.cpp
//MyScriptSite::Run の続き
  // Array オブジェクトに値とタイトル文字列を設定する
  IDispatchEx *pDEX=NULL;
  pArray->QueryInterface(__uuidof(IDispatchEx),(void**)&pDEX);
  DISPID propid;
  DISPID disp_propput=DISPID_PROPERTYPUT;
  pDEX->GetDispID(_bstr_t(L"0"), fdexNameEnsure, &propid);
  DISPPARAMS put_prop_parms={&arg1,&disp_propput,1,1};
  pDEX->InvokeEx(propid,LOCALE_USER_DEFAULT,
    DISPATCH_PROPERTYPUT,&put_prop_parms,NULL,NULL,NULL);

  pDEX->GetDispID(_bstr_t(L"1"), fdexNameEnsure, &propid);
  put_prop_parms.rgvarg=&arg2;
  pDEX->InvokeEx(propid,LOCALE_USER_DEFAULT,
    DISPATCH_PROPERTYPUT,&put_prop_parms,NULL,NULL,NULL);

  pDEX->GetDispID(_bstr_t(L"title"), fdexNameEnsure, &propid);
  _variant_t t(L"jscript_array");
  put_prop_parms.rgvarg=&t;
  pDEX->InvokeEx(propid,LOCALE_USER_DEFAULT,
    DISPATCH_PROPERTYPUT,&put_prop_parms,NULL,NULL,NULL);
  SAFE_RELEASE(pDEX);

 そして、呼び出したいJScript関数のDISPIDをGetIDsOfNamesで取得し、スクリプトエンジンのIDispatch::Invokeを呼び出すことによりJScriptの関数を実行できます。

jscript_array.cpp
//MyScriptSite::Run の続き
  // スクリプト関数を実行
  _variant_t argvar_t(pArray);
  DISPPARAMS args = {&argvar_t, 0, 1, 0};
  pD->GetIDsOfNames(IID_NULL, pBootstrap, 1, ::GetUserDefaultLCID(), 
                    &idMethod); 
  pD->Invoke(idMethod,IID_NULL,::GetUserDefaultLCID(), DISPATCH_METHOD
    ,&args,&result_t,NULL,NULL);
  SAFE_RELEASE(pD);
  return result_t;
}

 最後に_tmain関数にスクリプトを書き、実行する関数(Divide)と2つの数を指定します。戻り値をBSTR型に変換しメッセージボックスで表示させています。

jscript_array.cpp
int _tmain(int argc, _TCHAR* argv[]) {
  CoInitialize(NULL);
  CO_CREATE(MyScriptSite,my_site);
  my_site->Prepare();
  LPOLESTR funcs[]={L"Divide"};
  _variant_t result=my_site->Run(funcs,55,89,
    L"function Divide(a){"
    L"  var result=a[0]/a[1];"
    L"  SimpleMsgBox.Show(a[0]+\"/\"+a[1]+\"=\"+result,a.title);"
    L"  return result;"
    L"}"
  );
  result.ChangeType(VT_BSTR);
  MessageBox(NULL,result.bstrVal,TEXT("戻り値"),MB_OK);
  my_site->Close();
  SAFE_RELEASE(my_site);
  CoUninitialize();
  return 0;
}
演算結果
演算結果
JScript関数の戻り値を取得した結果
JScript関数の戻り値を取得した結果

おわりに

 Windows Scriptを使えば、簡単にアプリケーションにスクリプト機能を組み込むことができます。

 IActiveScriptSiteインターフェースを継承したクラスを作成し、C++とJScript間でメソッドを呼び出す方法を紹介しました。またJScriptのArrayオブジェクトを作成し、引数付きでJScript関数を呼び出す方法を紹介しました。

 本稿が開発の参考になれば幸いです。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

syu5()

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1827 2008/08/20 10:39

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング