<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    ActiveX異步回調JavaScript

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    ActiveX異步回調JavaScript

          開發環境:VC6.0

          背景知識:COM/ActiveX/JavaScript/MFC/Thread

     

          想必用過Ajax的童鞋們都知道xmlhttp這個東西吧,通過設定onreadystatechange屬性,我們就可以指定他狀態改變的回調函數,當狀態改變時,ActiveX控件就會調用我們通過onreadystatechange屬性制定的回調函數。從而就出現了Ajax給我們帶來的精彩。關于Ajax的技術我們這里不做討論,我們的目的就是實現像xmlhttp這樣具有異步回調JavaScript功能的ocx控件來。

     

          Let’s go!

     

    1.      建立MFC ActiveX Control(方法略)

    2.      ClassWizard中添加屬性callbackfunction屬性,并為該屬性生成getset方法。我們將在ActiveX控件中開啟線程,線程執行完后將調用通過該屬性執行的JavaScript函數。在該實例中,通過callbackfunction屬性指定的JavaScript函數必須是返回值是void的,并且含有一個short類型的參數的函數。

    3.      我們需要一個方法來觸發回調函數,添加方法Invoke包含一個short類型的參數param。在這個函數里將開啟一個線程進行運算,然后返回計算結果。并把結果以回調函數的形式調用JavaScript的函數。

    4.      Invoke方法中開啟線程。進行計算。線程同步的方法采用PostMessage自定義消息。這個很重要,否則的話,我們在線程中操作界面控件是不正確的。(我就是忘記了進行線程同步才多走了好多彎路)

    #define WM_THREADFIREEVENT WM_USER+101

    void f(void * r)

    {

          CThirdCtrl* p = (CThirdCtrl*)r;

          Sleep(5000);

          p->m_param +=10;

           PostMessage(p->m_hWnd,WM_THREADFIREEVENT,(WPARAM)NULL,(LPARAM)NULL);

          return;

    }

     

    void CThirdCtrl::invoke(short param)

    {

          m_param = param;

          _beginthread(f, 0, (void*)(this));

    }

     

    5.      添加THREADFIREEVENT消息的消息映射函數:

    ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread)

     

          6.   實現函數OnFireEventForThread

    LRESULT CThirdCtrl::OnFireEventForThread(WPARAM wParam, LPARAM lParam)

    {

       //FireLengthyProcessDone();

          InvokeScript ();

          return TRUE;

    }

    7.  在實現InvokeScript前,先說一個重要的東西,就是OnSetClientSite這是一個CThirdCtrl的父類ColeControl的一個虛方法。我們需要重寫他來獲得IWebBrowser2指針,有了IWebBrowser2我們就可以為所欲為了。比方說獲得document對象,獲得html中的elements,設定他們的屬性,調用方法。也可以執行頁面中的JavaScript函數。

         為獲得頂層IWebBrowser2引用,從客戶站點獲取IServiceProvider接口并且執行一個QueryService 操作獲取IID_IServiceProvider服務:SID_STopLevelBrowser (這在Shlguid.h中定義);對第二個IServiceProvider,執行一個QueryService獲取IID_IWebBrowser2服務:SID_SWebBrowserApp.

         上代碼:

    void CThirdCtrl::OnSetClientSite()

    {

         

         IOleClientSite*  pClientSite  =  GetClientSite(); 

         

         HRESULT  hr  =  S_OK; 

         IServiceProvider  *isp,  *isp2  =  NULL;//用于導航DHTML對象層次,作用就是提供服務 

         

         if  (!pClientSite) 

         

          if(browser!=NULL)

          {

                 browser->Release();

                 browser = NULL;

          }

          return;//  !S_OK; 

         

         else 

         

          hr  =  pClientSite->QueryInterface(IID_IServiceProvider,  reinterpret_cast<void  **>(&isp)); 

          if  (FAILED(hr))   

          

                 hr  =  S_OK; 

                 goto  cleanup; 

          

          

          hr  =  isp->QueryService(SID_STopLevelBrowser,  IID_IServiceProvider,  reinterpret_cast<void  **>(&isp2)); 

          if  (FAILED(hr)) 

          

                 hr  =  S_OK; 

                 goto  cleanup; 

          

          

          //獲得瀏覽器 

          hr  =  isp->QueryService(SID_SWebBrowserApp,  IID_IWebBrowser2,  reinterpret_cast<void  **>(&browser));

          if  (FAILED(hr))   

          

                 hr  =  S_OK; 

                 goto  cleanup; 

          

          

    cleanup: 

          //  Free  resources. 

          if(isp!=NULL)

          {

                 isp->Release();

                 isp = NULL;

          }

          if(isp2!=NULL)

          {

                 isp2->Release();

                 isp2 = NULL;

          }

          return;//  hr; 

         

         

         return;//  hr;

         

    }

                 同樣的道理,如果我們是ATL做的ActiveX,則需要重寫

    STDMETHODIMP  CThirdCtrl::SetClientSite()

    這個方法。

    8.   下面就是最關鍵的InvokeScript函數的實現,我們在這里使用上面獲取到的IWebBrowser2指針來獲取document對象,然后獲取Idispatch接口的script對象,然后調用Idispatch接口的Invoke方法。就可以調用JavaScript了。Idispatch接口真是強大啊。

    廢話少說,上代碼:

    void  CThirdCtrl::InvokeScript() 

    if(!browser) 

           if(browser!=NULL)

           {

                  browser->Release();

                  browser = NULL;

           }

           return; 

    CComPtr<IHTMLDocument2> m_spDoc; 

    HRESULT hr = browser->get_Document((IDispatch**)&m_spDoc);   

    if(FAILED(hr)) 

           throw(""); 

    CComPtr<IDispatch> pScript; 

    hr = m_spDoc->get_Script(&pScript); 

    if(FAILED(hr)) 

           throw(""); 

    CComBSTR  bstrMember(m_callbackfunction);   

    DISPID  dispid; 

    hr=pScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid); 

    //  設置函數參數 

    DISPPARAMS  dispparams; 

    memset(&dispparams,0,sizeof(dispparams)); 

    dispparams.cArgs = 1;//表示參數的計數。 

    dispparams.rgvarg = new VARIANT[dispparams.cArgs];//表示對參數數組的引用。 

    for(int i = 0; i < 1; i++) 

           //CComBSTR bstr = "111";  //  back  reading 

           //bstr.CopyTo(&dispparams.rgvarg[i].bstrVal); 

           dispparams.rgvarg[i].iVal = m_param;

           dispparams.rgvarg[i].vt = VT_I2; 

    dispparams.cNamedArgs =0;//表示命名參數的計數。 

    EXCEPINFO excepInfo; 

    memset(&excepInfo,0,sizeof(excepInfo)); 

    CComVariant vaResult; 

    UINT nArgErr = (UINT)-1;  //  initialize  to  invalid  arg 

    hr = pScript->Invoke(dispid, IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr); 

    這樣,ActiveX控件就完成了。

    9.      編寫html頁面代碼。打開Microsoft ActiveX Control Pad,插入控件。然后編寫JavaScript代碼。

    <HTML>

    <HEAD>

    <TITLE>New Page</TITLE>

    </HEAD>

    <BODY>

       <SCRIPT LANGUAGE="JavaScript" >

    function invoke()

    {

           Third1.callbackfunction = "callback";

           Third1.invoke(2);

           alert("begin invoke");

    }

    function callback(param)

    {

           alert(param);

    }

     

       </SCRIPT>

    <OBJECT ID="Third1" WIDTH=100 HEIGHT=51

     CLASSID="CLSID:E9D38528-0F4E-468B-858D-69905F16942F">

       <PARAM NAME="_Version" VALUE="65536">

       <PARAM NAME="_ExtentX" VALUE="2646">

       <PARAM NAME="_ExtentY" VALUE="1323">

       <PARAM NAME="_StockProps" VALUE="0">

    </OBJECT>

    <input type="button" value="test" onclick="invoke();" />

    </BODY>

    </HTML>

    10.  測試:打開瀏覽器,打開test.html頁面。點擊“test“按鈕,將會先顯示對話框begin invoke,然后過5秒鐘再顯示對話框12

    11.  調試方法:我們可以直接調試瀏覽器。瀏覽器加載了控件,然后我們調用控件的方法,這時會自動觸發我們在工程中設置的斷點。在

    project---settings---debug---executable for debug sessions設置瀏覽器的exe文件的路徑。我用的世界之窗瀏覽器。所以值設置為:C:\Program Files\TheWorld\TheWorld.exe

    如果你用IE瀏覽器,可設置為:C:\Program Files\Internet Explorer\iexplore.exe

     

    說明:

    1.   上述控件與xmlhttp不同的地方是callbackfunction我傳的是一個字符串,而xmlhttp傳的是一個JavaScript的函數指針。

    2.   COM中的線程模型不在本文討論范圍之內。還有瀏覽器安全問題和打包CAB的問題也不在本文討論范圍之內。

    參考:

    http://vcfaq.mvps.org/com/1.htm

    http://vcfaq.mvps.org/com/11.htm

    http://support.microsoft.com/kb/q157437/

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全