vc++访问javascript(2)--IDispatchEx是动态脚本语言的基础

IDispatchEx接口是为支持动态脚本语言如JavaScript而设计的,扩展了IDispatch的功能,允许在运行时添加、删除成员以及实现大小写敏感的方法。通过这个接口,VC++能够访问并模拟JavaScript的动态特性,例如添加expando、删除成员、枚举DISPID等。这对于在VC++中与JavaScript交互至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

IDispatch接口主要应用于传统的自动化编程,如著名的Microsoft Visual Basic。客户端程序只需得到COM组件的IDispatch接口就可调用组件所有的属性和方法。但IDispatch的局限在与它假定COM组件是静态的。也就是说,在运行期间,这些COM组件的属性和方法是不能改变的。因此,如果要实现javascript和vbscript脚本语言的动态特性,就需要一个更灵活的接口。

于是为脚本语言量身定制的IDispatchEx接口诞生了。IDispatchEx派生自IDispatch,除了支持IDispatch所约定的方法之外,还提供了一组扩展方法,用于支持脚本语言的动态特性,这些动态特性包括:

  • 为object添加成员 ("expando") — 使用带fdexNameEnsure标记的方法 GetDispID.
  • 删除object的成员 — 使用方法DeleteMemberByName 或者DeleteMemberByDispID.
  • 支持大小写敏感的方法 — 使用fdexNameCaseSensitive标记或fdexNameCaseInsensitive标记..
  • 使用隐含名搜索成员 — 使用fdexNameImplicit标记
  • 枚举object所有成员的DISPID — 使用GetNextDispID.
  • 通过DispID取得成员的名称 — 使用GetMemberName.
  • 获取object成员的属性 — 使用GetMemberProperties.
  • 使用执行带this指针的方法调用 — 使用方法InvokeEx.
    • 允许支持命名空间概念的浏览器获取object的命名空间 — 使用方法GetNameSpaceParent.

 

其实在这里,IDispatchEx接口存在更重要的意义在于,使得我们有途径在VC++中访问并模拟动态脚本语言的特性。下面我们以javascript为例。

 

举例:
方法test()中的javascript代码执行以下动作:
调用Object的constructor(构造器)创建一个新的object,用变量Obj保存。
在object中创建一个新的成员Elem,并将Elem的值设为方法cat的指针。
调用Elem方法,传入this指针。因为Elem是Obj的成员,所以this指针就指向Obj。于是方法cat中的代码也就是为Obj设置了一个新的成员Bar,并赋值为10。
完整的HTML代码如下:
   <HTML>
   <BODY>
   <SCRIPT LANGUAGE="javascript">    function cat()
   {
      //创建一个新的成员,并赋值10
      this.Bar = 10;
   }    function test()
   {
      // 创建一个新的object
      Obj = new Object();       // 创建新的成员,并赋值为cat
      Obj.Elem = cat;       //调用Elem("this" == Obj)
      Obj.Elem();       //现在Obj.Bar已经存在了
   }
   //
   test();
   </SCRIPT>
   </BODY>
   </HTML>
我们通过一个控件用VC++封装方法test中的代码。当一个控件放在一个网页中,就可以取得浏览器中的脚本引擎的IDispatch接口和IDispatchEx接口( 详情见上一篇)。
   <HTML>
   <BODY>
   <SCRIPT LANGUAGE="javascript">
   function cat()
   {
      // 创建一个新的成员,并赋值10       this.Bar = 10;
   }
   </SCRIPT>
   <OBJECT ID="test" <CLASSID="CLSID:9417DB5D-FA2A-11D0-8CB3-00C04FC2B085">>
   </OBJECT>
   </BODY>
   </HTML>
在控件test中我们将进行如下操作:
1、使用GetDispID()取得方法cat的指针。
2、使用GetDispID()取得方法Object的指针。
3、使用InvokeEx()调用方法Object创建一个新的object。
4、使用GetDispID()为object创建一个新的成员Elem。
5、使用InvokeEx()将方法cat的指针赋给成员Elem。
6、使用InvokeEx()调用Elem(也就是方法cat),将object对象作为this指针传入。于是方法cat为this指针(也就是object)创建一个新成员Bar。
7、使用GetNextDispID()枚举object,验证刚才新建的成员Bar是否存在。
控件test中的代码如下:
  
  1. BOOL test(IDispatchEx *pdexScript)
  2.    {
  3.       HRESULT hr;
  4.       VARIANT var;
  5.       DISPID dispid, putid;
  6.       BOOL retval = FALSE;
  7.       BSTR bstrName = NULL;
  8.       IDispatch   *pdispObj = NULL, *pdispCat = NULL;
  9.       IDispatchEx *pdexObj = NULL;
  10.       DISPPARAMS dispparams, dispparamsNoArgs = {NULL, NULL, 0, 0};
  11.       // Get dispatch pointer for "cat"
  12.       bstrName = SysAllocString(OLESTR("cat"));
  13.          if (bstrName == NULL) goto LDone;
  14.       hr = pdexScript->GetDispID(bstrName, 0, &dispid);
  15.          if (FAILED(hr)) goto LDone;
  16.       SysFreeString(bstrName);
  17.          bstrName = NULL;
  18.       hr = pdexScript->InvokeEx(dispid, LOCALE_USER_DEFAULT, 
  19.          DISPATCH_PROPERTYGET, &dispparamsNoArgs, 
  20.          &var, NULL, NULL);
  21.          if (FAILED(hr)) goto LDone;
  22.       pdispCat = var.pdispVal; 
  23.       // Create object by calling "Object" constructor
  24.       bstrName = SysAllocString(OLESTR("Object"));
  25.          if (NULL == bstrName) goto LDone;
  26.       hr = pdexScript->GetDispID(bstrName, 0, &dispid);
  27.          if (FAILED(hr)) goto LDone;
  28.       SysFreeString(bstrName);
  29.          bstrName = NULL;
  30.       hr = pdexScript->InvokeEx(dispid, LOCALE_USER_DEFAULT, 
  31.          DISPATCH_CONSTRUCT, &dispparamsNoArgs, 
  32.          &var, NULL, NULL);
  33.          if (FAILED(hr)) goto LDone;
  34.       pdispObj = var.pdispVal;
  35.       hr = pdispObj->QueryInterface(IID_IDispatchEx, (void **)&pdexObj);
  36.          if (FAILED(hr)) goto LDone; 
  37.       // Create new element in object
  38.       bstrName = SysAllocString(OLESTR("Elem"));
  39.          if (NULL == bstrName) goto LDone;
  40.       hr = pdexObj->GetDispID(bstrName, fdexNameEnsure, &dispid);
  41.          if (FAILED(hr)) goto LDone;
  42.       SysFreeString(bstrName);
  43.          bstrName = NULL; 
  44.       // Assign "cat" dispatch pointer to element
  45.       putid = DISPID_PROPERTYPUT;
  46.       var.vt = VT_DISPATCH;
  47.       var.pdispVal = pdispCat;
  48.       dispparams.rgvarg = &var;
  49.       dispparams.rgdispidNamedArgs = &putid;
  50.       dispparams.cArgs = 1;
  51.       dispparams.cNamedArgs = 1;
  52.       hr = pdexObj->InvokeEx(dispid, LOCALE_USER_DEFAULT, 
  53.          DISPATCH_PROPERTYPUTREF, &dispparams,
  54.          NULL, NULL, NULL);
  55.          if (FAILED(hr)) goto LDone; 
  56.       // Invoke method with "this" pointer
  57.       putid = DISPID_THIS;
  58.       var.vt = VT_DISPATCH;
  59.       var.pdispVal = pdispObj;
  60.       dispparams.rgvarg = &var;
  61.       dispparams.rgdispidNamedArgs = &putid;
  62.       dispparams.cArgs = 1;
  63.       dispparams.cNamedArgs = 1;
  64.       hr = pdexObj->InvokeEx(dispid, LOCALE_USER_DEFAULT,
  65.          DISPATCH_METHOD, &dispparams,
  66.             NULL, NULL, NULL);
  67.          if (FAILED(hr)) goto LDone; 
  68.       // Confirm that new element "Bar" is in object
  69.       hr = pdexObj->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid);
  70.       while (hr == NOERROR)
  71.       {
  72.             hr = pdexObj->GetMemberName(dispid, &bstrName);
  73.             if (FAILED(hr)) goto LDone;
  74.             retval = !wcscmp(bstrName, OLESTR("Bar"));
  75.             SysFreeString(bstrName);
  76.             bstrName = NULL;
  77.             if (retval) goto LDone;
  78.          hr = pdexObj->GetNextDispID(fdexEnumAll, dispid, &dispid);
  79.       }
  80. LDone:
  81.    SysFreeString(bstrName);
  82.    if (pdispCat != NULL)
  83.       pdispCat->Release();
  84.    if (pdispObj != NULL)
  85.       pdispObj->Release();
  86.    if (pdexObj != NULL)
  87.       pdexObj->Release(); 
  88.    return retval;
  89.    }

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值