在对话框上放置一个WebBrowser控件,取得所加载页面的某一个select表单元素的指针IHTMLSelectElement,
然后此接口指针列集后传递给一个工作线程,在此线程中用散列得到接口spSelectElement。
用spSelectElement成功得到此select域里面的所有option元素;
然后用put_selectedIndex()设定选中项。
hr = spSelectElem->put_selectedIndex(i);
执行完毕后hr==SD_OK。
然后试图用IHTMLElement3的fireEvent()来激发onchange事件。
VARIANT_BOOL vRect;
BSTR Eventonchange = SysAllocString(L"onchange"); 
CComQIPtr< IHTMLElement3 > spElem3;
hr=spSelectElem->QueryInterface(IID_IHTMLElement3,(void**)&spElem3);
ASSERT(SUCCEEDED(hr));
hr=spElem3->fireEvent(Eventonchange,0,&vRect);
ASSERT(SUCCEEDED(hr));
spElem3.Release();
但执行到
hr=spElem3->fireEvent(Eventonchange,0,&vRect);
ASSERT(SUCCEEDED(hr));  这一步时,编译器指出:
hr 0x800706f4 向占位程序传送了空的索引指针。  HRESULT
然后就报错。大家注意上面是通过spSelectElem->QueryInterface(IID_IHTMLElement3,(void**)&spElem3);得到IHTMLElement3接口的;
后来我把IHTMLElement3接口也在主线程列集,传递到工作线程再散列,爆出的问题跟之前一模一样。高人指点下是怎么回事?

解决方案 »

  1.   

    大家可以通过这个帖子跟详细地了解整个问题的来龙去脉:
    将主线程对话框上的(WebBrowser控件页面元素的DOM接口指针IHTMLSelectElement)传递给新线程,为什么操作不成功?之前发贴有人说:每个使用COM的线程都要调用CoInitialize和Counitialize。
    我在线程函数的里面加上这两个函数后,问题依然如果。
    而且我之前没有用线程时,没有用此连个函数初始化,也很正常。不知何故,是否因为程序中有使用ADO,所以我在app中曾经调用过:
    BOOL CWorkshopApp::InitInstance()
    {
    //TODO: call AfxInitRichEdit2() to initialize richedit2 library.
    if(!AfxOleInit())
    {
    AfxMessageBox(_T("OLE初始化出错!"));
    return FALSE;
    } 出问题的这部分代码是:
    HRESULT hr;
    m_listTT[k].ResetContent();
    CComQIPtr< IHTMLSelectElement > spSelectElem;
    if(ArrSpSelectElem.GetAt(k, spSelectElem))
    {
    nCount--;
    long length = 0;
    spSelectElem->get_length(&length); CStringArray strArrText;
    if(GetOptionsTextValue(spSelectElem, strArrText, 0))
    {
    for(int i=0; i<strArrText.GetCount(); i++)
    {
    m_listTT[k].AddString(strArrText[i]);
    }
    }
    else
    { return false; }
    for(int i=0; i<length; i++)
    {
    //AddToDB(i);

    hr = spSelectElem->put_selectedIndex(i);
                    if(FAILED(hr))  AfxMessageBox(_T("Fail to put_selectedIndex"));
                    //********************************点燃"onchange"事件********************************/
    VARIANT_BOOL vRect;
    BSTR Eventonchange = SysAllocString(L"onchange"); 
    CComQIPtr< IHTMLElement3 > spElem3;
    hr=spSelectElem->QueryInterface(IID_IHTMLElement3,(void**)&spElem3);
    ASSERT(SUCCEEDED(hr));
    hr=spElem3->fireEvent(Eventonchange,0,&vRect);
    ASSERT(SUCCEEDED(hr));//此处报错,前一步编译器显示:
                                                          //hr 0x800706f4 向占位程序传送了空的索引指针。 HRESULT 
    spElem3.Release();
                    //****************************************************************/
    m_listTT[k].SetCurSel(i);   
      

  2.   

    貌似的列集、散集下接口列集、散集的概念介绍:http://www.builder.com.cn/2007/1015/556787.shtml
    ------------------------
    ps:LZ上一个帖子还没结呢
      

  3.   

    fireEvent()函数所需要的IHTMLElement3接口指针,我后来也列集传递了过来,实验结果跟之前一模一样!
      

  4.   

    我sorry我刚记错了,是50分,我去结了,给了你46分。
    我严重确认列集散列都做成功了,因为我在调试中仔细观察每一步执行的情况,列集散列以及传递都没有问题。
    而且很蹊跷的是,传过来的IHTMLSelectElement指针可以得到这个表单域的option选项,spSelectElem->get_length也很准确。
    但是spSelectElem->put_selectedIndex执行后返回的hr显示SD_OK.
    pElem3->fireEvent执行后显示:/hr 0x800706f4 向占位程序传送了空的索引指针。 HRESULT 
    然后就报错。
      

  5.   

    //********************************点燃"onchange"事件********************************/
                    VARIANT_BOOL vRect;
                    BSTR Eventonchange = SysAllocString(L"onchange"); 
                    CComQIPtr< IHTMLElement3 > spElem3;
                    hr=spSelectElem->QueryInterface(IID_IHTMLElement3,(void**)&spElem3);
                    ASSERT(SUCCEEDED(hr));
                    hr=spElem3->fireEvent(Eventonchange,0,&vRect);
                    ASSERT(SUCCEEDED(hr));//此处报错,前一步编译器显示:
                                                          //hr 0x800706f4 向占位程序传送了空的索引指针。 HRESULT 
                    spElem3.Release();
                    //****************************************************************/
    你看我代码都贴出来了。spElem3->fireEvent(Eventonchange,0,&vRect);有三个参数,看哪一个都不像会出错的啊?
    还有,为什么0x800706f4表明是参数的问题?
      

  6.   

        HRESULT fireEvent(      
            BSTR bstrEventName,
            VARIANT *pvarEventObject,
            VARIANT_BOOL *pfCancelled
        );
    Parameters    bstrEventName
            [in] BSTR that specifies the name of the event to fire.
        pvarEventObject
            [in] Pointer to a VARIANT that specifies the IHTMLEventObj interface from which the event properties are obtained.
        pfCancelled
            [out, retval] VARIANT_BOOL that receives one of the following values:        VARIANT_TRUE
                Event fired successfully.
            VARIANT_FALSE
                Event was cancelled.我觉得应该是第二个参数不能设置为空,具体怎么设偶也没弄过,不太了解。
      

  7.   

    激发事件时必须创建一个有效的事件对象ITHMLEventObj,所以不能在第二个参数中传递NULL。
    这么多接口需要列集,是不是觉得列集太麻烦?其实不麻烦,只需要列集一个根接口即可,比如IWebBrowser2或者IHTMLDocument2即可,剩下的事情就从这个接口开始导航吧,后续接口不再需要列集。
      

  8.   

    非常感谢胡大哥,在你的帮助下,我对这个问题的困惑逐渐明白。
    CComQIPtr< IHTMLEventObj > spEo;    
    hr = spDoc4->createEventObject(NULL, &spEo);CComQIPtr<IDispatch> spDisp(spEo);
    CComVariant var(spDisp);
    VARIANT_BOOL bCancel = VARIANT_FALSE;CComQIPtr< IHTMLElement3 > spElem3;
    hr=spSelectElem->QueryInterface(IID_IHTMLElement3,(void**)&spElem3);
    ASSERT(SUCCEEDED(hr));hr = spElem3->fireEvent(L"onchange", &var, &bCancel);
    ASSERT(SUCCEEDED(hr));上面是我从网上找到的代码,来createEventObject。但执行报错createEventObject参数貌似不应该为空。我真是搞不懂这个createEventObject到底是怎么用的。以前没用它,fireEvent也很成功啊?
      

  9.   

    请问胡兄,如果只传递了IHTMLSelectElement接口或来,怎样才能得到IHTMLDocument4接口?
    hr = spSelectElem->QueryInterface(IID_IHTMLDocument4,(void**)&spDoc4);
    编译器指出: hr E_NOINTERFACE HRESULT
    看来这样不行,有木别的方法可以达到这个目的?
      

  10.   

    能查询到IHTMLDocument2么,实在不行用IServiceProvider中转一下