2012-01-11 36 views
10

मैं जावास्क्रिप्ट से अपनी बीएचओ विधि को कॉल करने की कोशिश कर रहा हूं। समस्या एक ही रूप में निम्न पदों में कहा गया है:जावास्क्रिप्ट से बीएचओ विधि को कॉल करना?

  1. Call BHO from Javascript function
  2. http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/91d4076e-4795-4d9e-9b07-5b9c9eca62fb/
  3. Calling C++ function from JavaScript script running in a web browser control

तीसरा लिंक है एक और अतः इसके बारे में बात पोस्ट, लेकिन मैं समझ में नहीं आया आवश्यकता और कोड। इसके अलावा साझा कामकाजी नमूना विंडोज 7 पर यानी 8 और विंडोज विस्टा के साथ 7 या तो विंडोज विस्टा के साथ दुर्घटनाग्रस्त रहता है।

यदि यह मेरे बीएचओ को एटीएल का उपयोग कर सी ++ में लिखा जाता है।

मैं क्या कोशिश की है:

मैं एक बहुत ही बुनियादी BHO लिखा और इगोर Tandetnik ने उल्लेख किया here के रूप में दृष्टिकोण की कोशिश की है। कोई अपवाद उत्पन्न नहीं हुआ है, लेकिन जब मैं IE में निम्न HTML फ़ाइल खोलता हूं तो यह कहता है कि ऑब्जेक्ट अपरिभाषित

<html> 
    <head> 
     <script language='javascript'> 
      function call_external(){ 
       try{ 
       alert(window.external.TestScript); 
       //JQueryTest.HelloJquery('a'); 
       }catch(err){ 
        alert(err.description); 
       } 
      } 
     </script> 
    </head> 
    <body id='bodyid' onload="call_external();"> 
     <center><div><span>Hello jQuery!!</span></div></center> 
    </boay> 
</html> 

प्रश्न:

  1. कृपया स्पष्ट करें कि बेनकाब और जावास्क्रिप्ट से BHO विधि कॉल या के रूप में [2] में jeffdav द्वारा उत्तर दिया मैं एक ActiveX (का उपयोग कर इसे बेनकाब करने के लिए है करने के लिए यह संभव है)? यदि हां तो यह कैसे करें।
  2. असल में मैं window.external का विस्तार करना चाहता हूं लेकिन उपर्युक्त लिंक [2] में दिखाया गया तरीका var x = new ActiveXObject("MySampleATL.MyClass"); का उपयोग करता है; क्या दोनों कॉलिंग सम्मेलन समान या अलग हैं?

नोट:

  1. वहाँ इतने पर एक संबंधित पोस्ट जो संकेत है कि यह BHO आईडीएल फ़ाइल में इस [id(1), helpstring("method DoSomething")] HRESULT DoSomething(); डालने के माध्यम से संभव है देता है। मुझे यकीन नहीं है कि यह कैसे किया गया था और Google के माध्यम से कोई सहायक संसाधन नहीं मिला।
  2. मुझे इस पोस्ट calling-into-your-bho-from-a-client-script के बारे में पता है, लेकिन मैंने कोशिश नहीं की है क्योंकि यह ActiveX का उपयोग कर समस्या को हल कर रहा है।
  3. एक्टिवएक्स से बचने का मेरा कारण मुख्य रूप से सुरक्षा प्रतिबंधों के कारण है।

संपादित करें 1


ऐसा लगता है वहाँ window.external विस्तार करने के लिए एक तरीका है। this देखें। विशेष रूप से IDocHostUIHandler::GetExternal: Extending the DOM. शीर्षक वाला अनुभाग मानते हुए कि हमारा आईडीस्पैच इंटरफ़ेस उसी ऑब्जेक्ट पर है जो IDocHostUIHandler लागू करता है।फिर हम कुछ इस तरह कर सकते हैं:

HRESULT CBrowserHost::GetExternal(IDispatch **ppDispatch) 
{ 
    *ppDispatch = this; 
    return S_OK; 
} 

समस्या इस दृष्टिकोण के साथ है कि यह मौजूदा खिड़कियों तरीकों को संलग्न नहीं होगा, बल्कि उन्हें बदलना। कृपया बताएं कि मैं गलत हूं या नहीं।

संपादित 2


The BHO Class:

class ATL_NO_VTABLE CTestScript : 
    public CComObjectRootEx<CComSingleThreadModel>, 
    public CComCoClass<CTestScript, &CLSID_TestScript>, 
    public IObjectWithSiteImpl<CTestScript>, 
    public IDispatchImpl<ITestScript, &IID_ITestScript, &LIBID_TestBHOLib, /*wMajor =*/ 1, /*wMinor =*/ 0>, 
    public IDispEventImpl<1, CTestScript, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1> 
{ 
public: 
    CTestScript() 
    { 
    } 

DECLARE_REGISTRY_RESOURCEID(IDR_TESTSCRIPT) 

DECLARE_NOT_AGGREGATABLE(CTestScript) 

BEGIN_COM_MAP(CTestScript) 
    COM_INTERFACE_ENTRY(ITestScript) 
    COM_INTERFACE_ENTRY(IDispatch) 
    COM_INTERFACE_ENTRY(IObjectWithSite) 
END_COM_MAP() 



    DECLARE_PROTECT_FINAL_CONSTRUCT() 

    HRESULT FinalConstruct() 
    { 
     return S_OK; 
    } 

    void FinalRelease() 
    { 
    } 

public: 
    BEGIN_SINK_MAP(CTestScript) 
     SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete) 
     //SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, OnNavigationComplete) 
    END_SINK_MAP() 

    void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL); 
    //void STDMETHODCALLTYPE OnNavigationComplete(IDispatch *pDisp, VARIANT *pvarURL); 

    STDMETHOD(SetSite)(IUnknown *pUnkSite); 

    HRESULT STDMETHODCALLTYPE DoSomething(){ 
     ::MessageBox(NULL, L"Hello", L"World", MB_OK); 
     return S_OK; 
    } 
public: 

//private: 
    // InstallBHOMethod(); 

private: 
    CComPtr<IWebBrowser2> m_spWebBrowser; 
    BOOL m_fAdvised; 
}; 

// TestScript.cpp : Implementation of CTestScript

#include "stdafx.h" 
#include "TestScript.h" 


// CTestScript 

STDMETHODIMP CTestScript::SetSite(IUnknown* pUnkSite) 
{ 
    if (pUnkSite != NULL) 
    { 
     HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser); 
     if (SUCCEEDED(hr)) 
     { 
      hr = DispEventAdvise(m_spWebBrowser); 
      if (SUCCEEDED(hr)) 
      { 
       m_fAdvised = TRUE;    
      } 
     } 
    }else 
    { 
     if (m_fAdvised) 
     { 
      DispEventUnadvise(m_spWebBrowser); 
      m_fAdvised = FALSE; 
     } 
     m_spWebBrowser.Release(); 
    } 
    return IObjectWithSiteImpl<CTestScript>::SetSite(pUnkSite); 
} 

void STDMETHODCALLTYPE CTestScript::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL) 
{ 
     CComPtr<IDispatch> dispDoc; 
     CComPtr<IHTMLDocument2> ifDoc; 
     CComPtr<IHTMLWindow2> ifWnd; 
     CComPtr<IDispatchEx> dispxWnd; 

     HRESULT hr = m_spWebBrowser->get_Document(&dispDoc); 
     hr = dispDoc.QueryInterface(&ifDoc);  
     hr = ifDoc->get_parentWindow(&ifWnd); 
     hr = ifWnd.QueryInterface(&dispxWnd); 

     // now ... be careful. Do exactly as described here. Very easy to make mistakes 
     CComBSTR propName(L"myBho"); 
     DISPID dispid; 
     hr = dispxWnd->GetDispID(propName, fdexNameEnsure, &dispid); 

     CComVariant varMyBho((IDispatch*)this); 
     DISPPARAMS params; 
     params.cArgs = 1; 
     params.cNamedArgs = 0; 
     params.rgvarg = &varMyBho;    
     params.rgdispidNamedArgs = NULL; 
     hr = dispxWnd->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, 
      &params, NULL, NULL, NULL); 

} 

The Javascript:

<script language='javascript'> 
      function call_external(){ 
       try{ 
       alert(window.ITestScript); 
       }catch(err){ 
        alert(err.description); 
       } 
      } 
     </script> 

संपादित 3


इस पर तीन दिन बिताने के बाद, मुझे लगता है कि मैं ActiveX पथ लेना चाहिए। एक बुनियादी सक्रियण लिखना आसान, लिखित एक तरीका है और सभी प्रमुख आईई रिलीज पर परीक्षण किया जाता है। मैं इस सवाल को खुले के रूप में छोड़ रहा हूं, कृपया उरी के जवाब में टिप्पणियां देखें (उनके लिए बहुत धन्यवाद)। मैंने अपने अधिकांश सुझावों की कोशिश की है (4 और 5 को छोड़कर)। I will also suggest you to see the MSDN IDispatcEx sample। यदि आपको कोई समाधान मिलता है तो कृपया मुझे पोस्ट करें, अगर मुझे कोई समाधान मिल जाए तो मैं निश्चित रूप से यहां अपडेट करूँगा।

संपादित 4


See my last comment in URI's post. Issue Resolved.

उत्तर

7

इगोर Tandetnik की विधि सही दृष्टिकोण है। पोस्ट के साथ समस्या यह है कि नमूना कोड (कम से कम कुछ पृष्ठों पर मैंने इसे देखा) यह है कि यह पूरा नहीं हुआ था। जब तक मैं इसे काम नहीं कर पाता, तब तक मेरे पास कई परीक्षण और त्रुटियां थीं। यहाँ कि काम कर देता है मेरी कोड का अच्छा हिस्सा है:

कहो तुम एक वर्ग CMyBho है, और आप जावा स्क्रिप्ट के लिए IMyBho स्वचालन वस्तु को बेनकाब करना चाहते हैं

कक्षा परिभाषा:
आप मानक CComObjectRootEx से निकाले जाते हैं , और CComCoClass इसे 'सह रचनात्मक' बनाने के लिए। आपके पास IObjectWithSiteImpl है (इस बेस क्लास द्वारा लागू m_spUnkSite का पुन: उपयोग करें)। IDispatchImpl अपने स्वचालन वस्तु को लागू करता है, और IDispatchEventImpl ब्राउज़र से सूचना पाने के लिए सिंक है:

class ATL_NO_VTABLE CMyBho 
    : public CComObjectRootEx<CComSingleThreadModel> 
    , public CComCoClass<CMyBho, &CLSID_MyBho> 
    , public IObjectWithSiteImpl<CMyBho> 
    , public IDispatchImpl<IMyBho, &IID_IMyBho, &LIBID_MyBhoLib, 1, 0> 
    , IDispatchEventImpl<1, CMyBho, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1> 
{ 
    ... 

public: 
    BEGIN_COM_MAP(CMyBho) 
     COM_INTERFACE_ENTRY(IMyBho) 
     COM_INTERFACE_ENTRY(IDispatch) 
     COM_INTERFACE_ENTRY(IObjectWithSite) 
    END_COM_MAP() 

    ... 

    BEGIN_SINK_MAP(CMyBho) 
     SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocComplete) 
    END_SINK_MAP() 

    ... 

private: 
    CComPtr<IWebBrowser2> m_ifbrz;   // pointer to the hosting browser 

} 

इसके बाद, SetSite विधि, जहां आप सूचना प्राप्त करने के लिए रजिस्टर। बेस क्लास को कॉल करना न भूलें।

STDMETHODIMP CMyBho::SetSite(IUnknown* unkSite) 
{ 
    ... 
    hr = IObjectWithSiteImpl::SetSite(unkSite); 
    if(unkSite) { 
     ... 
     // advise to browser event. 
     CComPtr<IServiceProvider> ifsp; 
     hr = m_spUnkSite.QueryInterface(&ifsp); 
     hr = ifsp->QueryService(SID_SwebBrowserApp, IID_IWebBrowser2, &m_ifbrz); 
     hr = DispEventAdvise(m_ifbrz); 
    } 
    else { 
     // release various resources (m_ifbrz will be released automatically by its dtor) 
     ... 
    } 
... 
} 

दस्तावेज़ लोड पूरा होने पर, इस फ़ंक्शन कॉल किया जाएगा:

void STDMETHODCALLTYPE CMyBho::onDocComplete(IDispatch* dispBrz, VARIANT* pvarUrl) 
{ 
    CComPtr<IDispatch> dispDoc; 
    CComPtr<IHTMLDocument2> ifDoc; 
    CComPtr<IHTMLWindow2> ifWnd; 
    CComPtr<IDispatchEx> dispxWnd; 

    hr = m_ifbrz->get_Document(&dispDoc); 
    hr = dispDoc.QueryInterface(&ifDoc);  
    hr = ifDoc->get_parentWindow(&ifWnd); 
    hr = ifWnd.QueryInterface(&dispxWnd); 

    // now ... be careful. Do exactly as described here. Very easy to make mistakes 
    CComBSTR propName(L"myBho"); 
    DISPID dispid; 
    hr = dispxWnd->GetDispID(propName, fdexNameEnsure, &dispid); 

    CComVariant varMyBho((IDispatch*)this); 
    DISPPARAMS params; 
    params.cArgs = 1; 
    params.cNamedArgs = 0; 
    params.rgvarg = &varMyBho;    
    params.rgdispidNamedArgs = NULL; 
    hr = dispxWnd->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF, 
          &params, NULL, NULL, NULL); 
} 

अपने अन्य प्रश्न के लिए के रूप में:

  • जाहिर है, मेरा उत्तर का तात्पर्य है कि आप एक स्वचालन बनाता है यह कर सकते हैं कि आपके बीएचओ से स्क्रिप्टिंग के लिए ऑब्जेक्ट उपलब्ध है। यह भी संभव है कि आपका ऑब्जेक्ट नए ActiveXObject के साथ चालू हो जाएगा।उस स्थिति में आईई को बताना न भूलें कि आपकी ऑब्जेक्ट स्क्रिप्टिंग के लिए सुरक्षित है (साइड नोट: स्क्रिप्टिंग के लिए अपना बीएचओ सुरक्षित बनाएं। सुनिश्चित करें कि दुर्भावनापूर्ण वेबसाइट आपके बीएचओ का फायदा उठाने में सक्षम नहीं होगी)।

  • मुझे लगता है कि window.myBho window.external.myBho से बेहतर जगह है। अर्थात्, 'बाहरी' तब होता है जब mshtml ब्राउज़र नियंत्रण किसी अन्य एप्लिकेशन के भीतर होस्ट किया जाता है।

आशा है कि इससे मदद मिलेगी।

+0

आपके उत्तर के लिए धन्यवाद। मैंने आपके सुझाव की कोशिश की लेकिन जब मैं अपने जावास्क्रिप्ट में bho ऑब्जेक्ट तक पहुंच रहा हूं तो यह मुझे 'ऑब्जेक्ट अपरिभाषित' दे रहा है। कृपया मेरा अद्यतन उत्तर देखें, मैंने बीएचओ कोड और संबंधित जावास्क्रिप्ट शामिल किया है। – Favonius

+0

मैंने इन दो कथनों को बदल दिया है 'params.rgvarg = और varTanduBar; params.rgdispidNamedArgs = null; 'इस' params.rgvarg = और varMyBho; params.rgdispidNamedArgs = NULL; '। अन्यथा मैंने एक ही कोड का उपयोग किया है। – Favonius

+0

इसके अलावा, मैंने 'DISPATCH_PROPERTYPUTREF' और' DISPATCH_PROPERTYPUT' को आजमाया है। लेकिन इस मामले में दोनों काम नहीं कर रहे हैं। – Favonius