VC DOM 编程,已经取得了IHTMLFormElement 的对象,想收到 from 提交的消息,用 put_onsubmit没反应,请指教我的代码:CComVariant vEvent;
CComPtr< COnWebEvent > pOnWebEvent;vEvent.pdispVal = (IDispatch*)pOnWebEvent;
spFormElement->put_onsubmit( vEvent );其中的 COnWebEvent 是这么写的class COnWebEvent : public IDispatch   
{
public:
COnWebEvent();
~COnWebEvent();         virtual HRESULT STDMETHODCALLTYPE Invoke( 
            /* [in] */ DISPID dispIdMember,
            /* [in] */ REFIID riid,
            /* [in] */ LCID lcid,
            /* [in] */ WORD wFlags,
            /* [out][in] */ DISPPARAMS *pDispParams,
            /* [out] */ VARIANT *pVarResult,
            /* [out] */ EXCEPINFO *pExcepInfo,
            /* [out] */ UINT *puArgErr);
};
我在 COnWebEvent 里面 和  Invoke 里面都下了断点和打印调试信息,都没反应,请指教

解决方案 »

  1.   

    楼上的没看清楚我的问题,
    你那样只是提交表单
    我现在需要的是,当我关心的表单被 submit 之后,我要第一时间收到通知。
      

  2.   

    用事件连接点试下:
        IConnectionPointContainer* pCPC = NULL;
        IConnectionPoint* pCP = NULL;
        DWORD wCookie;
        // Check that this is a connectable object.
        hr = spFormElement->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
        if (hr == S_OK)
        {
    // Find the connection point.
            hr = spFormElement->FindConnectionPoint(DIID_HTMLFormElementEvents2, &pCP);
    if (hr == S_OK)
            {
    // Advise the connection point.
    hr = l_pCP->Advise(&vEvent, &dwCookie);
            }
            l_pCPC->Release();
        }不用时,记得释放连接点 : hr = pCP->Unadvise(dwCookie);
      

  3.   

    上面l_pCPC改成pCPC, l_pCP改成pCP
      

  4.   

    CComVariant vEvent;
    CComPtr< COnWebEvent > pOnWebEvent; vEvent.pdispVal = (IDispatch*)pOnWebEvent;
    //spFormElement->put_onsubmit( vEvent ); IConnectionPointContainer* pCPC = NULL;
    IConnectionPoint* pCP = NULL;
    DWORD dwCookie;
    // Check that this is a connectable object.
    hr = spFormElement->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
    if (hr == S_OK)
    {
    // Find the connection point.
    hr = pCPC->FindConnectionPoint(DIID_HTMLFormElementEvents2, &pCP);
    if (hr == S_OK)
    {
    // Advise the connection point.
    hr = pCP->Advise((IUnknown*)&vEvent, &dwCookie);
    }
    pCPC->Release();
    }代码改成这样还是没有反应
      

  5.   

    CComVariant vEvent;
    CComPtr< COnWebEvent > pOnWebEvent; vEvent.pdispVal = (IDispatch*)pOnWebEvent;
    //spFormElement->put_onsubmit( vEvent ); IConnectionPointContainer* pCPC = NULL;
    IConnectionPoint* pCP = NULL;
    DWORD dwCookie;
    // Check that this is a connectable object.
    hr = spFormElement->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
    if (hr == S_OK)
    {
    // Find the connection point.
    hr = pCPC->FindConnectionPoint(DIID_HTMLFormElementEvents2, &pCP);
    if (hr == S_OK)
    {
    // Advise the connection point.
    hr = pCP->Advise((IUnknown*)&vEvent, &dwCookie);
    }
    pCPC->Release();
    }刚才的代码有点乱,从新贴一下,
    代码改成这样还是没有反应 
      

  6.   

    DIID_HTMLFormElementEvents2替换成IID_IHTMLFormElement
      

  7.   

    sorry. 上面那个不对试下替换成DIID_HTMLElementEvents2
      

  8.   

    或者用HTMLFormElementEvents试下,去掉2
      

  9.   


    HRESULT STDMETHODCALLTYPE COnWebEvent::Invoke( 
            /* [in] */ DISPID dispIdMember,
            /* [in] */ REFIID riid,
            /* [in] */ LCID lcid,
            /* [in] */ WORD wFlags,
            /* [out][in] */ DISPPARAMS *pDispParams,
            /* [out] */ VARIANT *pVarResult,
            /* [out] */ EXCEPINFO *pExcepInfo,
            /* [out] */ UINT *puArgErr)
    { ::ATLTRACE("in Invoke\n"); return -1;
    }也不行哦,我插入的调试信息和断点都没有触发
      

  10.   


    都试过了,我参考了 MSDN 说明,把你说的这几个事件都试过了
      

  11.   

    class COnWebEvent : public IDispatch  
    从CCmdTarget派生试下
      

  12.   


    class COnWebEvent : public IDispatch , public CCmdTarget 还是没反应
      

  13.   

    COnWebEvent  只是简单继承自 IDispatch  ,而并没有去实现 AddRef ,QueryInterface 之类的接口,用的时候也仅仅是利用 COnWebEvent 的指针,不知道跟这有没有关系?
      

  14.   

    CComVariant vEvent; 
    CComPtr < COnWebEvent > pOnWebEvent; vEvent.pdispVal = (IDispatch*)pOnWebEvent; 
    spFormElement->put_onsubmit( vEvent ); 改成
    CComVariant vEvent; 
    COnWebEvent OnWebEvent; // 不过这里如果是局部变量的话问题就大了vEvent = (IDispatch*)&OnWebEvent; 
    spFormElement->put_onsubmit( &vEvent ); 
      

  15.   

    发现个新问题。按照 yjgx007 老大的写法 
    hr = pCP->Advise((IUnknown*)&pOnWebEvent, &dwCookie);
    的返回值是 E_NOTIMPL,看来是不支持这个接口了??
      

  16.   

    不要用栈变量,用全局变量申明一个COnWebEvent变量再试。
    你的COnWebEvent到底是怎么写的?Invoke没有被调用到吗?put_onsubmit()返回值是什么?
      

  17.   

    put_onsubmit() 返回值是 E_NOTIMPL 
      

  18.   


    不实现AddRef/QueryInterface之类的方法你居然能编译通过?不可能吧。
      

  19.   


    就是 InVoke 没有被调用到啊,所以才奇怪被调用到就说明已经收到通知了,我现在是连通知都没收到
      

  20.   

    给你帖一段实现代码:class COnWebEvent : public IDispatch
    {
    public:
      virtual ULONG STDMETHODCALLTYPE AddRef()
      {
        return 1;
      }  virtual ULONG STDMETHODCALLTYPE Release()
      {
        return 1;
      }  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID* ppvObj)
      {
        if (iid==__uuidof(IDispatch) || iid==__uuidof(IUnknown))
        {
          if (ppvObj)
            *ppvObj = this;
          return S_OK;
        }
        return E_NOINTERFACE;
      }  virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT * /*pctinfo*/)
      {
        return E_NOTIMPL;
      }  virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT /*iTInfo*/, LCID /*lcid*/, ITypeInfo ** /*ppTInfo*/)
      {
        return E_NOTIMPL;
      }  virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID /*riid*/, LPOLESTR * /*rgszNames*/, UINT /*cNames*/, LCID /*lcid*/, DISPID * /*rgDispId*/)
      {
        return E_NOTIMPL;
      }  virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispidMember,REFIID riid, LCID lcid, WORD wFlags,
          DISPPARAMS * pdispparams, VARIANT * pvarResult,EXCEPINFO * pexcepinfo, UINT * puArgErr)
      {
        // do something
        // 在这里设置断点试试
        return hr;
      }
    };
      

  21.   

    Invoke里面改成return S_OK; 一下子写错了,习惯用HRESULT hr;变量
      

  22.   

    谢谢,我的实现代码跟你的一样,:)。。还有可能是哪里的问题?put_onsubmit() 返回值是 E_NOTIMPL 
      

  23.   

    真是稀奇,spFormElements是什么类型的变量?CComPtr<IHTMLFormElement>?
      

  24.   


    CComQIPtr< IDispatch > pDisp;
    hr = spElementCollection->item( CComVariant( i ), CComVariant(), &pDisp );
    if ( FAILED( hr ) ) continue; if( !pDisp )//容错
          return; CComQIPtr< IHTMLFormElement > spFormElement = pDisp;
      

  25.   

    CComQIPtr< IHTMLFormElement > spFormElement = pDisp;
      

  26.   

    pDisp的类型一般使用CComPtr<IDispatch>,后面要注意判断spFormElement是否空,其他还看不出问题
      

  27.   

    我帮你修正了下这个类, 很多接口没实现, 特别是AddRef, Release,你自已在Invoke设断点试下(当form提交后,你的代码是点击图片元素,提交表单).修正后的工程已发到你邮箱.class COnWebEvent : public IDispatch// , public CCmdTarget 
    {
    public:
    COnWebEvent():m_dwRef(1)
    {};
    ~COnWebEvent(){};         //HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
             //   /* [out] */ UINT *pctinfo);
            
             //HRESULT STDMETHODCALLTYPE GetTypeInfo( 
             //   /* [in] */ UINT iTInfo,
             //   /* [in] */ LCID lcid,
             //   /* [out] */ ITypeInfo **ppTInfo);
            
             //HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
             //   /* [in] */ REFIID riid,
             //   /* [size_is][in] */ LPOLESTR *rgszNames,
             //   /* [in] */ UINT cNames,
             //   /* [in] */ LCID lcid,
             //   /* [size_is][out] */ DISPID *rgDispId);
            
             //virtual HRESULT STDMETHODCALLTYPE Invoke( 
             //   /* [in] */ DISPID dispIdMember,
             //   /* [in] */ REFIID riid,
             //   /* [in] */ LCID lcid,
             //   /* [in] */ WORD wFlags,
             //   /* [out][in] */ DISPPARAMS *pDispParams,
             //   /* [out] */ VARIANT *pVarResult,
             //   /* [out] */ EXCEPINFO *pExcepInfo,
             //   /* [out] */ UINT *puArgErr);
    DWORD m_dwRef;
    // IUnknown
    STDMETHOD(QueryInterface)(const struct _GUID &riid,void ** ppv){
    *ppv = NULL; if (IID_IUnknown == riid)
    {
    *ppv = (LPUNKNOWN)this;
    AddRef();
    return NOERROR;
    }
    else if (IID_IDispatch == riid)
    {
    *ppv = (IDispatch*)this;
    AddRef();
    return NOERROR;
    }
    else
    {
    return E_NOTIMPL;
    }
    }
    ULONG __stdcall AddRef(void){
    return ++m_dwRef;
    }
    ULONG __stdcall Release(void){
    if (--m_dwRef == 0) 

    delete this; 
    return 0; 
    }
    return m_dwRef;
    }
    // IDispatch
    STDMETHOD(GetTypeInfoCount)(unsigned int *){
    TRACE("GetTypeInfoCount\n"); return E_NOTIMPL;
    }
    STDMETHOD(GetTypeInfo)(unsigned int,unsigned long,struct ITypeInfo ** ){
    TRACE("GetTypeInfo\n"); return E_NOTIMPL;
    }
    STDMETHOD(GetIDsOfNames)(const IID &,LPOLESTR *,UINT,LCID,DISPID *){
    TRACE("GetIDsOfNames\n"); return E_NOTIMPL;
    }
    STDMETHOD(Invoke)(long dispID,const struct _GUID &,unsigned long,unsigned short,struct tagDISPPARAMS * pParams,struct tagVARIANT *,struct tagEXCEPINFO *,unsigned int *)
    {
    return NOERROR;
    }
    };
      

  28.   

    sorry, 你的OnWebEvent.cpp没加到工程中,我重写了这个类 : )引用计数很重要, 你可不能给假的哦!
    另外QueryInterface不能简单返回this指针, 要根据继承接口的IID进行识别.
      

  29.   


    感谢老大,用连接点已经可以了但是 put_onsubmit() 还是不行,不过能解决问题就可以了,给分。
      

  30.   


    yjgx007 老大已经帮忙修改了,
    用连接点可以,但是 put_onsubmit()  还是不行,呵呵,不知道为啥,感谢老大参与,给分。
      

  31.   

    额,本来要结贴的,结果发现一个问题。这个现在是设定一个自定义的接受消息的 invoke,然后紧接着的代码就是模拟点击我感兴趣的页面元素提交表单。但是我不模拟点击,而是用手工点击的话,我的接收器就接收不到消息。我现在想枚举到所有的页面表单之后,不用代码去立即点击。而是用手工去点击了页面之后,我的接收器也能收到消息,是需要保存哪个变量?还是说应该怎么做?                ... ... hr = spFormElement->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
    if (hr == S_OK)
    {
    // Find the connection point.
    hr = pCPC->FindConnectionPoint( DIID_HTMLFormElementEvents , &pCP);
    if (hr == S_OK)
    {
    // Advise the connection point.
    hr = pCP->Advise((IUnknown*)&pOnWebEvent, &dwCookie);
    if ( FAILED( hr ) ) ::AfxMessageBox("bbb");
    }
    pCPC->Release();
    }
    //----------------------------------------------------------------------------------
    //枚举表单中的元素,找到与input 有关的项,如果发现为 image 类型的按钮,就点击。

    CComQIPtr< IHTMLElement > spAllInputElement;
    spFormElement->QueryInterface( IID_IHTMLElement  , (void**)&spAllInputElement ); CComQIPtr< IDispatch >    spCollDisp;
    CComQIPtr< IHTMLElementCollection > spCollElement; spAllInputElement->get_all( (IDispatch**)&spCollDisp );
    spCollDisp->QueryInterface( IID_IHTMLElementCollection , (void**)&spCollElement ); long nCollCount = 0;
    spCollElement->get_length(&nCollCount); for( long i = 0 ; i< nCollCount ; i++ )
    {
    CComQIPtr< IDispatch > MyDisp;
    CComQIPtr< IHTMLInputElement  > spInputElement;
    hr = spCollElement->item( CComVariant(i) , CComVariant() , &MyDisp );
    if ( FAILED( hr ) ) continue;

    if( !MyDisp )//容错
    return; hr = MyDisp->QueryInterface( IID_IHTMLInputElement  , (void**)&spInputElement );
    if ( FAILED( hr ) ) continue;
    if( !strnicmp(lpType , "image" , 5) )//如果发现 为 image 类型的按钮就点击之
    {
    CComQIPtr< IHTMLElement  > spSingleElement; hr = spInputElement->QueryInterface( IID_IHTMLElement , (void**)&spSingleElement);
    if( FAILED( hr ) ) continue; hr = spSingleElement->click();
    if( FAILED( hr ) ) continue;

    }
      

  32.   

    sorry,贴漏了一段代码,在 if( !strnicmp(lpType , "image" , 5) ) 的上面有一段代码漏了。 //取得表单域,并且点击按钮
    CComBSTR vName,vVal,vType; hr = spInputElement->get_name( &vName );
    if( FAILED( hr ) ) continue; hr = spInputElement->get_value( &vVal );
    if( FAILED( hr ) ) continue; hr = spInputElement->get_type( &vType );
    if( FAILED( hr ) ) continue; if( !strnicmp(lpType , "image" , 5) )//如果发现 为 image 类型的按钮就点击之
    {
    CComQIPtr< IHTMLElement  > spSingleElement; hr = spInputElement->QueryInterface( IID_IHTMLElement , (void**)&spSingleElement);
    if( FAILED( hr ) ) continue; hr = spSingleElement->click();
    if( FAILED( hr ) ) continue;

    }
      

  33.   

    put_onsubmit应该是可以的, 你少了指定variant类型的步骤,看下面代码:
    vEvent.pdispVal = (IDispatch*)&pOnWebEvent;
    vEvent.vt = VT_DISPATCH;