用于脚本的IDispatch实现

来源:互联网 发布:皮尔斯季后赛数据 编辑:程序博客网 时间:2024/05/18 01:16

做这个Dispatch实现基类的目标有3个:

1。能够很方便滴映射成员供脚本(包括使用WebBrowser的external对象) 访问;

2。最好能不依赖MFC;

3。不用tlb文件,不写注册表。

实现的时候,参考了Delphi的ComAutoObj(话说回来,这个单元的BUG可不小,上次做的时候用着用着就出错。。。还好有个好心的澳大利亚青年发了个补丁……扯到哪里去了-___-b) 最后完成下来,派生类中的映射是这样滴,看起来还不错:P,也没有像MFC的CDispatchHelper里面的VTS_I4这样的东东了:

 BEGIN_AC_DISPMAP(CMyGlobal)
  AC_DISP_FUNCTION(1, L"alert", alert)
  AC_DISP_FUNCTION(2, L"add", add2)
  AC_DISP_PROP(3, L"count", get_count, put_count)
  AC_DISP_READONLYPROP(4, L"beeper", get_beeper)
 END_AC_DISPMAP()

不多说鸟,贴CODE:

ACDispatch.h

#pragma once

#include "oaidl.h"
#include "comutil.h"

#define BEGIN_AC_DISPMAP(theClass) /
 typedef void (theClass::*_AC_DispP1Func)(_variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP1Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
  if ( pDispParams->cArgs != 1 ) return E_INVALIDARG;/
  _variant_t v1(pDispParams->rgvarg[0]);/
  _variant_t retval;/
  (this->*func)(v1, retval);/
  if (pVarResult) *pVarResult = retval;/
  return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP2Func)(_variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP2Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 2 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t retval;/
 (this->*func)(v1, v2, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP3Func)(_variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP3Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 3 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP4Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP4Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 4 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP5Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP5Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 5 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t v5(pDispParams->rgvarg[4]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, v5, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP6Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP6Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 6 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t v5(pDispParams->rgvarg[4]);/
 _variant_t v6(pDispParams->rgvarg[5]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, v5, v6, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP7Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP7Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 7 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t v5(pDispParams->rgvarg[4]);/
 _variant_t v6(pDispParams->rgvarg[5]);/
 _variant_t v7(pDispParams->rgvarg[6]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, v5, v6, v7, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP8Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP8Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 8 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t v5(pDispParams->rgvarg[4]);/
 _variant_t v6(pDispParams->rgvarg[5]);/
 _variant_t v7(pDispParams->rgvarg[6]);/
 _variant_t v8(pDispParams->rgvarg[7]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, v5, v6, v7, v8, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP9Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP9Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 9 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t v5(pDispParams->rgvarg[4]);/
 _variant_t v6(pDispParams->rgvarg[5]);/
 _variant_t v7(pDispParams->rgvarg[6]);/
 _variant_t v8(pDispParams->rgvarg[7]);/
 _variant_t v9(pDispParams->rgvarg[8]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, v5, v6, v7, v8, v9, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 typedef void (theClass::*_AC_DispP10Func)(_variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t, _variant_t&);/
 HRESULT MultiParamInvoke(_AC_DispP10Func func, DISPPARAMS *pDispParams, VARIANT *pVarResult)/
 {/
 if ( pDispParams->cArgs != 10 ) return E_INVALIDARG;/
 _variant_t v1(pDispParams->rgvarg[0]);/
 _variant_t v2(pDispParams->rgvarg[1]);/
 _variant_t v3(pDispParams->rgvarg[2]);/
 _variant_t v4(pDispParams->rgvarg[3]);/
 _variant_t v5(pDispParams->rgvarg[4]);/
 _variant_t v6(pDispParams->rgvarg[5]);/
 _variant_t v7(pDispParams->rgvarg[6]);/
 _variant_t v8(pDispParams->rgvarg[7]);/
 _variant_t v9(pDispParams->rgvarg[8]);/
 _variant_t v10(pDispParams->rgvarg[9]);/
 _variant_t retval;/
 (this->*func)(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, retval);/
 if (pVarResult) *pVarResult = retval;/
 return S_OK;/
 }/
 virtual HRESULT GetIDOrInvoke(BOOL bGetID, WORD wFlags, LPOLESTR szName, DISPPARAMS *pDispParams, VARIANT *pVarResult, DISPID* rgDispID)/
 {/


#define END_AC_DISPMAP() /
  return E_NOTIMPL;/
 }


#define AC_DISP_FUNCTION(id, funcName, funcptr) /
  if ( bGetID && wcscmp(szName, funcName) == 0 )/
  {/
   *rgDispID = id;/
   return S_OK; /
  }/
  else if ( (!bGetID) && *rgDispID == id ) /
  { /
   return MultiParamInvoke(funcptr, pDispParams, pVarResult);/
  }

#define AC_DISP_PROP(id, propName, getfunc, putfunc) /
 if ( bGetID && wcscmp(szName, propName) == 0 )/
 {/
  *rgDispID = id;/
  return S_OK;/
 }/
 else if ( (!bGetID) && *rgDispID == id ) /
 { /
  if ( wFlags & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF) ) /
  { /
   if ( pDispParams->cNamedArgs != 1 || pDispParams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT ) return DISP_E_MEMBERNOTFOUND; /
   putfunc(_variant_t(pDispParams->rgvarg[0]));/
   return S_OK; /
  } /
  else /
  { /
   if ( pDispParams->cArgs != 0 ) return DISP_E_BADPARAMCOUNT; /
   _variant_t retval; /
   getfunc(retval); /
   *pVarResult = retval; /
   return S_OK; /
  } /
 }

#define AC_DISP_READONLYPROP(id, propName, getfunc) /
 if ( bGetID && wcscmp(szName, propName) == 0 )/
 {/
  *rgDispID = id;/
  return S_OK;/
 }/
 else if ( (!bGetID) && *rgDispID == id ) /
 { /
  if ( pDispParams->cArgs != 0 ) return DISP_E_BADPARAMCOUNT; /
  _variant_t retval; /
  getfunc(retval); /
  *pVarResult = retval; /
  return S_OK; /
 } /

/********************** 广告位招租 *************************/

/*
 * CACAutoDispatch : a simple dispatch driver used for script
 */
class CACAutoDispatch : public IDispatch
{
private:
 UINT m_uRefCount;
public:
 CACAutoDispatch(BOOL bZeroRefCount);
 virtual ~CACAutoDispatch(void);
public:
 virtual HRESULT STDMETHODCALLTYPE QueryInterface(
  /* [in] */ REFIID riid,
  /* [iid_is][out] */ void ** ppvObject);

 virtual ULONG STDMETHODCALLTYPE AddRef(void);

 virtual ULONG STDMETHODCALLTYPE Release(void);

 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
  /* [out] */ UINT *pctinfo);

 virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
  /* [in] */ UINT iTInfo,
  /* [in] */ LCID lcid,
  /* [out] */ ITypeInfo **ppTInfo);

 virtual HRESULT GetIDOrInvoke(BOOL bGetID, WORD wFlags, LPOLESTR szName, DISPPARAMS *pDispParams, VARIANT *pVarResult, DISPID* rgDispID) = 0;

 virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
  /* [in] */ REFIID riid,
  /* [size_is][in] */ LPOLESTR *rgszNames,
  /* [in] */ UINT cNames,
  /* [in] */ LCID lcid,
  /* [size_is][out] */ DISPID *rgDispId)
 {
  return GetIDOrInvoke(TRUE, 0, rgszNames[0], NULL, NULL, rgDispId);
 }

 virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke(
  /* [in] */ DISPID dispIdMember,
  /* [in] */ REFIID riid,
  /* [in] */ LCID lcid,
  /* [in] */ WORD wFlags,
  /* [out][in] */ DISPPARAMS *pDispParams,
  /* [out] */ VARIANT *pVarResult,
  /* [out] */ EXCEPINFO *pExcepInfo,
  /* [out] */ UINT *puArgErr)
 {
  return GetIDOrInvoke(FALSE, wFlags, NULL, pDispParams, pVarResult, &dispIdMember);
 }
};

ACDispatch.cpp

#include "StdAfx.h"
#include "./acdispatch.h"

/* Note: we initialized the ref count to zero to make the object
 auto-deleted by script engine when bZeroRefCount is TRUE,
   *NEVER* call Release() in constructor */
CACAutoDispatch::CACAutoDispatch(BOOL bZeroRefCount) : m_uRefCount(1)
{
 if (bZeroRefCount) m_uRefCount = 0;
}

CACAutoDispatch::~CACAutoDispatch(void)
{
}

HRESULT STDMETHODCALLTYPE CACAutoDispatch::QueryInterface(
 /* [in] */ REFIID riid,
 /* [iid_is][out] */ void **ppvObject)
{
 if ( riid == IID_IUnknown || riid == IID_IDispatch )
 {
  this->AddRef();
  *ppvObject = this;
  return S_OK;
 }
 else
 {
  *ppvObject = NULL;
  return E_NOINTERFACE;
 }
}

ULONG STDMETHODCALLTYPE CACAutoDispatch::AddRef(void)
{
 return ++m_uRefCount;
}

ULONG STDMETHODCALLTYPE CACAutoDispatch::Release(void)
{
 ULONG ret = --m_uRefCount;
 if (ret == 0) delete this;
 return ret;
}

STDMETHODIMP CACAutoDispatch::GetTypeInfoCount(
 /* [out] */ UINT *pctinfo)
{
 return E_NOTIMPL;
}

STDMETHODIMP CACAutoDispatch::GetTypeInfo(
 /* [in] */ UINT iTInfo,
 /* [in] */ LCID lcid,
 /* [out] */ ITypeInfo **ppTInfo)
{
 return E_NOTIMPL;
}

下面是用一个console工程测试的代码,测试的脚本环境当然是msscriptcontrol,真是方便亚。

// testcons2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "conio.h"
#include "atlstr.h"
#include "d:/design/ac/acdispatch.h"
#include "comutil.h"

#import "c:/windows/system32/msscript.ocx"

class CBeeper2 : public CACAutoDispatch
{
private:
 void beep(_variant_t msg, _variant_t& retval)
 {
  CString str = msg;
  printf("beep:%s/n", str);
 }
public:
 CBeeper2(BOOL bZeroRefCount) : CACAutoDispatch(bZeroRefCount)
 {
 }
 ~CBeeper2()
 {
 }
public:
 BEGIN_AC_DISPMAP(CBeeper2)
  AC_DISP_FUNCTION(1, L"beep", beep)
 END_AC_DISPMAP()
};

class CMyGlobal : public CACAutoDispatch
{
private:
 void alert(_variant_t msg, _variant_t& retval)
 {
  CString str = msg;
  printf("%s/n", str);
 }
 void add2(_variant_t v1, _variant_t v2, _variant_t& retval)
 {
  int p1 = v1;
  int p2 = v2;
  retval = p1 + p2;
 }
 int m_count;
 void put_count(_variant_t v1)
 {
  m_count = v1;
 }

 void get_count(_variant_t& retval)
 {
  retval = m_count;
 }

 void get_beeper(_variant_t& retval)
 {
  // init ref count to 1
  retval = new CBeeper2(FALSE);
 }
public:
 CMyGlobal(BOOL bZeroRefCount) : CACAutoDispatch(bZeroRefCount)
 {
  m_count = 0;
 }
 ~CMyGlobal()
 {
 }
public:
 BEGIN_AC_DISPMAP(CMyGlobal)
  AC_DISP_FUNCTION(1, L"alert", alert)
  AC_DISP_FUNCTION(2, L"add", add2)
  AC_DISP_PROP(3, L"count", get_count, put_count)
  AC_DISP_READONLYPROP(4, L"beeper", get_beeper)
 END_AC_DISPMAP()
};

using namespace MSScriptControl;

int _tmain(int argc, _TCHAR* argv[])
{
 ::CoInitialize(NULL);
 {
  IScriptControlPtr pCtrl;
  pCtrl.CreateInstance(__uuidof(ScriptControl));
  pCtrl->put_Language(_bstr_t("javascript"));
  pCtrl->AddObject( _bstr_t("myglobal"), new CMyGlobal(TRUE), VARIANT_TRUE );
  /* 以下这句将打印出beep:3 */
  pCtrl->ExecuteStatement("count = 2; beeper.beep(add('1', count));");
  pCtrl = NULL;
 }
 ::CoUninitialize();
 getch();
 return 0;
}

 

原创粉丝点击