vc++訪問javascript(2)–IDispatchEx是動態指令碼語言的基礎

來源:互聯網
上載者:User
 

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.    }

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.