CodeZine(コードジン)

特集ページ一覧

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

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

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/12/10 14:00

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

目次

JScriptからC++のクラスメソッドを呼び出す 1

本章の目的

 メッセージボックスを表示するJScriptから参照可能なグローバルオブジェクトSimpleMsgBoxをC++クラスで実装し、JScriptから呼び出してみます。メソッド名はShowとします(ソースコードは「call_jscript」を参照してください)。

SimpleMsgBox.Showの使用イメージ
SimpleMsgBox.Show(本文の文字列,[タイトルバーの文字列]);

使用例1.
SimpleMsgBox.Show("文法が違います。","エラーが発生しました");

使用例2. タイトルバーの文字列を省略する場合。
SimpleMsgBox.Show("OKボタンを押してください。");

実装手順

  1. IDispatchインターフェースを継承したSimpleMsgBoxクラスを実装する。
  2. IActiveScripteSiteインターフェースを継承したMyScriptSiteクラスを実装する。
  3. スクリプトをスクリプトエンジンに渡して実行する処理を実装する。

SimpleMsgBoxクラスの実装

 JScriptから直接C++のクラスメソッドを呼ぶことはできません。JScriptから呼べるのはIDispatchインターフェースを継承したクラスのみです。ここではSimpleMsgBoxクラスとして実装することにします。クラス図を下図に示します。

SimpleMsgBoxのクラス図
SimpleMsgBoxのクラス図

 まずIUnknownインターフェースを実装します。IUnknown::QueryInterfaceメソッドにおいて引数にIID_IDispatchが渡された場合IDispatchインターフェースへのポインタを返すようにします。これには先ほど定義したIMPL_IUNKNOWNマクロを使います。

call_jscript.cpp
class SimpleMsgBox : public IDispatch {
  IMPL_IUNKNOWN(IDispatch)
public:
  static LPCOLESTR GetClassName() { 
    return L"SimpleMsgBox";
  }
  SimpleMsgBox() : refCount(1) {
  }
  virtual ~SimpleMsgBox() {
  }

 次にIDispatchインターフェースを実装します。メソッドを表2に示します。

表2.IDispatchインターフェース
メソッド名 処理内容
GetTypeInfoCount タイプ情報の個数を返す。
GetTypeInfo タイプ情報を返す。
GetIDsOfNames 引数で渡された名前のメソッドやプロパティのDISPIDを返す。
Invoke 引数で渡されたDISPIDのメソッドの実行またはプロパティを設定・取得する。

 GetTypeInfoCountGetTypeInfoは、ここでは未使用です。

 GetIDsOfNamesが呼ばれたときShowという名前で問い合わせが来たら、1をDISPIDとして返します。

 Invokeが呼ばれたとき、DISPIDが1であればメッセージボックスを表示します。JScript上で指定された引数は、Invokeメソッドの引数として渡されます。

call_jscript.cpp
//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を使っています。

VARIANT型
 VARIANT型は、oaidl.hで定義されている、整数や文字列などが格納可能な構造体・共用体です。VARTYPE型のvtというメンバに、どの型で格納されているかという情報が入ります。型は「wtype.h」で定義されています。
例えばLONG型であればVT_I4、これが配列になるとVT_ARRAY | VT_I4になります。
これにより型に厳密なC++言語と、そうでない他の言語との間で、変数の受け渡しを実現しています。扱いを容易にするためのラッパークラスとして_variant_tが用意されています。

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5