COM组件开发实践(七)---多线程ActiveX控件和自动调整ActiveX控件大小(上)



声明:本文代码基于CodeProject的文章《A Complete ActiveX Web Control Tutorial》修改而来,因此同样遵循Code Project Open License (CPOL)

      最近遇到两个需求:1)在ActiveX控件中使用工作线程来完成底层的硬件设备扫描任务,并在工作线程中根据操作结果回调外部web页面的JavaScript函数;2)能根据控件任务的不同自动调整控件大小。但在查阅了大量资料后,发现网上讨论ActiveX中多线程开发的文章基本没有,最后在csdn论坛里遇到一个高手帮忙后,摸索了几天才解决这两个问题,本文的目的就在于记录下我解决这两个问题的过程,也希望能帮助到以后有同样需求的朋友

      简单抽象下第一个任务的模型:在AcitveX控件中开启一个工作线程去执行特点任务后,然后根据工作线程的执行结果中去通知外部的web页面的JavaScript。在进入到多线程之前,先来介绍下ActiveX中调用外部web页面的JavaScript函数的两种方式。

ActiveX中调用JavaScript

       第一种方式是使用事件,这是最简单方法。在类视图中,右键CMyActiveXCtrl ,选择添加事件,这种方式就不赘述了。

      第二种方式是利用IWebBrowser2IHTMLDocument2这两个COM组件来访问包含ActiveX控件的外部Web页面上的所有元素。具体实现步骤如下:

1, CMyActiveXCtrl类中加入两个变量:

public:
    IWebBrowser2
* pWebBrowser; //IE浏览器
    IHTMLDocument2* pHTMLDocument; //包含此控件的web页面

2重载OnSetClientSite函数。

复制代码void CMyActiveXCtrl::OnSetClientSite()
{
    HRESULT hr 
= S_OK;
    IServiceProvider 
*isp, *isp2 = NULL;
    
if (!m_pClientSite)
    {
        COMRELEASE(pWebBrowser);
    }  
    
else
    {
        hr 
= m_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 
= isp2->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, reinterpret_cast<void **>(&pWebBrowser)); //查询IE浏览器接口
        if (FAILED(hr)) 
        {
            hr 
= S_OK;
            
goto cleanup;
        }
        hr   
=   pWebBrowser->get_Document((IDispatch**)&pHTMLDocument); //查询Web页面接口  
        if(FAILED(hr))   
        {   
            hr 
= S_OK;
            
goto cleanup;
        }   
    cleanup:
        
// Free resources.
        COMRELEASE(isp);
        COMRELEASE(isp2);
    }
}
3, 控件在加载后会调用 OnSetClientSite 函数的,因此就会查询到对应包含控件的 Web 页面,有了这个页面后,就可以使用下述函数来调用 Web 页面中的 JavaScript 函数了。下述代码来自 CodeGuru 的文章 JavaScript Calls from C++ 》,感兴趣的话可以细读。
bool CMyActiveXCtrl::GetJScript(CComPtr<IDispatch>& spDisp)
{
    CHECK_POINTER(pHTMLDocument);
    HRESULT hr 
= pHTMLDocument->get_Script(&spDisp);
    ATLASSERT(SUCCEEDED(hr));
    
return SUCCEEDED(hr);
}

bool CMyActiveXCtrl::GetJScripts(CComPtr<IHTMLElementCollection>& spColl)
{
    CHECK_POINTER(pHTMLDocument);
    HRESULT hr 
= pHTMLDocument->get_scripts(&spColl);
    ATLASSERT(SUCCEEDED(hr));
    
return SUCCEEDED(hr);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,CComVariant* pVarResult)
{
    CStringArray paramArray;
    
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,const CString strArg1,CComVariant* pVarResult)
{
    CStringArray paramArray;
    paramArray.Add(strArg1);
    
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,const CString strArg1,const CString strArg2,CComVariant* pVarResult)
{
    CStringArray paramArray;
    paramArray.Add(strArg1);
    paramArray.Add(strArg2);
    
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,const CString strArg1,const CString strArg2,const CString strArg3,CComVariant* pVarResult)
{
    CStringArray paramArray;
    paramArray.Add(strArg1);
    paramArray.Add(strArg2);
    paramArray.Add(strArg3);
    
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc, const CStringArray& paramArray,CComVariant* pVarResult)
{
    CComPtr
<IDispatch> spScript;
    
if(!GetJScript(spScript))
    {
        
//ShowError("Cannot GetScript");
        return false;
    }
    CComBSTR bstrMember(strFunc);
    DISPID dispid 
= NULL;
    HRESULT hr 
= spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,
        LOCALE_SYSTEM_DEFAULT,
&dispid);
    
if(FAILED(hr))
    {
        
//ShowError(GetSystemErrorMessage(hr));
        return false;
    }
    
const int arraySize = paramArray.GetSize();
    DISPPARAMS dispparams;
    memset(
&dispparams, 0sizeof dispparams);
    dispparams.cArgs 
= arraySize;
    dispparams.rgvarg 
= new VARIANT[dispparams.cArgs];
    
forint i = 0; i < arraySize; i++)
    {
        CComBSTR bstr 
= paramArray.GetAt(arraySize - 1 - i); // back reading
        bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);
        dispparams.rgvarg[i].vt 
= VT_BSTR;
    }
    dispparams.cNamedArgs 
= 0;
    EXCEPINFO excepInfo;
    memset(
&excepInfo, 0sizeof excepInfo);
    CComVariant vaResult;
    UINT nArgErr 
= (UINT)-1;  // initialize to invalid arg
    hr = spScript->Invoke(dispid,IID_NULL,0,
        DISPATCH_METHOD,
&dispparams,&vaResult,&excepInfo,&nArgErr);
    delete [] dispparams.rgvarg;
    
if(FAILED(hr))
    {
        
//ShowError(GetSystemErrorMessage(hr));
        return false;
    }
    
if(pVarResult)
    {
        
*pVarResult = vaResult;
    }
    
return true;
}

4,现在就可以来测试上述两种调用JavaScript函数的方式了,为了简单起见,就在原文代码的基础上修改了下。

void CMyActiveXCtrl::LoadParameter(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    m_OutputParameter 
= m_InputParameter;
    
// Fire an event to notify web page
    FireParameterLoaded();
    CString strOnLoaded(
"OnLoaded");
    
this->CallJScript(strOnLoaded);
}

并且在web页面中加入了一个测试用的JavaScript函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值