Estoy tratando de llamar a mi método BHO desde el javascript. El problema es el mismo que se indica en los siguientes mensajes:¿Llamando al método BHO desde 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
tercer enlace es otro SO post hablando sobre ello, pero no entiendo la necesidad y el código. Además, la muestra de trabajo compartida sigue fallando en Windows 7, es decir, 8 y Windows Vista, es decir, 7
Si ayuda mi BHO está escrita en C++ utilizando ATL.
Lo que he intentado:
He escrito un BHO muy básico y probado el método como se ha mencionado here por Igor Tandetnik. No se genera ninguna excepción, pero cuando abro el siguiente archivo html en IE dice objeto indefinido.
<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>
Pregunta:
- Por favor aclarar si es posible exponer y llamar al método BHO desde JavaScript o tengo para exponerlo utilizando un ActiveX (como respondida por jeffdav en [2])? Si es así, ¿cómo hacerlo?
- Básicamente quiero extender el
window.external
pero la forma que se muestra en el enlace de arriba [2] usavar x = new ActiveXObject("MySampleATL.MyClass");
; ¿Ambas convenciones son iguales o diferentes?
Nota:
- Hay un post relacionado en SO que da indicio de que es posible a través de la inserción de este
[id(1), helpstring("method DoSomething")] HRESULT DoSomething();
en el archivo IDL BHO. No estoy seguro de cómo se hizo y no pude encontrar ningún recurso de apoyo a través de google. - Conozco esta publicación calling-into-your-bho-from-a-client-script, pero no la he probado, ya que está solucionando el problema con ActiveX.
- Mi razón para evitar ActiveX se debe principalmente a las restricciones de seguridad.
Editar 1
Parece que hay una manera de extender la
window.external
. Compruebe
this. Especialmente la sección titulada
IDocHostUIHandler::GetExternal: Extending the DOM.
Ahora suponiendo que nuestra interfaz IDispatch está en el mismo objeto que implementa IDocHostUIHandler.Entonces podemos hacer algo como esto:
HRESULT CBrowserHost::GetExternal(IDispatch **ppDispatch)
{
*ppDispatch = this;
return S_OK;
}
El problema con este enfoque es que no va a anexar a los métodos existentes de Windows, sino más bien reemplazarlos. Dime si estoy equivocado.
Editar 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>
Datos 3
Después de pasar tres días en esto, creo que debería tomar el camino de ActiveX. Escribir un activex básico es fácil, escrito y probado en todas las principales versiones de IE. Dejo esta pregunta abierta, por favor vea los comentarios en la respuesta de Uri (muchas gracias a él). He intentado la mayoría de sus sugerencias (excepto 4 y 5).
I will also suggest you to see the MSDN IDispatcEx sample
. Si encuentra una solución, por favor publique, si encuentro una solución, definitivamente la actualizaré aquí.
Editar 4
See my last comment in URI's post. Issue Resolved.
Gracias por su respuesta. Intenté su sugerencia, pero cuando estoy accediendo al objeto bho en mi javascript, me está dando 'object undefined'. Por favor, mira mi respuesta actualizada, he incluido el código BHO y el javascript correspondiente. – Favonius
He cambiado estas dos sentencias 'params.rgvarg = & varTanduBar; params.rgdispidNamedArgs = null; 'a este' params.rgvarg = & varMyBho; params.rgdispidNamedArgs = NULL; '. De lo contrario, he usado el mismo código. – Favonius
Además, he intentado 'DISPATCH_PROPERTYPUTREF' y' DISPATCH_PROPERTYPUT'. Pero en este caso, ambos no están funcionando. – Favonius