Sto provando a chiamare il mio metodo BHO dal javascript. Il problema è lo stesso come indicato nei seguenti posti:Chiamare il metodo BHO da Javascript?
- Call BHO from Javascript function
- http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/91d4076e-4795-4d9e-9b07-5b9c9eca62fb/
- Calling C++ function from JavaScript script running in a web browser control
terzo anello è un altro SO post parlando di esso, ma non ho capito la necessità e il codice. Anche l'esempio di lavoro condiviso continua a bloccarsi su Windows 7 con ie 8 e windows vista con ie 7.
Se aiuta il mio BHO è scritto in C++ usando ATL.
Quello che ho cercato:
Ho scritto un BHO molto semplice e provato l'approccio come detto here da Igor Tandetnik. Non è stata generata alcuna eccezione, ma quando apro il seguente file html in IE, viene indicato l'oggetto non definito.
<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>
Domanda:
- Si prega di chiarire se è possibile esporre e chiamare il metodo BHO da JavaScript o devo esporlo tramite un ActiveX (come risposta da jeffdav in [2])? Se sì, allora come si fa?
- Fondamentalmente voglio estendere il
window.external
ma il modo mostrato nel link sopra [2] utilizzavar x = new ActiveXObject("MySampleATL.MyClass");
; Entrambe le convenzioni di chiamata sono uguali o diverse?
Nota:
- C'è un post correlati su SO che dà suggerimento che è possibile attraverso l'inserimento di questo
[id(1), helpstring("method DoSomething")] HRESULT DoSomething();
nel file BHO IDL. Non sono sicuro di come è stato fatto e non sono riuscito a trovare alcuna risorsa di supporto tramite Google. - Sono a conoscenza di questo post calling-into-your-bho-from-a-client-script, ma non l'ho provato in quanto risolve il problema utilizzando ActiveX.
- La ragione per cui si desidera evitare ActiveX è principalmente dovuta alle restrizioni di sicurezza.
Modifica 1
Sembra che ci sia un modo per estendere la
window.external
. Controllare
this. Specialmente la sezione
IDocHostUIHandler::GetExternal: Extending the DOM.
Ora supponiamo che la nostra interfaccia IDispatch si trovi sullo stesso oggetto che implementa IDocHostUIHandler.Poi possiamo fare qualcosa di simile:
HRESULT CBrowserHost::GetExternal(IDispatch **ppDispatch)
{
*ppDispatch = this;
return S_OK;
}
Il problema con questo approccio è che non aggiungerà ai metodi esistenti di Windows, ma piuttosto sostituirli. Per favore, dimmi se ho torto.
Edit 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,
¶ms, NULL, NULL, NULL);
}
The Javascript:
<script language='javascript'>
function call_external(){
try{
alert(window.ITestScript);
}catch(err){
alert(err.description);
}
}
</script>
Edit 3
Dopo aver trascorso tre giorni in questo, penso che dovrei prendere il sentiero ActiveX. Scrivere un activex di base è solo un modo semplice, scritto e testato su tutte le principali versioni di IE. Lascio questa domanda aperta, per favore vedi i commenti nella risposta di Uri (molte grazie a lui). Ho provato la maggior parte dei suoi suggerimenti (ad eccezione di 4 e 5).
I will also suggest you to see the MSDN IDispatcEx sample
. Se trovi una soluzione, per favore posta, se trovo una soluzione, la aggiornerò sicuramente qui.
Edit 4
See my last comment in URI's post. Issue Resolved.
Grazie per la risposta. Ho provato il tuo suggerimento ma quando accedo all'oggetto bho nel mio javascript mi sta dando l'oggetto undefined. Si prega di consultare la mia risposta aggiornata, ho incluso il codice BHO e il javascript corrispondente. – Favonius
Ho modificato queste due istruzioni 'params.rgvarg = & varTanduBar; params.rgdispidNamedArgs = null; 'a questo' params.rgvarg = & varMyBho; params.rgdispidNamedArgs = NULL; '. Altrimenti ho usato lo stesso codice. – Favonius
Inoltre, ho provato 'DISPATCH_PROPERTYPUTREF' e' DISPATCH_PROPERTYPUT'. Ma in questo caso entrambi non funzionano. – Favonius