原本JavaScript可以接受ActiveX的事件。不过貌似要知道什么时候产生消息,而且Script要在调用了ActiveX之后马上产生事件,不然就接收不到消息。
若采用多线程就完全没有办法实现交互了。
我做的那个东西,是一定要采用多线程的。是调用了ActiveX之后一段时间之后产生才可以事件,如果不采用多线程会导致浏览器假死。
没有办法,只好采用ActiveX回调JavaScript代码来实现与多线程之间的交互。
问题又出来了,如果我采用把浏览器中的对象用指针的方式传给新的线程,就会导致接下来产生的对象产生NULL,很郁闷用了很多方法都不行,貌似只要传COM对象都会导致接下来的对象产生空对象。
最后还是上网查一下,原来这样的方式是不正确的。
方法如下:
(1)在类中声明
private:
IStream* pStream;
(2)
void CSecurityCtrl::Scan(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加调度处理程序代码
// TODO: 在此添加调度处理程序代码
IOleClientSite* m_spClientSite = GetClientSite();
IServiceProvider* isp;
HRESULT hr = m_spClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast(&isp));
if(FAILED(hr)) return;
IWebBrowser2* ppBrowser;
hr = isp->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, reinterpret_cast(&ppBrowser));
if(FAILED(hr)) return;
IDispatch *m_ppDispDoc;
hr = ppBrowser->get_Document(&m_ppDispDoc);
if(FAILED(hr)) return;
IHTMLDocument2 *ppDocument2;
hr = m_ppDispDoc->QueryInterface(IID_IHTMLDocument2 ,reinterpret_cast(&ppDocument2));
if(FAILED(hr)) return;
IDispatch *pScript;
hr=ppDocument2->get_Script(&pScript);
if(FAILED(hr)) return;
::CoMarshalInterThreadInterfaceInStream(IID_IDispatch, pScript, &pStream);
pScript->Release();
ppDocument2->Release();
m_ppDispDoc->Release();
ppBrowser->Release();
m_spClientSite->Release();
AfxBeginThread(ScanThread,this);
}
UINT CSecurityCtrl::ScanThread(LPVOID pParam)
{
CSecurityCtrl * pCSecurityCtrl = (CSecurityCtrl *)pParam;
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
IDispatch *pScript;
::CoGetInterfaceAndReleaseStream( pCSecurityCtrl->pStream, IID_IDispatch,(void**)&pScript);
//你的操作......................
// js函数名 参数个数 参数内容
JsCallback(pScript,_T("ActiveXCallback"),1,_T("ActiveXCallback"));
pScript->Release();
return 0;
}
int CSecurityCtrl::JsCallback(IDispatch *pScript ,_TCHAR *strName,int nParamCount,...)
{
if(pScript == NULL)
{
return 1;
}
try
{
DISPID dispid;
CComBSTR bstrMember(strName);
pScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);
DISPPARAMS dispparams;
memset(&dispparams, 0, sizeof dispparams);
dispparams.cArgs = nParamCount;
dispparams.rgvarg = new VARIANT[dispparams.cArgs];
va_list ap;
va_start(ap, nParamCount);
for(int j = 0; j Invoke(dispid,IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);
}
catch(_com_error &e)
{
AfxMessageBox(e.ErrorMessage());
}
return 0;
}
上面代码可以实现页面JavaScript代码回调。从而实现页面与ActiveX的交互。
或者可以使用这段代码把浏览器对象传过去
::CoMarshalInterThreadInterfaceInStream(IID_IWebBrowser2, ppBrowser, &pStream);
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
IWebBrowser2 * ppBrower;
::CoGetInterfaceAndReleaseStream(pStream, IID_IWebBrowser2, (void**)&ppBrower);
因为一个Web窗口,CComPtr 指针是不变的,而IHTMLDocument2指针是会变化的(比如刷新页面时,比如Navigate到其他URL时。)动态取得m_spDoc和pStream,就可以及时地释放。
总之,总结一下就是,如果要实现多线程,就要用上面红字的方式来传COM对象,具体原因我到现在还没有搞清楚。
其他相关的资料:
http://blog.csdn.net/zblue78/archive/2008/07/21/2683883.aspx
http://topic.csdn.net/u/20070212/20/1011ad32-1ce7-416d-9e6c-cffca7a100fe.html?seed=1066340289
http://vcfaq.mvps.org/com/11.htm
http://vcfaq.mvps.org/com/1.htm