JScriptからC++のクラスメソッドを呼び出す 1
本章の目的
メッセージボックスを表示するJScriptから参照可能なグローバルオブジェクトSimpleMsgBoxをC++クラスで実装し、JScriptから呼び出してみます。メソッド名はShowとします(ソースコードは「call_jscript」を参照してください)。
SimpleMsgBox.Show(本文の文字列,[タイトルバーの文字列]); 使用例1. SimpleMsgBox.Show("文法が違います。","エラーが発生しました"); 使用例2. タイトルバーの文字列を省略する場合。 SimpleMsgBox.Show("OKボタンを押してください。");
実装手順
- IDispatchインターフェースを継承したSimpleMsgBoxクラスを実装する。
- IActiveScripteSiteインターフェースを継承したMyScriptSiteクラスを実装する。
- スクリプトをスクリプトエンジンに渡して実行する処理を実装する。
SimpleMsgBoxクラスの実装
JScriptから直接C++のクラスメソッドを呼ぶことはできません。JScriptから呼べるのはIDispatchインターフェースを継承したクラスのみです。ここではSimpleMsgBoxクラスとして実装することにします。クラス図を下図に示します。

まずIUnknownインターフェースを実装します。IUnknown::QueryInterfaceメソッドにおいて引数にIID_IDispatchが渡された場合IDispatchインターフェースへのポインタを返すようにします。これには先ほど定義したIMPL_IUNKNOWNマクロを使います。
class SimpleMsgBox : public IDispatch { IMPL_IUNKNOWN(IDispatch) public: static LPCOLESTR GetClassName() { return L"SimpleMsgBox"; } SimpleMsgBox() : refCount(1) { } virtual ~SimpleMsgBox() { }
次にIDispatchインターフェースを実装します。メソッドを表2に示します。
| メソッド名 | 処理内容 |
| GetTypeInfoCount | タイプ情報の個数を返す。 |
| GetTypeInfo | タイプ情報を返す。 |
| GetIDsOfNames | 引数で渡された名前のメソッドやプロパティのDISPIDを返す。 |
| Invoke | 引数で渡されたDISPIDのメソッドの実行またはプロパティを設定・取得する。 |
GetTypeInfoCountとGetTypeInfoは、ここでは未使用です。
GetIDsOfNamesが呼ばれたときShowという名前で問い合わせが来たら、1をDISPIDとして返します。
Invokeが呼ばれたとき、DISPIDが1であればメッセージボックスを表示します。JScript上で指定された引数は、Invokeメソッドの引数として渡されます。
//SimpleMsgBoxクラスに追加 // IDispatch STDMETHODIMP GetTypeInfoCount(UINT __RPC_FAR *pctinfo) { return E_NOTIMPL; } STDMETHODIMP GetTypeInfo(UINT iTInfo,LCID lcid ,ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) { return E_NOTIMPL; } STDMETHODIMP GetIDsOfNames(REFIID riid,LPOLESTR __RPC_FAR *rgszNames ,UINT cNames ,LCID lcid ,DISPID __RPC_FAR *rgDispId) { HRESULT hr = NOERROR; for (UINT i = 0; i < cNames; i++){ *(rgDispId + i) = DISPID_UNKNOWN; hr = DISP_E_MEMBERNOTFOUND; if (_wcsicmp(*(rgszNames + i), L"Show") == 0) { *(rgDispId + i) = 1; hr=S_OK; } } return hr; } STDMETHODIMP Invoke(DISPID dispIdMember,REFIID riid, LCID lcid,WORD wFlags,DISPPARAMS FAR *pDispParams, VARIANT FAR *pVarResult,EXCEPINFO FAR *pExcepInfo, unsigned int FAR *puArgErr) { if(wFlags!=DISPATCH_METHOD || dispIdMember!=1) return DISP_E_MEMBERNOTFOUND; if(pDispParams->cArgs==1) { // 引数が1つのとき _variant_t str(pDispParams->rgvarg); str.ChangeType(VT_BSTR); MessageBox(NULL,str.bstrVal,TEXT("(no title)"),MB_OK); }else if(pDispParams->cArgs==2) { // 引数が2つのとき _variant_t str(pDispParams->rgvarg[1]); // 引数取得 _variant_t subject(pDispParams->rgvarg[0]); str.ChangeType(VT_BSTR); subject.ChangeType(VT_BSTR); MessageBox(NULL,str.bstrVal,subject.bstrVal,MB_OK); } return S_OK;; }
JScriptとC++間で変数やオブジェクトをやり取りするとき、C++ではVARIANT型として扱います。ここでは、そのラッパークラスである_variant_tを使っています。
例えばLONG型であればVT_I4、これが配列になるとVT_ARRAY | VT_I4になります。
これにより型に厳密なC++言語と、そうでない他の言語との間で、変数の受け渡しを実現しています。扱いを容易にするためのラッパークラスとして_variant_tが用意されています。
