seraphyの日記

日記というよりは過去を振り返るときのための単なる備忘録

ActiveScriptHostの最小(?)の雛形

#include <stdio.h>
#include <tchar.h>
#include <locale.h>

#include <atlbase.h>
#include <atlcom.h>

#include <activscp.h>

class __declspec(uuid("{B54F3741-5B07-11cf-A4B0-00AA004A55E8}")) VBScript;
//class __declspec(uuid("{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}")) JScript;


class __declspec(uuid("{147F5B60-1F9B-4035-A22C-1A87493CF6BD}")) MyScriptSite
	: public CComObjectRoot
	, public CComCoClass<MyScriptSite, &__uuidof(MyScriptSite)>
	, public IActiveScriptSite
	, public IActiveScriptSiteWindow
{
public:

	BEGIN_COM_MAP(MyScriptSite)
		COM_INTERFACE_ENTRY(IActiveScriptSite)
		COM_INTERFACE_ENTRY(IActiveScriptSiteWindow)
	END_COM_MAP( )

	DECLARE_NO_REGISTRY()
	DECLARE_CLASSFACTORY()

	virtual HRESULT STDMETHODCALLTYPE GetLCID( 
		/* [out] */ LCID *plcid) throw()
	{
		_tprintf(_TEXT("GetLCID\n"));
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE GetItemInfo( 
		/* [in] */ LPCOLESTR pstrName,
		/* [in] */ DWORD dwReturnMask,
		/* [out] */ IUnknown **ppiunkItem,
		/* [out] */ ITypeInfo **ppti) throw()
	{
		_tprintf(_TEXT("GetItemInfo\n"));
		return TYPE_E_ELEMENTNOTFOUND;
	}

	virtual HRESULT STDMETHODCALLTYPE GetDocVersionString( 
		/* [out] */ BSTR *pbstrVersion) throw()
	{
		_tprintf(_TEXT("GetDocVersionString\n"));
		*pbstrVersion = SysAllocString(L"MyScriptSite");
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE OnScriptTerminate( 
		/* [in] */ const VARIANT *pvarResult,
		/* [in] */ const EXCEPINFO *pexcepinfo) throw()
	{
		_tprintf(_TEXT("OnScriptTerminate\n"));
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE OnStateChange( 
		/* [in] */ SCRIPTSTATE ssScriptState) throw()
	{
		_tprintf(_TEXT("OnStateChange: %d\n"), ssScriptState);
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE OnScriptError( 
		/* [in] */ IActiveScriptError *pscripterror) throw()
	{
		EXCEPINFO excepinfo = {0};

		pscripterror->GetExceptionInfo(&excepinfo);
		CW2T mes(excepinfo.bstrDescription);
		_tprintf(_TEXT("OnScriptError: %s\n"), mes);
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE OnEnterScript(void) throw()
	{
		_tprintf(_TEXT("OnEnterScript\n"));
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE OnLeaveScript(void) throw()
	{
		_tprintf(_TEXT("OnLeaveScript\n"));
		return S_OK;
	}

	////

	virtual HRESULT STDMETHODCALLTYPE GetWindow(
		/* [out] */ HWND *phwnd)
	{
		_tprintf(_TEXT("GetWindow\n"));
		*phwnd = GetDesktopWindow();
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE EnableModeless( 
		/* [in] */ BOOL fEnable)
	{
		_tprintf(_TEXT("EnableModeless:%d\n"), fEnable);
		return S_OK;
	}
};

OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO(__uuidof(MyScriptSite), MyScriptSite);

class MyAXScriptHostTest1
	: public CAtlExeModuleT<MyAXScriptHostTest1>
{
public:
	HRESULT PreMessageLoop(int nShowCmd) throw()
	{
		HRESULT hr = __super::PreMessageLoop(nShowCmd);
		ATLASSERT(SUCCEEDED(hr));
		if (FAILED(hr)) {
			return hr;
		}

		// スクリプトエンジンの構築
		hr = pScript_.CoCreateInstance(__uuidof(VBScript));
		ATLASSERT(SUCCEEDED(hr));

		return hr;
	}

	void RunMessageLoop(void) throw()
	{
		HRESULT hr;

		// Siteの構築
		CComPtr<IActiveScriptSite> pSite;
		hr = MyScriptSite::CreateInstance(&pSite);
		ATLASSERT(SUCCEEDED(hr));

		// スクリプトエンジンにSiteを設定
		hr = pScript_->SetScriptSite(pSite);
		ATLASSERT(SUCCEEDED(hr));

		ParseScript();

		// スクリプトの開始
		hr = pScript_->SetScriptState(SCRIPTSTATE_CONNECTED);
		ATLASSERT(SUCCEEDED(hr));

		TestDispatch();

		// スクリプトの解放
		pScript_->Close();
	}

	void ParseScript(void) throw()
	{
		HRESULT hr;

		// スクリプト解析インターフェイスの取得
		CComQIPtr<IActiveScriptParse> pParse(pScript_);

		hr = pParse->InitNew(); // 初回のみ、以後Closeするまで呼び出し不可
		ATLASSERT(SUCCEEDED(hr));

		// ParseScriptTextは複数回呼び出し可能
		LPCWSTR source = L"MsgBox \"ok\"\r\n"
				L"Sub testfunc\r\nMsgBox \"ok2\"\r\nEnd Sub\r\n";
		hr = pParse->ParseScriptText(source, NULL, NULL, NULL, 0, 1,
			SCRIPTTEXT_ISPERSISTENT | SCRIPTTEXT_ISVISIBLE, NULL, NULL);
		ATLASSERT(SUCCEEDED(hr));
	}

	void TestDispatch(void) throw()
	{
		HRESULT hr;

		// スクリプトのルートコンテキストを取得
		CComPtr<IDispatch> pScriptDisp;
		hr = pScript_->GetScriptDispatch(NULL, &pScriptDisp);
		ATLASSERT(SUCCEEDED(hr));

		// スクリプト上に定義されているtestfuncの呼び出し
		LPOLESTR szMember[] = {L"testfunc", NULL};
		DISPID dispids[1];
		hr = pScriptDisp->GetIDsOfNames(IID_NULL, &szMember[0], 1,
			LOCALE_SYSTEM_DEFAULT, &dispids[0]);
		ATLASSERT(SUCCEEDED(hr));

		DISPPARAMS param = {NULL, NULL, 0, 0};
		hr = pScriptDisp->Invoke(dispids[0], IID_NULL, LOCALE_SYSTEM_DEFAULT,
			DISPATCH_METHOD, &param, NULL, NULL, NULL);
		ATLASSERT(SUCCEEDED(hr));

		pScriptDisp.Release();
	}

private:
	CComPtr<IActiveScript> pScript_;
};

int _tmain(int argc, _TCHAR* argv[])
{
	setlocale(LC_ALL, "");
	MyAXScriptHostTest1 module;
	return module.WinMain(SW_SHOWNORMAL);
}

過去に何度も試しているが使うたびに忘れてサンプルを探すハメになっているのでメモしておく。