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が用意されています。