C++からJScriptの関数を呼び出す
本章の目的
本章ではC++からJScriptの関数を呼び出してみます。2つの数を引数として、それらを割った値を画面に表示し、戻り値として返すDivide
関数をJScriptで作成します。引数はJScriptのArray
オブジェクトで渡すことにし、画面表示にはSimpleMsgBox.Show
を使います(ソースコードは「jscript_array」を参照してください)。
function Divide(a){ // a : Array オブジェクト var result=a[0]/a[1]; SimpleMsgBox.Show(a[0]+"/"+a[1]+"="+result,a.title); return result;" }
- Arrayオブジェクトは添え字の数値が連続している必要がない。例えば0、1、2の次が100でも構わない。
- Arrayオブジェクトは連想配列のため添え字に文字列を指定できる。JScriptではmyObject.nameのようにアクセスできる。
- Arrayオブジェクトはexpandoプロパティを持っている。
- Arrayオブジェクトは長さを返すlengthなどのプロパティを持つ。
しかし、VBArrayオブジェクトは値の取得のみが可能でありスクリプト上で直接作成できません。そこで今回はC++側でArrayオブジェクトを作成し、引数として渡すようにしてみます。
実装手順
- スクリプトエンジンのIDispatchインターフェースを取得し、Arrayオブジェクトを作成する。
- ArrayオブジェクトのIDispatchExを取得し、2つの数とタイトル文字列を設定する。
- IDispatch::GetIDsOfNamesを呼び出し、Divide関数のDISPIDを取得する。
- 関数に渡す引数をDISPPARAMS構造体に設定し、IDispatch::Invokeを呼び出す。
Arrayオブジェクトの作成と、値の設定
まずスクリプトエンジンのIDispatch
インターフェースを取得します。これによりJScriptの組み込みオブジェクトにアクセスできます。Invoke
を使ってArray
オブジェクトを作成します。
//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
プロパティにアクセスするためです。
//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の関数を実行できます。
//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
型に変換しメッセージボックスで表示させています。
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; }
おわりに
Windows Scriptを使えば、簡単にアプリケーションにスクリプト機能を組み込むことができます。
IActiveScriptSite
インターフェースを継承したクラスを作成し、C++とJScript間でメソッドを呼び出す方法を紹介しました。またJScriptのArray
オブジェクトを作成し、引数付きでJScript関数を呼び出す方法を紹介しました。
本稿が開発の参考になれば幸いです。