SHOEISHA iD

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

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

特集記事

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

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

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

ダウンロード ソースコード (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が用意されています。

次のページ
JScriptからC++のクラスメソッドを呼び出す 2

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

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

もっと読む

この記事の著者

syu5()

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング