SHOEISHA iD

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

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

特集記事

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

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

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

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

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

MyScriptSiteクラスの実装

 JScriptを実行するにはIActiveScriptSiteを継承したクラスを用意します。ここではMyScriptSiteクラスとします。クラス図を下図に示します。

MyScriptSiteのクラス図
MyScriptSiteのクラス図

 まずIUnknownを実装します。QueryInterfaceにて、インターフェースIDにIID_IActiveScripteSiteが渡された場合、IActiveScriptSiteインターフェースへのポインタを返すようにします。ここでもSimpleMsgBoxクラスと同様、IMPL_IUNKNOWNマクロを使います。

call_jscript.cpp
class MyScriptSite : public IActiveScriptSite {
  IMPL_IUNKNOWN(IActiveScriptSite)
  IActiveScript *pAs;
  IActiveScriptParse *pAsp;
public:
  MyScriptSite() : refCount(1), pAs(NULL), pAsp(NULL) {
  }
  virtual ~MyScriptSite() {
  }

 次にIActiveScriptSiteの実装を行います。このインターフェースはスクリプトを実行する際に、スクリプトエンジンからコールバックされるメソッドが宣言されています。

 OnScriptErrorはスクリプトの実行エラー発生時に呼び出されます。引数として渡されるIActiveScriptErrorGetExceptionInfoを使うことにより、エラーメッセージの文字列を取得できます。ここでは、それをメッセージボックスに表示させています。

 GetItemInfoはスクリプトで使用されるオブジェクトを作成します。作成したオブジェクトは引数のppunkItemに代入しています。

 他のメソッドについては、特に実装は行いません。

call_jscript.cpp
// MyScriptSite クラスに追加
// IActiveScriptSite
STDMETHODIMP GetLCID(LCID*pLcid) {
  return E_NOTIMPL;
}
STDMETHODIMP GetDocVersionString(BSTR *pbstrVersionString) {
  return E_NOTIMPL;
}
STDMETHODIMP OnScriptTerminate(const VARIANT *pvarResult,
  const EXCEPINFO *pexcepinfo) {
  return S_OK;
}
STDMETHODIMP OnStateChange(SCRIPTSTATE ssScriptState) {
  return S_OK;
}
STDMETHODIMP OnScriptError(IActiveScriptError *pAse) {
  HRESULT hr;
  if(pAse==NULL) return E_POINTER;
  EXCEPINFO ei;
    hr=pAse->GetExceptionInfo(&ei);
  if(SUCCEEDED(hr))
    MessageBox(NULL, ei.bstrDescription, 
               ei.bstrSource, MB_OK | MB_ICONSTOP);
  return hr;
}
STDMETHODIMP OnEnterScript(void) {
  return S_OK;
}
STDMETHODIMP OnLeaveScript(void) {
  return S_OK;
}
STDMETHODIMP GetItemInfo(LPCOLESTR pstrName,DWORD dwReturnMask,
  IUnknown **ppunkItem,ITypeInfo **ppTypeInfo) {
  if((dwReturnMask & SCRIPTINFO_IUNKNOWN)) {
    if(wcscmp(pstrName,SimpleMsgBox::GetClassName())==0) {
      *ppunkItem=(IUnknown*)new SimpleMsgBox();
      return S_OK;
    }
  }
  return TYPE_E_ELEMENTNOTFOUND;
}
deleteは呼ばなくて良い?
 GetItemInfoにてSimpleMsgBoxをnewしていますがdeleteを呼んでいません。これは、SimpleMsgBox::Releaseにおいて参照カウンタが0になったとき自身をdeleteしているためです。SimpleMsgBox::Releaseはスクリプトエンジンから呼ばれます。

スクリプトエンジンでスクリプトを実行する

 スクリプトの実行準備を行うPrepareメソッドをMyScriptSiteクラスに追加します。

 スクリプトエンジンのインターフェースIActiveScriptを取得し、SetScriptSiteMyScriptSiteクラスのポインタを指定します。次にIActiveScriptParseインターフェースを取得しInitNewを呼びます。最後にAddNamedItemを呼んでSimpleMsgBoxクラスをグローバルオブジェクトとして追加しています。

call_jscript.cpp
// MyScriptSite クラスに追加
void Prepare() {
  CLSID clsid;
  CLSIDFromProgID(L"JScript", &clsid );
  CoCreateInstance(clsid, 0, CLSCTX_ALL, 
                   IID_IActiveScript, (void **)&pAs);
  pAs->SetScriptSite(this);
  pAs->QueryInterface(IID_IActiveScriptParse, (void **)&pAsp);
  pAsp->InitNew();
  pAs->AddNamedItem(SimpleMsgBox::GetClassName()
    ,SCRIPTITEM_GLOBALMEMBERS | SCRIPTITEM_ISVISIBLE);
}

 スクリプトを実行するRunメソッドをMyScriptSiteクラスに追加します。

 IActiveScriptParse::ParseScriptTextを呼び出しスクリプトを解析させ、IActiveScript::SetScriptStateを呼び出して状態をSCRIPTSTATE_CONNECTEDにするとスクリプトが実行されます。

call_jscript.cpp
// MyScriptSite クラスに追加
void Run(LPCOLESTR pScript) {
  pAsp->ParseScriptText(pScript,NULL,NULL,NULL,0,0
    ,SCRIPTTEXT_ISPERSISTENT,NULL,NULL);
  pAs->SetScriptState(SCRIPTSTATE_CONNECTED);
}

 状態をSCRIPTSTATE_CLOSEDにし、取得したインターフェースを解放するメソッドCloseMyScriptSiteクラスに追加します。

call_jscript.cpp
// MyScriptSite クラスに追加
void Close() {
  pAs->SetScriptState(SCRIPTSTATE_CLOSED);
  SAFE_RELEASE(pAs);
  SAFE_RELEASE(pAsp);
}

 _tmain関数を次のように書き換えます。スクリプトは直接文字列で渡しています。

call_jscript.cpp
int _tmain(int argc, _TCHAR* argv[]) {
  CoInitialize(NULL);
  CO_CREATE(MyScriptSite,my_site);
  my_site->Prepare();
  my_site->Run(
    L"var calc_result=55/89;"
    L"SimpleMsgBox.Show(\"This is a SimpleMsgBox\");"
    L"SimpleMsgBox.Show(\"This is a SimpleMsgBox with title\",
\"MY SCRIPT\");"
    L"SimpleMsgBox.Show(calc_result,\"calc_result\");"
  );
  my_site->Close();
  SAFE_RELEASE(my_site);
  CoUninitialize();
  return 0;
}

 以下のようなメッセージボックスが順番に表示されれば成功です。

本文の文字列だけを指定したメッセージボックス
本文の文字列だけを指定したメッセージボックス
本文とタイトルバーの文字列を指定したメッセージボックス
本文とタイトルバーの文字列を指定したメッセージボックス
JScriptの変数も表示可能
JScriptの変数も表示可能
alert関数は使えない
 メッセージを表示させるためにalertやWScript.Echoを使おうとしてもできません。alertはInternet Explorer、WScript.EchoはWSH(Windows Scripting Host)上でスクリプトを実行したときに使用可能です。

次のページ
C++からJScriptの関数を呼び出す

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

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

もっと読む

この記事の著者

syu5()

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング