VC與JavaScript交互(二) --- 調用JS函數


這一章,我們來動手實踐VC調用JS函數

我們動手寫一個HTML,其中包含這樣一段JS代碼:

//[html]
<script type="text/javascript">  
    function Add(value1, value2) 
    {  
        return value1 + value2;  
    }  
</script>

然后我們用WebBrowser加載這個HTML后,在VC中這樣來調用這個函數名為Add的JS函數:

//[Cpp]
//別忘了#include <MsHTML.h>  

void CTestCallJsDlg::OnBnClickedOk()
{
    //m_WebBrowser是一個WebBrowser的Activex控件對象。  
    CComQIPtr<IHTMLDocument2> spDoc  = m_WebBrowser.get_Document();  
    CComDispatchDriver spScript;  
    spDoc->get_Script(&spScript);  
  
    CComVariant var1 = 10, var2 = 20, varRet;  
    spScript.Invoke2(L"Add", &var1, &var2, &varRet);
}

調試(Debug):

 

spScript.Invoke2的作用是調用JS函數中名為Add的函數,傳入兩個參數,用varRet接收返回值。

可以看到,Invoke2調用成功后,varRet得到了返回值30。

 

但這樣的話一次只能接受一個返回值。

如果要一次接受多個返回值的話,怎么辦呢?

我們可以讓JS返回一個JS中的Array數組或Object對象。

當JS函數return一個Array或一個Object對象時,VC這邊的varRet將接受到一個代表該對象的IDispatch接口。我們仍然用CComDispatchDriver來管理這個IDispatch。用上一篇文章介紹的CComDispatchDriver的四個方法:

GetProperty

GetPropertyByName

PutProperty

PutPropertyByName

來從這個Array或Object對象中取出我們要的數據。

實踐是檢驗真理的唯一標准,讓我們再來寫一個JS函數:

//[html] view plaincopy在CODE上查看代碼片派生到我的代碼片 
<script type="text/javascript">  
    function Add(value1, value2) {  
        var array = new Array();  
        array[0] = value1;  
        array[1] = value2;  
        array[2] = value1 + value2;  
        return array;  
    }  
</script>  

然后在VC中這樣寫:

//[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片 
void CTestCallJsOnBnClickedOk()
{
    CComQIPtr<IHTMLDocument2> spDoc = m_WebBrowser.get_Document();  
    CComDispatchDriver spScript;  
  spDoc->get_Script(&spScript);  
  
    CComVariant var1 = 10, var2 = 20, varRet;  
    spScript.Invoke2(L"Add", &var1, &var2, &varRet);  
      
    CComDispatchDriver spArray = varRet.pdispVal;  
    //獲取數組中元素個數,這個length在JS中是Array對象的屬性,相信大家很熟悉  
    CComVariant varArrayLen;  
    spArray.GetPropertyByName(L"length", &varArrayLen);  
    //獲取數組中第0,1,2個元素的值:  
    CComVariant varValue[3];  
    spArray.GetPropertyByName(L"0", &varValue[0]);  
    spArray.GetPropertyByName(L"1", &varValue[1]);  
    spArray.GetPropertyByName(L"2", &varValue[2]);  
}

調試(Debug):

 

可以看到,10,20,30,這三個JS函數返回的值已經躺在我們的varValue[3]里了。

當然,如果不知道JS返回的Array對象里面有幾個元素,我們可以在VC這邊獲取它的length屬性,然后在一個循環中取出數組中的每個值。

 

如果我們的JS函數返回一個包含有多個屬性值的Object對象,VC這邊該如何接收呢?

讓我們再來寫一個JS函數:

//[html] view plaincopy在CODE上查看代碼片派生到我的代碼片 
<script type="text/javascript">  
    function Add(value1, value2) {  
        var data = new Object();  
        data.result = value1 + value2;  
        data.str = "Hello,我是小明!";  
        return data;  
    }  
</script>  

然后在VC中我們這樣接收:

//[cpp] 
void CTestCallJsOnBnClickedOk()
{
    CComQIPtr<IHTMLDocument2> spDoc = m_WebBrowser.get_Document();  
    CComDispatchDriver spScript;  
    spDoc->get_Script(&spScript);  
  
    CComVariant var1 = 10, var2 = 20, varRet;  
    spScript.Invoke2(L"Add", &var1, &var2, &varRet);  
      
    CComDispatchDriver spData = varRet.pdispVal;  
    CComVariant varValue1, varValue2;  
    spData.GetPropertyByName(L"result", &varValue1);  
    spData.GetPropertyByName(L"str", &varValue2);  
}

調試(Debug):

 

我們從JS返回的Object對象里取出了它的兩個屬性,result和str,分別是一個整形數據和一個字符串。

這里JS代碼是我們自己寫的,在VC這邊當然事先知道這個JS函數返回的對象有result和str這兩個屬性。

如果JS代碼不是我們寫的,或者它的屬性是事先不能確定的,該怎么辦呢?答案是使用IDispatchEx接口來枚舉這個對象的相關信息(方法名、屬性名)。

這個現在暫時不講,在后續的文章中會講。

 

當然,JS不只可以返回Object對象,返回什么對象都可以,當返回一個對象而非基本數據類型(整形、浮點、字符串)時,VC這邊收到的返回值是一個IDispatch,然后我們需要調用GetPropertyByName方法從這個IDispatch代表的對象中取出它的屬性來。

 

這樣一來,VC調用JS函數,傳遞參數給JS和JS返回返回值給VC,大致就都會了。

對於CComVariant包裝的VARIANT這種智能型變量,不了解的可以到網上看下相關資料。《深入解析ATL》之類的書上均有介紹。

 

值得注意的是ATL提供的這些CCom開頭的智能包裝類,並不依賴於ATL的動態庫。因為我在VC項目中並沒有選擇鏈接ATL,程序調試運行時進程加載的模塊中也有沒有ATL100.dll之類的模塊載入。大家可以放心使用而不用擔心依賴上ATL。

 

VC調用JS函數沒問題了。那么JS函數如何調用VC呢?我們將在下一篇文章中慢慢道來。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM