CodeZine(コードジン)

特集ページ一覧

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

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

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

ダウンロード ソースコード (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)上でスクリプトを実行したときに使用可能です。

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

著者プロフィール

あなたにオススメ

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